How do you use pip, virtualenv and Fabric to handle deployment?

e-satis picture e-satis · Mar 14, 2010 · Viewed 13.1k times · Source

What are your settings, your tricks, and above all, your workflow?

These tools are great but there are still no best practices attached to their usage, so I don't know what is the most efficient way to use them.

  • Do you use pip bundles or always download?
  • Do you set up Apache/Cherokee/MySQL by hand or do you have a script for that?
  • Do you put everything in virtualenv and use --no-site-packages?
  • Do you use one virtualenv for several projects?
  • What do you use Fabric for (which part of your deployment do you script)?
  • Do you put your Fabric scripts on the client or the server?
  • How do you handle database and media file migration?
  • Do you ever need a build tool such as SCons?
  • What are the steps of your deployment? How often do you perform each of them?
  • etc.

Answer

Carl Meyer picture Carl Meyer · Mar 15, 2010

"Best practices" are very context-dependent, so I won't claim my practices are best, just that they work for me. I work on mostly small sites, so no multiple-server deployments, CDNs etc. I do need to support Webfaction shared hosting deployment, as some clients need the cheapest hosting they can find. I do often have to deploy sites multiple times in different environments, so repeatable scripted deploys are critical.

  • I don't use pip bundles, I install from a requirements.txt. I do run my own chishop server with sdists of everything I need, so there aren't multiple single points of failure in the build process. I also use PIP_DOWNLOAD_CACHE on my development machines to speed up bootstrapping project environments, since most of my projects' requirements overlap quite a bit.
  • I have Fabric scripts that can automatically set up and configure nginx + Apache/mod_wsgi on an Ubuntu VPS, or configure the equivalent on Webfaction shared hosting, and then deploy the project.
  • I do not use --no-site-packages with virtualenv, because I prefer having slow-moving compiled packages (Python Imaging Library, psycopg2) installed at the system level; too slow and troublesome to do inside every virtualenv. I have not had trouble with polluted system site-packages, because I generally don't pollute it. And in any case, you can install a different version of something in the virtualenv and it will take precedence.
  • Each project has its own virtualenv. I have some bash scripts (not virtualenvwrapper, though a lot of people use that and love it) that automate deploying the virtualenv for a given project to a known location and installing that project's requirements into it.
  • The entire deployment process, from a bare Ubuntu server VPS or Webfaction shared hosting account to a running website, is scripted using Fabric.
  • Fabric scripts are part of the project source tree, and I run them from a local development checkout.
  • I have no need for SCons (that I am aware of).

Deployment

At the moment a fresh deployment is split into these steps:

  • fab staging bootstrap (server setup and initial code deploy)
  • fab staging enable (enable the Apache/nginx config for this site)
  • fab staging reload_server (reload Apache/nginx config).

Those can of course be combined into a single command line fab staging bootstrap enable reload_server.

Once these steps are done, updating the deployment with new code is just fab staging deploy.

If I need to roll back an update, fab staging rollback. Nothing particularly magical in the rollback; it just rolls back the code to the last-deployed version and migrates the database to the previous state (this does require recording some metadata about the migration state of the DB post-deploy, I just do that in a text file).

Examples

I haven't used the Fabric scripts described in this answer for a few years, so they aren't maintained at all and I disclaim responsibility for their quality :-) But you can see them at https://bitbucket.org/carljm/django-project-template - in fabfile.py in the repo root, and in the deploy/ subdirectory.