Vagrant describes itself as a tool to create VM based development environments, allowing it to be shared between developers. By default it sets up a local VirtualBox instance, although through an extensible set of providers it can also be used to create VMs in various clouds.
eBay internally has a private cloud based on OpenStack. This article summarizes my first experiences with Vagrant and creating a new OpenStack VM instance.
Automated Deployment Technology Maturity
More and more projects are moving to the cloud. The whole idea of not having to bother with buying and maintaining hardware, maintaining a machine room, and all the other “stuff” that comes along with hosting servers is rather attractive. The industry trend I believe has also been simplified with ongoing improvements in supporting tools. For example:
- There is lots of good, free software (Linux, Apache, MySQL, etc) making it easy to spin up more servers without too much licensing pain.
- Popular distributions of Linux all have good software installation technologies. Whether it is rpm, yum, or apt-get, most useful software packages can now be installed with a single command. This greatly simplifies the automation of creating a new server instance.
- While installing the base software release is much easier and more consistent, some local configuration is still typically required specific to your application or hardware. For example, do you want the HTTPS port opened on your web server? How to install your server certificate file? How many concurrent threads do you want to allow? After packages have been installed on your server, tools like Puppet, Chef, and Ansible simplify automation of configuration changes.
These sorts of tools have made a big difference when it comes automating the setup of a new server or VM. (The fact whether the server is virtualized or bare metal is not relevant here.
Vagrant
So what does Vagrant have to offer? The way I see Vagrant is it is the beginnings of trying to abstract building a VM from a specific deployment environment. That is, it is moving a layer higher in the abstraction stack, building upon the other existing tools. Using Vagrant it is possible to define a template of how to provision a server built on top of tools like those mentioned above. This template can then be used with multiple hosting providers.
Vagrant abstracts out deployment settings by allowing a ‘box’ definition to define special rules for different ‘providers’. Which provider to use is selected when the Vagrant command line tool is run. For example, one provider creates a VirtualBox VM on the user’s local machine, another can create an Amazon Web Service (AWS) instance, and other providers are popping up such as for OpenStack. This is great – it abstracts a VM definition away from a particular provider, making it possible to test a definition on the developer’s local machine before deploying to a production environment in the cloud.
So why do I say it is only the ‘beginnings’? While the provider is abstracted out, there are still issues. (Disclaimer: The following is personal opinion based on limited real experience.)
- When using OpenStack, the approach is to identify which OS image to use from a set of images that exist in your OpenStack cloud. When using VirtualBox, the OS image is downloaded and created locally. So different providers may need a different OS image starting point. The OS images may come pre-configured with knowledge of the hardware and networking environment they are to operate within.
- Different hosting providers will have different server specifications that should ideally be taken into account. For example, there may be different amounts of memory available, meaning cache sizes need to be different for the different environments.
- Configuration of packages (like the Apache web server) differs across releases, and software package release availability is often linked with OS releases. Ideally you want to describe the configuration wanted to be achieved (e.g. listen on a HTTPS port with a certificate) without being specific to a version of the package. This level of abstraction is not currently available in Vagrant – I cannot (I believe) describe a concept (such as configure the HTTPS port of Apache) and provide different implementations of this concept (e.g. specific to different versions of the web server).
Even though such variations exist, the provider abstraction is still a great step forwards – just not enough yet to make ‘boxes’ (VM definitions) truly reusable and generic. That may take a bit more time for the maturity level of the relevant technologies to continue to improve. For example, maybe Vagrant could add support to detect the web server version installed and use the appropriate Puppet scripts relevant to the version.
Vagrant and OpenStack
Back to my hands on experiment – creating a OpenStack VM using Vagrant. Doing a web search I came across what looked like a few different provider implementations for OpenStack so I used a highly scientific evaluation and selection approach – I picked the first one returned by the search engine! In my case that brought up cloudbau/vagrant-openstack-plugin.
To make my life a little more complicated, I run Windows on my laptop. For myself, that meant tools like rsync were from Cygwin. This caused me some problems as Vagrant or the OpenStack plugin expands some relative path names into absolute path names. The problem with this is the Cygwin rsync implementation does not understand the resultant Windows full path names. (rsync wanted /cygdrive/c and not C:\.) So I had to do some quick hacks to the Ruby scripts to get it to work for myself. Linux or Mac users should not have these sorts of problems.
The following is the configuration file I ended up with.
# -*- mode: ruby -*- # vi: set ft=ruby : VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # Every Vagrant virtual environment requires a box to build off of. # ‘dummy’ is an empty box to build upon. config.vm.box = "dummy" # I created a keypair from the OpenStack Web UI and downloaded it. config.ssh.private_key_path = "my-key.pem"
# Specify the OpenStack provider configuration options. # (This file does not contain any other provider configurations. # but it could.) config.vm.provider :openstack do |os| # In the OpenStack UI, there was an option to download a shell # RC file with environment variables set to access the cloud. # The following #{ENV['OS_USERNAME']} references assume those # environment variables have been set up before the ‘vagrant up’ # command is run. # OpenStack Authentication - get from environment variables. os.username = "#{ENV['OS_USERNAME']}" os.api_key = "#{ENV['OS_PASSWORD']}" # Select the image to use. I looked through the locally available # images and selected a supported option. In this case I selected # an image using Ubuntu 14, then selected the ‘tiny’ flavor # (1 CPU and limited memory). os.flavor = /tiny/ os.image = /ubuntu-14/ # OpenStack identity endpoint – used to authenticate against. os.endpoint = "#{ENV['OS_AUTH_URL']}/tokens" os.keypair_name = "my-key" os.ssh_username = "stack" # Prefix added to my instance. That is, the hostname in this # case will be “play-“. os.server_name = "play" # Tenant/project name in OpenStack. This controls where the instance # is created (e.g. which data center). os.tenant = "#{ENV['OS_TENANT_NAME']}" end # Install puppet for in order for other provisioning to work. # (Other base OS images may have Puppet pre-installed.) config.vm.provision :shell, inline: "sudo apt-get -y install puppet" # Use Puppet to configure packages as required. config.vm.provision :puppet do |puppet| puppet.manifests_path = 'puppet/manifests' puppet.manifest_file = 'site.pp' puppet.module_path = 'puppet/modules' end end
The above was my complete Vagrantfile. See the embedded comments for descriptions of the appropriate sections of this file. In this case, with the OpenStack VM images already located in the OpenStack environment, Vagrant only had to manage the name of the instance to install (not download the whole OS image). This I suspect saved me quite a lot of transfer time and may have reduced the configuration of the OS required as it was officially certified as ‘supported’ by the cloud hosting team.
Using Vagrant, I could spin up new instances just by running ‘vagrant up’ on the command line. There were additional files to configure the host via Puppet not shown above – I stole these from other projects I found via web searches. They are not specific to Vagrant so I did not include them.
Conclusions
Apart from some issues relating to using Windows on my laptop, the OpenStack provider I selected did work without too much effort. I created a new server instance with a running Apache web server instance (configured via Puppet).
Debugging was a bit painful – each iteration took a while (minutes) to create a new VM instance and get it spun up. But it did work as advertised.
The ‘provider’ abstraction was nice, but complete abstraction was not available. I must admit I was left wondering with OpenStack how much effort Vagrant saved me over just using a shell script to run Puppet to set up a server. I suspect in real life the value of Vagrant may increase when you want to test your deployment locally and then provision it to the cloud. I did find it slightly strange the Vagrant web site talked so much about setting up development environments with not much talking about reusing the scripts in production. It did make me wonder if there were hidden issues lurking there that I did not yet understand.
Another area I have not explored yet is whether the scripts can be easily used to manage a cluster of say web server nodes, including adding and removing nodes form the cluster. There does seem to be some support for this, but again this feels like an area for additional development.
All up, Vagrant looks interesting. It was kinda cool seeing a node spin up by itself from scratch. However, I have some concerns that it is not quite generic enough yet to reach its full potential. I am not sure how portable the Vagrant box definitions are in practice. But I do think the emergence of tools such as Vagrant bodes well for the relevant industry in general – the direction makes sense, it just has further to go.
PS: This post was not intended to be about Magento, just Vagrant. However for those interested, a web search such as “Magento vagrant” will quickly bring up work that different people are doing to provision Magento nodes using Vagrant.