Using Capistrano to Deploy Django Apps

Capistrano is a great tool for automating tasks on one or more remote servers. It’s mainly used for deploying Rails apps but it can fairly easily be used for other tasks, too. After reading the new getting started docs for upcoming 2.0 version, I created a simple script for deploying Django apps with Capistrano.

Feeling Lazy

Let’s be honest. Deploying Django apps is dead easy. There really isn’t much stuff that would need automation. But there are many situations where you are doing much more work on the remote server than you’d really want to. The more commands you execute the more the chances of screwing up increases. And personally, I’m just too lazy for doing simple monkeywork on the command line again and again. This is where Capistrano comes along: it can do most of the work for you.

Do it Capistrano Way

Capistrano, like Rails, assumes many things about your project. For example, it assumes that you want to deploy a Rails app, and that you are using subversion for version control. Also the current documentation is mostly written from Rails viewpoint. Fortunately the docs have been improved lately and Capistrano is starting to present itself as a true multipurpose tool — which it really is.

I generally like the Rails-way of doing things. When things are always done in a consistent way, developing becomes really easy. (Don’t underestimate the weight of cognitive load!) Until you want to be different. At that point everything usually falls apart. Fortunately Capistrano is fairly flexible in this regard — you can do things your own way.

Capistrano has built-in functions for doing stuff like deploying (a Rails app), controlling FCGI servers, and simple rollbacks. I wanted to do something very basic and in a way that could be easily modified and expanded. After learning the basics and reading Capistano chapter on Rails manual, I wrote and tested the following script in just few hours. It uses just basic shell commands, none of those fancy Capistrano functions. I think that this script is a good starting point for building smarter and more complete scripts.

Run Me Baby One More Time

Okay, let’s cut the crap. In brief, what I wanted to do with Capistrano was ease the upgrading of production sites by automating a set of things I do when upgrading a production site.

I work for a small company where we run dozens of Django sites on many different servers. (I believe we are if not the only one, at least one of the few companies in Finland that specialize in Django.) A typical project consists of one subversion repo and a server setup of Apache+mod_python and dedicated servers for database and static files. All of our projects are configured for easy off-line development and most of them usually need some tweaking on the production server after a subversion checkout.

Personally I like to do development with real data, so normally just before deployment I import the live database to my local machine, modify it if needed, and finally upload the modified dump back to the production server. Naturally, this only works on small sites, but for those (and for me) it works great.

So, my first Capistrano script automates what I normally do manually for an upgrade of a small site. The steps are:

  1. Log in to a remote server
  2. Run svn update in project directory
  3. If there are changes in models:
    1. Backup old database
    2. Upload new database to server
    3. Import new database
    4. Delete the just loaded sql-file
  4. Move settings.py in place
  5. Reload apache

Most importantly, Capistrano does all this in a way that in a case of “OMG! OMG!11 I JUST BROKE THE ENTIRE SITE!11” (which of course never happens because I’m perfect and I never do mistakes) I can roll back all of the changes in a matter of seconds.

The Capistrano script that does all the above looks like this.

This script can be run from the local development machine. I put mine in the projects root directory. And when upgrading the site, I run the upgrade_project-task that I wrote by typing cap upgrade_project. Capistrano then asks for my password, logs in to the remote server(s) and executes every command defined in given task, outputting the results on the terminal as it goes. It’s finished before you can say “freaking cool”. For added security you can (and should) use SSH keys for authentication, and Capistrano lets you even define a gateway server for piped connections.

The capfile is a ruby script that defines one of more tasks. A task consists of one or more commands that will be executed on one or more remote servers. (Capistrano can run a task simultaneously on several remote servers.) A small task could be something like running ls on a remote server, while a complex one could do everything needed for deploying an application on a virgin box. There really isn’t much limits to what Capistrano can do.

IM IN UR DJANGO

Above example is a quick & dirty proof-of-concept type of script. I know it can be bettered quite a bit. It would be nice to see more Django-related scripts out there. If you have used Capistrano for Django-related work, share your experiences! Also bettering the Capistrano documentation wouldn’t hurt. Django wiki is one good place for sharing.

For something to think about, with a little bit of extra work it would be possible to do totally virgin deployment with configuring apache and media servers, too. I’m also pretty sure that it would be possible to use some of the Capistranos built-in helpers for deploying non-Rails apps. Google for using Capistrano for more info.

I hope this post got you at least a bit interested in Capistrano. If you have any suggestions or comments, please add them below 🙂