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
- 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