In this short blog I will show you how to manage a Docker container using Vagrant. Since version 1.6 Vagrant supports Docker as a provider, next to existing providers for VirtualBox and AWS. With the new Docker support Vagrant boxes can be started way faster. In turn Vagrant makes Docker easier to use since its runtime configuration can be stored in the Vagrantfile. You won’t have to add runtime parameters on the command line any time you want to start a container. Read on if you like to see how I create a Vagrantfile for an existing Docker image from Quinten’s Docker cookbooks collection.
Vagrant – A quick recap
Vagrant is a tool for managing virtual environments. To use it you create a Vagrantfile which specifies the VM image, shared folders, forwarded ports and other configuration and then you manage this VM using the Vagrant workflow: vagrant start, vagrant stop, vagrant destroy and so on. Vagrant also supports provisioners for shell, chef and puppet which provide configuration management for your VM.
Now with Docker!
Since Vagrant 1.6, Docker is now supported as a provider so we can benefit from its blazing speed! I have always liked Vagrant a lot because it keeps all runtime configuration in the Vagrantfile. In the past I have created virtual environments using Vagrant and Puppet to create replicable environments. Checkout a previous blog of mine on how I have used Vagrant and Puppet.
The key feature of Vagrant is its workflow: the simple lifecycle commands to start, stop and destroy a Vagrant instance. The runtime configuration of an instance is stored in the Vagrantfile. It’s a great tool. The only problem with it was that the original provider was VirtualBox. A Virtualbox VM takes very long to start up and require quite some memory and disk space. Luckily, with the new Docker provider this is changed. Read on to get started with setting up a Vagrant instance.
To get started install Vagrant 1.6.3 and Docker 1.1.1. I assume you use Ubuntu Trusty, 14.04. If you use Windows or have a Mac you can still use Docker via Boot2Docker, which uses a Vagrant VirtualBox VM with Docker on it. After installation set the VAGRANT_DEFAULT_PROVIDER environment variable so Vagrant uses the Docker provider by default.
$ export VAGRANT_DEFAULT_PROVIDER=docker $ wget https://dl.bintray.com/mitchellh/vagrant/vagrant_1.6.3_x86_64.deb $ sudo dpkg -i vagrant_1.6.3_x86_64.deb $ sudo apt-get install lxc-docker-1.1.1
Vagrantfile example for Jenkins
As an example, let’s create a Vagrantfile to manage a Docker container based on Quinten’s Jenkins image. Below is the complete Vagrantfile. I will walk you through all Docker configuration options that I used. Vagrant supports a block style configuration format. This allows you to configure multiple VMs or Docker images in one file. This file contains a single configuration block. Using the config.vm.provider “docker” notation we can declare a Docker instance and reference this container via its variable name ‘d’.
Vagrant.configure("2") do |config| config.vm.provider "docker" do |d| d.image = "quintenk/jenkins" d.has_ssh = false d.ports = ["8080:8080"] d.volumes = ["/data/jenkins:/root/.jenkins"] end end
Specify the image for the container we want to start. In our case this is quintenk/jenkins. Note that you can also tell Vagrant to first build an image from a Dockerfile before starting the container. In that case use build_dir = “.” to tell Vagrant the Dockerfile should be in the current directory.
Vagrant uses SSH to run provisioner command such as shell scripts or Puppet runs. In our case we do not have an SSH server on the container so we set this parameter to false.
Use the ports parameter to specify port forwarding. The first port is the host port and the second port is the port on the container.
The volumes parameter allows you to specify a list of shared folders. In this example we map the Jenkins data folder to /data/jenkins.
Let’s start the Vagrant instance! Go to the directory of the Vagrantfile and run:
$ vagrant up Bringing machine 'default' up with 'docker' provider... ==> default: Creating the container... default: Name: jenkins default: Image: quintenk/jenkins default: Volume: /data/jenkins:/root/.jenkins default: Volume: /home/frank/Desktop/jenkins:/vagrant default: Port: 8080:8080 default: default: Container created: 22464e4b42ab8530 ==> default: Starting container... ==> default: Provisioners will not be run since container doesn't support SSH.
In a split second Vagrant pulled the image if it was not cached already and started the container with the right configuration. Now open up a browser and visit http://localhost:8080 and there it is a clean Jenkins instance .You can look at the Jenkins data from the outside when you go to /data/jenkins
$ ls -la /data/jenkins frank@franktop:~/Desktop/jenkins$ ls -la /data/jenkins/ total 48 drwxr-xr-x 8 root root 4096 Jul 18 16:47 . drwxr-xr-x 3 root root 4096 Jul 18 15:56 .. -rw-r--r-- 1 root root 159 Jul 18 16:47 hudson.model.UpdateCenter.xml -rw------- 1 root root 1680 Jul 18 16:35 identity.key.enc drwxr-xr-x 2 root root 4096 Jul 18 15:56 jobs -rw-r--r-- 1 root root 907 Jul 18 16:47 nodeMonitors.xml drwxr-xr-x 19 root root 4096 Jul 18 16:35 plugins -rw-r--r-- 1 root root 64 Jul 18 15:56 secret.key -rw-r--r-- 1 root root 0 Jul 18 15:56 secret.key.not-so-secret drwx------ 2 root root 4096 Jul 18 16:35 secrets drwxr-xr-x 2 root root 4096 Jul 18 15:57 updates drwxr-xr-x 2 root root 4096 Jul 18 15:56 userContent drwxr-xr-x 9 root root 4096 Jul 18 16:35 war
You can check the logs from the underlying process in the Docker container with the following command:
frank@franktop:~/Desktop/jenkins$ vagrant docker-logs ==> default: 2014-07-18 14:47:40,888 CRIT Supervisor running as root (no user in config file) ==> default: 2014-07-18 14:47:40,888 WARN Included extra file "/etc/supervisor/conf.d/jenkins.sv.conf" during parsing ==> default: 2014-07-18 14:47:40,890 INFO supervisord started with pid 7 ==> default: 2014-07-18 14:47:41,893 INFO spawned: 'jenkins' with pid 10 ==> default: 2014-07-18 14:47:43,341 INFO success: jenkins entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Here you see the logs from the supervisor process that monitors the underlying Jenkins Java process. For more information on Supervisor, checkout Quinten’s blog on Supervisor and Docker.
Halt & Destroy
When you want to stop the container run vagrant halt. If you want to destroy it run vagrant destroy. This command destroys the container but the volume will still be around. You can recreate the container running vagrant up. Doing this with Docker cli is a bit more involved.
This concludes this blog on how to set up Vagrant with Docker.
Thanks for reading! 🙂 Feel free to leave a comment or ask a question.