As we have already discovered earlier in this chapter, Vagrant can be used as a virtual machine manager. We have already used it to bring up a local Ubuntu 14.04 instance using VirtualBox on our local machine; however, if we wanted to, we could have done this using VMware Fusion, Amazon Web Services, DigitalOcean, or even OpenStack.
Like Puppet and Ansible, when Docker was first released, there were a lot of articles published around Vagrant versus Docker. In fact, when the question was asked on Stack Overflow, the authors of both Vagrant and Docker weighed in on the question. You can read the full discussion at http://stackoverflow.com/questions/16647069/should-i-use-vagrant-or-docker-for-creating-an-isolated-environment
So, in what ways can Vagrant support Docker? There are two main ones we are going to be looking at. The first is the provisioner.
When we worked out way through Puppet, we used Vagrant to launch Ubuntu 14.04 locally using VirtualBox; as part of that, we used the Shell provisioner to install Puppet and deploy the Docker Puppet module. Vagrant has the following provisioners available:
The Vagrantfile
looks really close to the one we used to deploy our Puppet WordPress example:
# -*- mode: ruby -*- # vi: set ft=ruby : VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "ubuntu/trusty64" config.vm.network "private_network", ip: "192.168.33.10" HOSTNAME = 'docker' DOMAIN = 'media-glass.es' Vagrant.require_version '>= 1.7.0' config.ssh.insert_key = false config.vm.host_name = HOSTNAME + '.' + DOMAIN config.vm.provider "VirtualBox" do |v| v.memory = 2024 v.cpus = 2 end config.vm.provider "vmware_fusion" do |v| v.vmx["memsize"] = "2024" v.vmx["numvcpus"] = "2" end config.vm.provision "docker" do |d| d.run "mysql", image: "mysql", args: "-e 'MYSQL_ROOT_PASSWORD=password'" d.run "wordpress", image: "wordpress", args: "-p 80:80 --link mysql:mysql -e WORDPRESS_DB_PASSWORD=password" end end
As you can see, this will download (if you don't have it already) and launch an Ubuntu 14.04 server and then provision two containers, one WordPress and one MySQL.
To launch the host, run the following command:
vagrant up --provider VirtualBox
You should see something similar to the following terminal output:
You can also run the following command to open your browser and get to your WordPress installation screen (remember: we have launched the Vagrant host with a fixed local IP address, which means the following URL should resolve to your local installation):
open http://docker.media-glass.es/
You may have already noticed one thing that happened when we launched the Vagrant host: we didn't have to provide Vagrant any commands to install Docker; it took care of that for us.
Also, we had to launch our MySQL container before we launched our WordPress one. This is because we have linked our WordPress container to the MySQL one. If we tried to launch the WordPress container first, we would have received an error telling us that we are trying to reach a link that does not exist.
As you can see from the following terminal output, you can connect to your Vagrant host using the vagrant ssh
command:
The other thing you may notice is that the Docker version installed isn't the most up-to-date one; this is because Vagrant installs the version that is available in the operating system's default repository rather than the latest version provided by Docker in their repository.
As I mentioned, there are two ways in which you can use Docker with Vagrant: the one we just looked at is a provisioner, and the second way is to use a provider.
So, what's a provider? We have already used a provider twice in this chapter when we launched our Docker hosts. A provider is a virtual machine process, manager, or API that Vagrant can make a connection to and then launch a virtual machine from.
Vagrant has the following providers built in:
There is also a commercial plugin provided by the authors, which adds the following provider:
Finally, Vagrant supports custom providers, such as ones for Amazon Web Services, libvirt, and even LXC, for example. A full list of custom providers and other Vagrant plugins can be found at http://vagrant-lists.github.io/.
Obviously, if you are using OS X, then you won't be able to use the Docker provider natively; however, Vagrant takes care of this you. Let's look at launching an NGINX container using the Docker provider rather than a provisioner.
The Vagrantfile
looks a little different to the ones we have been using:
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.define "boot2docker", autostart: false do |dockerhost| dockerhost.vm.box = "russmckendrick/boot2docker" dockerhost.nfs.functional = false dockerhost.vm.network :forwarded_port, guest: 80, host: 9999 dockerhost.ssh.shell = "sh" dockerhost.ssh.username = "docker" dockerhost.ssh.password = "tcuser" dockerhost.ssh.insert_key = false end config.vm.define "nginx", primary: true do |v| v.vm.provider "docker" do |d| d.vagrant_vagrantfile = "./Vagrantfile" d.vagrant_machine = "boot2docker" d.image = "russmckendrick/nginx" d.name = "nginx" d.ports = ["80:80"] end end end
As you can see, it is split into two parts: one for a Boot2Docker virtual machine and the second part for the container itself. If you were to run vagrant up
, you would see something like the following terminal output:
As you can see, as I am using OS X, Vagrant knows that I can run Docker natively, so it takes the first section of Vagrantfile
and launches a Boot2Docker instance. Boot2Docker is the tiny Linux distribution that powers Docker Machine's default driver.
Once it has downloaded the Boot2Docker Vagrant Box, it launches the virtual machine and maps port 22
on the virtual machine to port 2222
on our local PC so that we can get SSH access. Also, as defined in Vagrantfile
, port 80
from the virtual machine is mapped to port 9999
on the local PC.
Its worth noting that if I were running this on a Linux PC that had Docker installed, then this step would have been skipped and Vagrant would have made use of my local Docker installation.
Now that Boot2Docker has been started, the second part of the Vagrantfile
can be run. If, like in my case, Vagrant has downloaded and launched the Boot2Docker Vagrant Box, then you will be asked for a password; this is because we have not exchanged keys with the Boot2Docker virtual machine. The password is tcuser
.
Once you have entered the password, Vagrant will download the NGINX image from https://hub.docker.com/r/russmckendrick/nginx/ and launch the container, opening port 80
.
Once the container has been launched, you should be able to go to the NGINX welcome page at http://localhost:9999/
.
If you like, you can SSH into the Boot2Docker virtual machine, as Vagrant is primarily managing the container and not the Boot2Docker virtual machine. You will have to use the following command:
ssh docker@localhost -p2222
Again, because we have not exchanged keys, you will need to enter the password, tcuser
. You should then see this:
Once SSHed in, you will be able to run Docker commands locally. Finally, to terminate both the container and virtual machine, run the following command from within the same folder as your Vagrantfile
and you will see something as following:
vagrant destroy
This will prompt you, asking whether you are sure you would like to remove the container and then the virtual machine; answer yes to both questions.
You must have noticed that we didn't cover our WordPress example while walking through the Docker provider. The reason for this is that the Docker provider functionality, in my opinion, is pretty much redundant now, especially as it has quite a few limitations that can all be easily overcome by using the provisioner or other tools.
One such limitation is that it can only use port mapping; we cannot assign an IP address to the virtual machine. If we did, it would have silently failed and reverted to port mapping from the virtual machine to the host PC.
Also, the functionality offered when launching containers doesn't feel as up to date and feature aligned to the latest version of Docker as the other tools we have been looking at so far in the chapter.
Because of this, I would recommend that you look at using the provisioner rather than the provider if you are looking at utilizing Vagrant.