Recently, for some reason, I’ve found myself creating a number of virtual machines: Linux machines, AWS machines, new machines, etc.
Invariably, the first things I want are to get “my” personal toolchain in place. I want:
- my vim configuration
- my tmux configuration
- my favorites libraries
- Ember Data
- my Ruby version manager (chruby)
To this end I have adopted “Chef”. Thanks to the following superior documentation resources, I found this to be not too much of a pain.
Figure Out EC2 Instances on AWS
I had never used EC2 or AWS for computing services. This is a means for getting a virtual machine that you can pay for per-use from Amazon. The reason I wanted one of these is that I wanted a development machine that I could work on and throw away if I messed it up too bad. Since I wanted this deployment solution to “pretty much work” without me minding it I wanted to be able to destroy the machine completely and make sure that my deployment and configuration worked.
Since I decided to use Ubuntu for my target operating system, I was able to follow Ubuntu’s great guide on getting Ubuntu on EC2.
Use Chef to Configure a “Pristine” System
Thanks to (the great) Jo Liss' documentation on how she automated her deployment process with Chef, I had a great framework for using chef-solo deploy my recipe and get things running. Thanks to Jo’s example I was able to get my own “recipe” on the remote host and do some trivial “test” tasks (install a package with
apt-get, ensure ruby was installed, etc.). From there it was just about adding more tasks (in Chef-ese these are called “Resources”) to my recipe. I put all my “Resources” in a single “Recipe” in a single “Cookbook.” This means that I can’t pick-and choose my recipes (as) flexibly but I don’t see that as too much of a problem since my deployment targets are fairly uniform. I did take an approach that I think may help my monolithic resource be a bit more flexible, see the “Tips” section below.
Taking a quick look at Chef’s Resources page should demonstrate just how many tasks Chef can make easy for you
Nothing fun or sexy about this one. Iterate on getting the resources to do what you think should happen. Re-run the recipe. Does it work?
Focus on idempotency (which I pronounce e-dem-pO-tency because I cannot bear mangling a purely Latinate word): make sure that your script cleans up after itself and returns the system to a “pristine” state. As you develop you will probably have to re-run things several times so a leftover temp directory could be the difference between a successful and unsuccessful run.
Embrace conditionals to speed up development: as you are iterating,
if you do clean up as I suggest, you can put in test clauses such as
not_if which means that instead of re-running some long process (like
building Ruby) you can test if the binary is where you put it. If it is
don’t rebuild. While you might go get coffee for the first pristine
build, it’s nice to have successive iterations avoid the long steps and
simply try to integrate new differences.
Leverage the shell: One of the resources is run pure bash script. I put several bits of logic in bash because if I were ever on a machine that didn’t have chef (for example, there is no build available for my laptop, presently), I could run a manual step or two and then copy and paste out the relevant sections into a shell script which I could run on a one-off basis.
So there you go, chef can make building a deploying new systems to baseline much easier. As always, it’s much easier to delete unwanted behavior than to write new behavior. Chef gives you something that’s a bit more nicely abstracted than a shell script (seriously, how brain dead is a shell script test for directory presence or substring substitution? Can you ever remember that syntax right the first time? I cannot).