Django + Fabric = easy multi-stage deployment on WebFaction
The django docs do not sufficiently cover best-practices for deployment of a site; just googling about the different ways of configuring multiple settings.py files is proof of that. Below, I have posted my current approach to multi-stage deployment of 1000it.pl which is currently deployed with the help of Fabric.
The idea is to have three separate stages: testing, staging, and production. Running
fab deploy
deploys our current SVN HEAD to the test server, which uses a copy of the production database (to safely test all functionality and database migrations without any chance of catastrophic failure). After we have thoroughly tested our new system, we run
fab promote_stage
which promotes our testing system to staging, migrates our production database, and releases all new functionality and templates on our staging domain. Note: at this time our production database has already been migrated, but our production domain is still showing old views/templates. The idea is to check that everything migrated smoothly and then with one command, we flip the switch to our new server:
fab promote_live
Currently the server code is hosted in a subversion repository, while development work is done with git and git-svn. The manner of deploying code to the server is given as an example, it can be easily modified to your needs. The fabfile.py is posted below. It is still a work in-progress, but maybe someone may find it useful. Among other things, we still need to improve automated testing of the test server (eg. twill, selenium) as well as make more elegant rollback procedures.
from __future__ import with_statementfrom fabric.api import env, run, localfrom fabric.context_managers import cdenv.hosts = ['yourdomain.com']env.user = 'username'serv = {}serv['webapp'] = '/home/username/webapps/yourwebapp'def update_testdb():env.warn_only = Truerun('pg_dump -Ft -U prodDBuser prodDB | pg_restore -c -O -U testDBuser -d testDB')def deploy():with cd(serv['webapp']):with cd('svntrunk'):run('svn update')run('svn export --force . ../site/testing/release/')with cd('site/testing/release'):run('python2.6 ./bootstrap.py')run('bin/buildout \django:settings=settings_prestaging')run('bin/django syncdb')run('bin/django migrate')run('bin/django test')def promote_stage():with cd(serv['webapp']):with cd('site/staging'):run('rm -rf ./release')run('mv ../testing/release release')with cd('site/staging/release'):run('bin/buildout \django:settings=settings_production')run('bin/django syncdb')run('bin/django migrate')
run('bin/django test')def promote_live():with cd(serv['webapp']):with cd('site/live'):run('rm -rf ./release')run('mv ../staging/release release')with cd('site/live/release'):run('bin/buildout \django:settings=settings_production')run('bin/django syncdb')run('bin/django migrate')run('./apache2/bin/restart')def init():
local('python ./bootstrap.py', capture=False)def dev():
local('bin/buildout \
django:settings=settings_dev', capture=False)
local('bin/django syncdb', capture=False)
local('bin/django migrate', capture=False)
local('bin/django test', capture=False)
local('bin/django runserver', capture=False)
Do you have a better approach? Maybe you're using Capistrano with better results? Do post a comment!




Comments [0]