vagrant, docker, shared volume not ready on initial provisioning

693 views Asked by At

I'm playing around with docker and vagrant to isolate my dev environment on os x. So far so good, i've found a couple of good tutorials and introductions but some of the posts seems to be outdated as vagrant envolved...

My main issue the mounting of a shared folder from my host machine to the docker container – it kind of works, but i have no idea if i'm running into a vagrant/docker issue or just doing something wrong.

Let me explain my current state:

I'm using the following Vagrantfile.boot2docker for my virtual machine and mount the current directory to /app in the vm. I can see the folder inside the vm and it's content changes, whenever I update the files on the host machine.

VAGRANTFILE_API_VERSION = "2"
Vagrant.require_version ">= 1.6.3"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "yungsang/boot2docker"
  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.synced_folder ".", "/app", type: "rsync"
  # Uncomment below to use more than one instance at once
  # config.vm.network :forwarded_port, guest: 2375, host: 2375, auto_correct: true
  # Fix busybox/udhcpc issue
  config.vm.provision :shell do |s|
    s.inline = <<-EOT
      if ! grep -qs ^nameserver /etc/resolv.conf; then
        sudo /sbin/udhcpc
      fi
      cat /etc/resolv.conf
    EOT
  end
  # Adjust datetime after suspend and resume
  config.vm.provision :shell do |s|
    s.inline = <<-EOT
      sudo /usr/local/bin/ntpclient -s -h pool.ntp.org
      date
    EOT
  end
  config.vm.network :forwarded_port, guest: 5000, host: 5000
end

In my Vagrantfile i'm creating two seperate docker containers, a isolated redis instance and my node app which mounts the app directory from the vm to the container d.volumes=["/app:/foo"]

VAGRANTFILE_API_VERSION = "2"
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.define "redis" do |redis|
    redis.vm.provider 'docker' do |d|
      d.image  = 'redis:latest'
      #Comment the line below if you are running on a linux host
      d.vagrant_vagrantfile = "./Vagrantfile.boot2docker"
      d.name   = 'redis'
    end
  end
  config.vm.define "node_app" do |node_app|
      node_app.vm.provider "docker" do |d|
      d.name = 'node_app'
        d.build_dir = "."
        #Comment the line below if you are running on a linux host
        d.vagrant_vagrantfile = "./Vagrantfile.boot2docker"
        d.ports = ["5000:5000"]
        d.volumes = ["/app:/foo"]
        d.link('redis:redis')
      end
  end
end

My Dockerfile loads the latest nodejs container and copies the package.json and app.js from the host to the app directory before installing dependencies and running the app. The static copy of the folder from the current directory works well, my app connects to redis and works i can reach it as expected at http://192.168.33.10:5000 ! (Note: i've commented out the VOLUME command here, so files are just copied at container the beginning of the lifecylce)

FROM node:latest
#use vagrant shared folder
ADD . /app

WORKDIR /app

# install your application's dependencies
RUN npm install
# exposes our app port
EXPOSE 5000
# replace this with your main "server" script file
CMD ["node", "app.js"]

After my first success i've tried to use my shared volume and changed the Dockerfile as follows:

FROM node:latest
#use vagrant shared folder
ADD . /foo
# mount volume
VOLUME ['/foo']
WORKDIR /foo

# install your application's dependencies
RUN npm install
# exposes our app port
EXPOSE 5000
# replace this with your main "server" script file
CMD ["node", "app.js"]

I've reloaded the vm and got a bunch of errors: mostly no package.json found or npm module missing (express). I've figured out – by using the first Dockerfile and the following node.js app https://gist.github.com/joernroeder/e86a3882360497c828f9 (which simply lists the files in /foo and there content) – that the volume needs some time to mount, replaces the content of foo with it's own initial content and removes the generated files (including the node_modules directory). The files inside /foo therefore reflects the changes from the host, and syncing works well.

Do you have any tips and tricks for me how i can mount the volume in time, or are i'm doing something completly stupid here?

Thanks

1

There are 1 answers

0
crascher On

The defined volume for the node_app container d.volumes = ["/app:/foo"] will be available only after the dockerfile is executed and the container is started.

A workaround is to first use Add /app /foo in the dockerfile and after container creation the static added data will be overriden by the volume mount.

An example implementaion with docker and compose can be found here: https://github.com/b00giZm/docker-compose-nodejs-examples/tree/master/02-express-redis-nodemon. Note that this is also possible without compose just using vagrant and docker providers.