For some time now Vagrant has been the go-to solution for creating development environments that can be configured independantly of your machine and shared with a team. There are many benefits to using virtual machines over installing software directly on your local machine (as MAMP does for example):
- Software stacks are entirely independent from the machine you are working on.
- Software stacks can be shared with other people and be reproduced automatically with ease.
- Virtual machines can be started and stopped as required.
- Hosting environments become ephemeral and can be thrown away when no longer useful.
- It saves a lot of time.
Over the last couple of years, however, a new kid on the block has been gaining traction. While Docker also runs on a virtual machine it works in a fundanmentally different way. In this post we’re going to look at the difference between Vagrant and Docker and show you how to set up a WordPress development site in each.
Vagrant vs Docker – High Level Comparison
Vagrant utilises a much simpler architecture than Docker. It uses virtual machines to run environments independent of the host machine. This is done using what is called “virtualization” software such as VirtualBox or VMware. Each environment has its own virtual machine and is configured by use of a
Vagrantfile tells Vagrant how to set up the virtual machine and what scripts need to be run in order to provision the environment.
The downside to this approach is that each virtual machine includes not only your application and all of its libraries but the entire guest operating system as well, which may well be tens of GBs in size.
Docker, however, uses “containers” which include your application and all of its dependencies, but share the kernel (operating system) with other containers. Containers run as isolated processes on the host operating system but are not tied to any specific infrastructure (they can run on any computer).
What is the upshot of all of this?
- Vagrant is easier to understand and is easier to get up and running but can be very resource intensive (in terms of RAM and space).
- Docker’s architecture is harder to understand and can be harder to get up and running but is much faster, uses much less CPU and RAM and potentially uses much less space than Vagrant VM’s.
Setting up Vagrant
One of the great things about both the Vagrant and Docker ecosystems is that, due to the fact environments are easy to script and share, there are loads of great Vagrant “boxes” and Docker images already available to use.
In this case we are going to use a project called Varying Vagrant Vagrants (VVV) which is a popular vagrant configuration specifically designed for WordPress development. Before we begin, you will need both VirtualBox and Vagrant installed on your machine.
There are also several Vagrant plugins that VVV recommends you install:
- vagrant-hostsupdater – Automatically updates your
hostsfile to access the provisioned VVV domains in your browser.
- vagrant-triggers – Allows for various scripts to fire (such as database backups) when issuing commands such as
Now that we have all the prerequisites installed let’s clone the VVV repo:
$ git clone git://github.com/Varying-Vagrant-Vagrants/VVV.git vagrant-local
Then we simply need to
cd into the directory and run
$ cd vagrant-local && vagrant up
It will take Vagrant a while to download the required files, set up the virtual machine and provision it. (Note: if you’re using the “vagrant-hostsupdater” plugin you may be prompted for your password.) Once the provision script has finished you should be able to visit http://local.wordpress.dev and see WordPress! I recommend you read the VVV Readme for more information on how to set up and use VVV WordPress sites.
Setting up Docker
To get started with Docker first you need to install the Docker Toolbox which provides you with not only the Docker Client, but also Docker Machine (which controls the Docker Engine, previously boot2docker) and Docker Compose (which allows you to specify a multiple container setup in a single file) as well as some other bits and pieces.
Once you have it installed, the first thing you need to do is set up a Docker Virtual Machine. Docker will use this virtual machine to run the Docker Engine which manages any containers that you want to run. To do this let’s create a Docker Machine using VirtualBox called “docker-vm”:
$ docker-machine create --driver virtualbox docker-vm
Once the machine has been created we can check the details of the machine by running:
$ docker-machine env docker-vm
It should output something similar to:
export DOCKER_TLS_VERIFY="1" export DOCKER_HOST="tcp://192.168.99.101:2376" export DOCKER_CERT_PATH="/Users/gilbitron/.docker/machine/machines/docker-vm" export DOCKER_MACHINE_NAME="docker-vm" # Run this command to configure your shell: # eval "$(docker-machine env docker-vm)"
You’ll notice that these are actually commands that set environment variables for the Docker Client to communicate with the Docker Engine. So we do as we are told and run:
$ eval "$(docker-machine env docker-vm)"
Top tip: Every time you open a new session you will need to run this eval command as these settings don’t persist. So to save you this hassle you can add the eval command to your
~/.bashrc file so that it is run automatically every time you open a new session.
Now we are finally able to start creating Docker containers. One important thing I should point out here is that Docker encourages running only one process per container. This means that technically if we were running a LAMP stack, Apache, MySQL and PHP-FPM should all be run in their own containers. These, however, are only guidelines and in most cases it’s fine to group relevant processes together (for example Apache and PHP would normally run in one container, and MySQL in another container).
Thankfully there are official Docker images for both WordPress and MySQL that we are going to use. We will run WordPress (which includes Apache and PHP) in one container and we will run MySQL in a different container as the database.
To create a MySQL container run:
$ docker run --name wordpressdb -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress -d mysql:5.7
You can have a look at the docker run reference to see what each of these flags does in detail but here is a quick rundown:
- We give our container a
--nameso we can link to it later (if we didn’t specify this a random name would be generated).
- We specify two
-eenvironment variables that will be used by the container. This is a common way of passing configuration information to a container.
- We tell the container to run in detached mode.
- Finally we specify the
image:versionwe want to use. If the image doesn’t exist locally it will be downloaded.
Next let’s create a WordPress container:
$ docker run --name wordpress -e WORDPRESS_DB_PASSWORD=password -v "$PWD/":/var/www/html --link wordpressdb:mysql -p 80:80 -d wordpress
There are two things we did here that we didn’t do for the MySQL container above:
- We specified a
-vvolume to map our “Present Working Directory” to the
/var/www/htmlfolder inside the container (note that
$PWDcould be an absolute or relative path as well). This allows us to manipulate the WordPress files.
--linked this container to our
wordpressdbcontainer and gave it an alias
mysql. This allows the WordPress container to connect to the MySQL container.
- We set up ports so that port
80on our virtual machine points to port
80in the Docker network (which will be this container).
We can check the status of our containers by running:
$ docker ps
Now you can simply visit the IP address of your Docker Machine (you can find the IP address by running
docker-machine env docker-vm like we did above and looking at the
DOCKER_HOST value) et voilà you should see a WordPress install screen. Now would be a good point to add a local domain to your hosts file so you don’t need to use the IP address all the time. You should also see the WordPress files in your
$PWD as we set it up as a volume earlier.
Bonus: Use Docker Compose
Running commands like we did above can be quite cumbersome and prone to human error. Docker Compose can help us out as it allows us to specify a single file in which we can define our entire environment structure and run it with a single command (much like a
Let’s create a
wordpress: image: wordpress environment: - WORDPRESS_DB_PASSWORD=password ports: - "80:80" volumes: - ./:/var/www/html links: - wordpressdb:mysql wordpressdb: image: mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_DATABASE=wordpress
You can see how we’ve just replicated the commands above into a
yml file (using the compose file reference). Now all we need to do is run:
$ docker-compose up -d
So Which is Better?
As with all things of this nature there is no “right” and “wrong”, “better” or “worse”. It depends entirely on how you want to use it and what you feel comfortable with. I personally dabbled with setting up a Docker development environment recently but decided it was just too complex to get things working the way I wanted. I’m happy using Vagrant for the time being as it’s simple and just works, but I’ll be keeping an eye on Docker as the project matures and things will no doubt become easier.
What do you use for your development environment? Do you prefer Vagrant, Docker or something else?