Wednesday, February 23, 2022

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

Issue

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.

Solution

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



Answered By - Carl Meyer
Answer Checked By - Mary Flores (WPSolving Volunteer)