For the last eight years, we’ve watched with special attention the evolution of web ecosystems like Ruby and Ruby on Rails, which were until recently our go-to tools in the development of backend infrastructure to support both web and mobile applications.
Eight years is a long time in the life of any technology on a never-ending evolution process. For that reason, we’ve seen projects built in the almost forgotten Rails 3.1 on top of Ruby 1.9, without keyword arguments or safe navigation operators, to the most recent Rails 5.2.2 on Ruby 2.5.3. Now add several different versions of gems and a dash of package’s dependencies – on top of different operating systems – and we get a myriad of project environments.
In such scenarios, setting up a development environment that allows replication of the conditions to reproduce a bug, or even having a quick way of checking the current state of the project in order to estimate the effort of introducing a new feature becomes a critical and urgent task.
Switching between projects with different configurations and environments becomes harder, and transitioning to old projects in order to provide a hot-fix turns into a dreadful and frustrating task.
This is because the setup of old projects takes longer than the time to reproduce, fix and deploy a new hot-fix.
That’s not fun.
That’s not healthy.
That’s not efficient.
It became evident that there was a need to preserve the development environment in a portable and confined manner, allowing a smoother transition between projects.
That’s when Vagrant stepped into action.
In Vagrant we trust
Vagrant is a popular open source virtual machine declaration and management tool from HashiCorp. Its popularity comes from the simple Ruby syntax that describes a resource from base image, the resource allocation feature, and other minor provision configurations, such as how it mounts a shared folder or hook provision scripts to prepare the development environment.
Additionally, it was extended by the community to support popular hosting services such as Amazon Web Services or DigitalOcean, allowing them to work as providers and abstract all the creation and management process of Droplets and EC2 instances.
This way, developers can simulate and coordinate multiple node architectures through a familiar interface. And the best part? All the specifications are done on a single text file, which can be easily bundled into a project and kept under version control, ready to checkout.
Going further with Ansible
Vagrant offers a fast and clean way of interacting with development environments, using an operating system similar to staging and production. This increases the resilience of applications and makes them less prone to failures that stay hidden on development environments. However, by itself, Vagrant is not the best tool to provision a virtual machine.
Taking this into account, Ansible was our weapon of choice to provision the virtual machines. It doesn’t require any kind of agent running on the virtual machine, as other alternatives such as Chef and Puppet would, and does most of its work through Push, via SSH.
Its specifications are done in YAML, making it quite readable and easy to understand, so that anyone can quickly entail each instruction and change a provision script to suit new needs, such as adding an extra system library for a new gem. The overall structure of the scripts also enables a clear view of the changes being introduced, which helps to entail the new dependencies added during code reviews and security audits. That’s something easy to miss when evaluating a plain shell script with long commands that look like an endless cargo train.
With Vagrant, Ansible’s scripts are just plain text that can be stored with the project, under version code.
The Vagrant Experience
Similar to what happens with every other innovation, Vagrant and Ansible's introduction may meet different degrees of resistance on its adoption. Developers that are allocated on just one project for longer periods of time may not fully appreciate this necessity or value its portability, and that’s understandable.
However, as developers hop from project to project, tinkering with different stuff on a daily basis, they will get a better understanding of how valuable Vagrant is. It’s not an uncommon scenario to fix something on an old Python project in the morning, switch to Ruby maintenance in the afternoon and tinker with Node.js in the next day, for instance.
Vagrant efficiently allows to change the project’s context.
The future of Vagrant and Ansible
Ansible alone is a powerful provisioning tool that effectively interacts with multiple VPS and can be used to deploy changes in large clusters. While a massive usage of Ansible to manage large clusters is not foreseeable in the near future, by adopting it consistently, one can reuse the already built Ansible scripts to setup development virtual machines, provisioning the VPS that will host both staging and production environments.
It's mostly aligned with development best practices, as it builds good and flexible provision scripts that can fulfil more than just provisioning a virtual machine, reusing them when trying to deploy the application to multiple environments.
Whilst Vagrant can be used as a tool to create and manage VPS for development, or even to create staging and production environments, there are other tools that can be used to accomplish the same goals, such as Terraform.
But that's a whole new story for another day...