Preamble
I have a Vagrantfile
which is using Docker to deploy 5 machines, all based on the same base Dockerfile
.
This builds all OK, but when I do a vagrant up
I build the same image 5 times (because it’s executing docker build
for all 5 machines in parallel).
For context, the Vagrantfile looks a bit like this (to save clicking through to the Git repo, and for posterity):
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'
Vagrant.configure("2") do |config|
config.vm.provider "docker" do |d|
d.build_dir = "."
d.has_ssh = true
d.remains_running = false
d.create_args = ['--tmpfs', '/tmp', '--tmpfs', '/run', '--tmpfs', '/run/lock', '-v', '/sys/fs/cgroup:/sys/fs/cgroup:ro', '-t']
end
config.vm.define "host1" do |host|
host.vm.hostname = "host1.example.org"
host.vm.network "private_network", ip: "192.0.2.11"
host.vm.provider "docker" do |d|
d.name = "host1_example_org"
end
end
# Repeat until
config.vm.define "host5" do |host|
host.vm.hostname = "host5.example.org"
host.vm.network "private_network", ip: "192.0.2.15"
host.vm.provider "docker" do |d|
d.name = "host5_example_org"
end
host.vm.provision "ansible_local", run: "always" do |ansible|
ansible.playbook = "build_setup.yml"
ansible.playbook_command = "sudo ansible-playbook"
ansible.install_mode = "pip"
ansible.pip_install_cmd = "sudo apt install -y python3-pip && sudo rm -f /usr/bin/pip && sudo ln -s /usr/bin/pip3 /usr/bin/pip"
end
end
end
The ansible playbook at the end copies the SSH keys into /root/.ssh/host[1-5]
and creates an SSH config file for each host with the respective IP address and SSH key.
I thought I could add this block into the host5
block:
host.trigger.before :up do |trigger|
trigger.run = {
inline: "docker build . -t 'example/build:latest'"
}
end
And then in the other host blocks, I could add this line (which is very OS specific):
host.trigger.before :up do |trigger|
trigger.run = {
inline: "bash -c 'until docker image list example/build:latest | grep latest ; do sleep 5 ; done'"
}
end
However, I get a race condition where the image is tagged by Docker, but it actually isn’t usable by Vagrant, causing a failure, and the Ansible playbook will fire before the rest of the machines are started.
What I want
Ideally, Vagrant+Docker will do a docker build . -t 'example/build:latest'
before it then tries to use those images
I also want to set the ansible_local
provision to execute once the other machines are up.
Can anyone help me get to the bottom of how I might achieve this?