Covering Deployments With Fabric

I think I’ve officially decided that Fabric is my favorite Python module ever. Sure there are probably other modules I use constantly and never really care about (sorry datetime!). However, they don’t bring me the sheer joy that Fabric brings to me. When I’m developing my personal applications, namely YaBa (this blog) and HateOnYourJob, I tend to perform frequent deployments. Unfortunately deployments can be a time consuming process of bundling my application, pushing it to my server, exploding the archive, putting it in place, restarting Apache and Memcached, and then testing my changes. Not only is that all time consuming, but it’s also very prone to human error (i.e. me being a jackass). Now, I thought initally, before I learned of the joys of Fabric that is, that a simple BASH script could easily perform my deployments. So I did at one point have some loosely coupled group of BASH scripts for performing deployments, but it just didn’t feel flexible enough. Insert Fabric though, and everything is absolutely effortless.

Currently this is roughly how my deployment path works.

1. Write some code in a git branch
2. Merge it on into the master branch
3. Push
4. Run my fabfile

My fabric file currently consists of:

set(fab_user='f4nt',
fab_hosts=['f4ntasmic.com'],
root='/tmp/',
site='hateonyourjob')

def staging():
set(root='/var/www/domains/hateonyourjob.com/new/')
set(settings='staging_settings.py')

def production():
set(root = '/var/www/domains/hateonyourjob.com/www/')
set(settings='production_settings.py')

def deploy():
local('git archive --format=tar HEAD | gzip > $(site).tar.gz')
sudo('chown -R f4nt.f4nt $(root)')
sudo('rm -rf $(root)$(site).OLDER')
sudo('mv $(root)$(site).OLD $(root)$(site).OLDER')
sudo('mv $(root)$(site) $(root)$(site).OLD')
run('mkdir $(root)$(site) -p')
put('$(site).tar.gz', '$(root)$(site)/$(site).tar.gz')
run('cd $(root)$(site) && tar zxf $(site).tar.gz')
sudo('rm -f $(root)$(site)/localsettings.py')
put('$(settings)', '$(root)$(site)/localsettings.py')
run('mkdir -p $(root)$(site)/cache')
sudo('chown -R apache:apache $(root)')
local('rm -f $(site).tar.gz')
restart()

def restart():
sudo('/etc/init.d/httpd reload')
sudo('/etc/init.d/memcached restart')

This file is executed by running:

fab production deploy

I can also replace ‘production’ with ‘staging’ to deploy to my staging instance of HOYJ. Also, along with it deploying to my staging instance, it’ll also put my staging settings file in place instead of my production settings file to ensure that I don’t have database conflicts. Some people like to timestamp each of their deployments, and have a rotation system in place built around that. Personally, I feel 3 deployments (current, old, and older) is typically plenty. If I need to fall back further than that I have a git repository that I can go mucking around in. Keeping 50 some odd deployments is just a waste of disk space in my opinion, but your feelings might vary.

I think what I enjoy about Fabric is how easy it is to follow and use. I barely know anything about Fabric, and have barely read any documentation, but I can do deployments with one quick command. Within 5 minutes my deployment is done, and it’s done right, everytime. That leaves me more time to focus on developing rather than futzing around with deployments where I’m likely going to screw something up since it’s boring and I’ll rush through it. :) Anyways, hope this points a couple more people towards Fabric that hadn’t previously heard of it. Maybe you Capistrano users might even find it useful :)