In the past months I was assigned a new task at work, that essentially boiled down to this question: how can we simplify the deployment of new development workstations?
In my development team at the time, we were tired of repeating the same (mostly manual and not documented) steps. The configuration process resulted in different development environment leading to confusion (it works on my machine!) and deployment issues.
We were in the situation where each developer, depending on his/her experience, installed and configured a set of development tools at his/her own will. This process was largely undocumented (READMEs were Holy Grails) and led to all sort of environment disparity issues. Moreover the configuration could not be easily changed because of the fear of breaking something. For the same reason no one actually bothered to install upgrades for such tools (we had someone who was stuck on a 3-years-ago Eclipse version!).
After some research, I could not find a out-of-the-box solution or even a set of established best practices to follow. Everyone was (is?) focusing on development environments and not on the configuration process of the development tools.
This solution (ferrarimarco/open-development-environment-devbox) is a process that produces a packaged machine with the needed tools already installed and ready to be used. For a list of the available tools refer to the README in ferrarimarco/open-development-environment-devbox.
Some of the included tools run inside Docker containers to ease and speed up the setup and deployment.
I chose Packer because it let me write a recipe (a single JSON file called template) to provision and configure the machine in a totally automated way. I just run the packer build command to start the build process.
The other interesting Packer feature is that you can use multiple providers ( different hypervisors and/or cloud providers), multiple configuration methods ( shell scripts, Ansible playbooks, Chef recipes, etc.) and different post processors to package the created images. This gives you maximum deployment flexibility (i.e. start with a local virtualized environment and move to a cloud based one in the future).
I chose to run the configuration process while building the image so I had to execute this process only once per build and not every time an instance is started.
The configuration process was implemented by developing a set of Ansible roles. I decided to use a dedicated configuration tool (Ansible) instead of writing shell scripts to avoid the complexity of ensuring the compatibility of such scripts across multiple platforms. I also benefited from the built-in node management mechanisms that these dedicated tools implement out-of-the-box.
The adoption of this kind of tools has the added plus of letting you reuse your code on different platforms (Virtual Machines, Physical Machines) without much effort. You just need to tell to such tools where your instances are and they will do the rest.
Physical machines, by applying the same set of Ansible roles to a given host. In this case Vagrant can be used as a development environment before applying any role to the production node.