SidekickJS's blog

If you love automation why is your development environment manual?

I guess two things about you: you believe automation is a good thing, but you don’t automate your development environment.

Production vs development

Most teams I’ve been on run Linux. Development, however, is on OSX, and setup is a hideous mess of XCode, ports/brew, & random installer yak-shaving. And the final result barely resembles production.

Additionally most devs have hand-written their editor & command line config. If their laptop goes out of action they’ll take hours to get productive again.

The answer to both problems is the same - script it!

TL;DR: Vagrant + Chef + Vim/Emacs + SSH-in to VM + tmux = only configure your editor/*nix env once, no dev/production pain, repeatable deploys, common env across team.

Strategy

The idea is our editor, tools etc will all live on a virtual machine, in which we’ll also setup our application environment - databases, services etc. We can then develop features using the precise environment we have in production, reusing the production scripts.

Pros & con

The sole con for me has been the up-front cost. If you like GUI editors or IDEs this technique could also be trickier.

Tools

Chef

Chef allows you to define your server configuration in code. It uses a Ruby-based DSL, so it’s either familiar for you as a Rubyist, or a new language that’s easy and useful to learn. When Chef runs it ensures a server is in a specified state; the first run will be installation, later runs for deployment or maintenance.

template "/etc/nginx.conf" do
  owner "nginx"
  group "nginx"
  source "nginx.conf.erb"
end

A complete Chef tutorial is out of scope, but it’s easy to learn and there are great docs.

My strategy has been to split out the development environment into a separate recipe which is placed in the run list for my local environment. This takes care of:

Once the development recipe has been run I have my development repos cloned, my keys in place (kept out of version control, in secure online storage), my editor ready and configured. I can be writing, committing and deploying code immediately.

I also run 2 instances of the application - one over port 80 from the /srv directory as in production, the other from /home, over the same server, just changing ports. I edit and push code from the /home directory. When I’m happy with a feature in /home I reprovision the VM to run the deploy - and I know it’s ready to deploy cleanly in production!

VirtualBox

Since we want to be able to quickly create and destroy development environments, it’s best not to manage your machine’s actual OS with Chef. That implies virtualisation.

VirtualBox is a free virtual machine runner. We’ll not actually be doing anything with it aside from downloading the installer and running it.

Vagrant

We script VirtualBox via Vagrant. It’s responsible for downloading, installing and configuring virtual-machines: port-forwarding, shared folders, and the specific OS you’d like to install. It hands off responsibility for configuration of that OS to a provisioner - in this case Chef solo, but alternatively shell or Puppet.

Getting Vagrant is really easy - again just download and run the installer. You’ll then create a Vagrant file which contains the configuration of your box (or boxes if you have a multi-server production environment). You choose a base OS (‘box’ for Vagrant) and use the Vagrant command line tool to install.

You Vagrant file will contain configuration for the box, and for your provisioner, setting up the OS and your app’s environment respectively. Here’s a snippet from mine - you can see I’m forwarding ports so I can access services running on the box on my host browser.

config.vm.host_name = "vagrant.vagrantup.com"

config.vm.box_url = "https://github.com/downloads/leapcode/minimal-debian-vagrant/wheezy.box"

config.vm.forward_port 80, 8080 # chef managed rails from production recipe
config.vm.forward_port 3000, 3030 # dev rails in home

config.vm.provision :chef_solo do |chef|
  
  # ... boiler-plate

  # install editors, dotfiles etc
  chef.add_recipe "skjs::development"
  # install production environment
  chef.add_recipe "skjs"

  # dev overrides
  chef.json = {
    env: "development",
    unicorn_workers: 1,
    app_domain: "localhost",
  }
end

tmux or screen

Since our development environment now lives inside our VM, we’ll need to SSH in. Recreating the editor/command line sessions every-time you develop is a waste of time. A terminal multiplexer allows you to create persistent development sessions running multiple commands in different panes.

I keep a tmux session alive for each repository, tailing logs, running test servers and my editor. By suspending the VM rather than shutting it down I can run the same tmux session for weeks.

Conclusion

I can’t see any reason not to do this for new projects - it solves multiple pain-points and if you’re already using Chef or Puppet it’s mostly work you’ll need to do anyway. It’s been great for me as a bootstrapper - it would be even more beneficial for larger teams.