Using Docker with Vagrant
Development environments can often be mixed, using both virtual machines and Docker containers. While virtual machines include everything needed to run a full operating system like memory, CPU, a kernel and all required libraries, a container is much more lightweight and can share all this with its host, while keeping a good isolation through special kernel features named cgroups. Docker containers helps developers use, share and ship a bundle including everything needed to run their application. Here, we'll show how to use Vagrant to start containers. Since Docker usage is a little different between Linux hosts and other platforms, the reference used here is the native Docker platform—Linux.
Getting ready
To step through this recipe, you will need the following:
- A working Vagrant installation (no hypervisor needed)
- A working Docker installation and basic Docker knowledge
- An Internet connection
How to do it…
We'll see how to use, access, and manipulate an NGINX container in Vagrant using Docker as a provider.
Using NGINX Docker container through Vagrant
Let's start with the simplest Vagrantfile possible, using the nginx:stable
container with the Docker Vagrant provider:
Vagrant.configure("2") do |config| config.vm.hostname = "vagrant-docker-1" config.vm.post_up_message = "HTTP access: http://localhost/" config.vm.provider "docker" do |docker| docker.image = "nginx:stable" end end
Simply start it up with the following code:
$ vagrant up --provider=docker Bringing machine 'default' up with 'docker' provider... ==> default: Creating the container... […] ==> default: HTTP access: http://localhost/
Let's remove the need to specify the provider on the command line by setting a simple Ruby environment access code at the top of the Vagrantfile:
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'
Now you can distribute your Vagrantfile and not worry about people forgetting to explicitly specify the Docker provider.
Exposing Docker ports in Vagrant
Okay, the previous example wasn't terribly useful as we didn't expose any ports. Let's tell Vagrant to expose the Docker container HTTP (TCP/80) port to our host's HTTP (TCP/80) port:
config.vm.provider "docker" do |docker| docker.image = "nginx:stable" docker.ports = ['80:80'] end
Restart the Vagrant and verify you can access your NGINX container:
$ curl http://localhost/
Sharing folders with Docker through Vagrant
What about sharing a local folder so you can code on your laptop and see the result processed by the Vagrant environment? The default NGINX configuration reads files from /usr/share/nginx/html
. Let's put our own index.html
in there.
Create a simple src/index.html
file, containing some text:
$ mkdir src; echo "<h1>Hello from Docker via Vagrant<h1>" > src/index.html
Add the Docker volume configuration to our Docker provider block in Vagrant:
config.vm.provider "docker" do |docker| docker.image = "nginx:stable" docker.ports = ['80:80'] docker.volumes = ["#{Dir.pwd}/src:/usr/share/nginx/html"] end
Note
#{Dir.pwd}
is the Ruby for finding the current directory, so you don't hardcode paths, making it highly distributable.
Restart the Vagrant environment and see the result:
$ curl http://localhost <h1>Hello from Docker via Vagrant<h1>
Note
On SELinux-enabled systems you may need to do some configuration that's beyond the scope of this book. We encourage you to secure your Docker systems using SELinux, but to disable SELinux just type the following:
$ sudo setenforce 0
There's more…
You can choose not to use your local or default Docker installation, but instead use a dedicated VM, maybe to reflect production or a specific OS (such as CoreOS). In this case, you can specify a dedicated Vagrantfile as follows:
config.vm.provider "docker" do |docker| docker.vagrant_vagrantfile = "docker_host/Vagrantfile" end