Deploying Django with Fabric

This is a followup to my previous posting Deploying Django with Gunicorn and Supervisor.

I have been using Fabric for five or even more years. Fabric is a very flexible and powerful tool for automating deployment routines.

My fabfile.py is composed for Git, but you can easily change it to Mercurial or even Subversion.

It's much easier to deploy when you use deploy keys, but it is still possible to use HTTP. I personally hate entering passwords, so I would recommend using deploy keys and SSH.

I'm assuming that you already have installed nginx and configured your database instance.

You will only need two commands to bootstrap and deploy:

$ fab staging bootstrap  # Clones your project from the repository and perform the initial setup
$ fab staging deploy  # Pushes your latest changes

Obviously, replacing staging with production will change your environment.

Here's my typical fabfile.py:

import os  
from contextlib import contextmanager  
from fabric.api import cd, env, prefix, run, sudo, task


PROJECT_NAME = 'YOUR PROJECT NAME'  
PROJECT_ROOT = '/var/www/%s' % PROJECT_NAME  
VENV_DIR = os.path.join(PROJECT_ROOT, '.venv')  
REPO = 'git@bitbucket.org:monmar/%s.git' % PROJECT_NAME

env.hosts = []

@task
def staging():  
    env.hosts = ['user@staging-server']
    env.environment = 'staging'


@task
def production():  
    env.hosts = ['user@production-server']
    env.environment = 'production'

# DO NOT EDIT ANYTHING BELOW THIS LINE!

@contextmanager
def source_virtualenv():  
    with prefix('source ' + os.path.join(VENV_DIR, 'bin/activate')):
        yield


def clean():  
    """Cleans Python bytecode"""
    sudo('find . -name \'*.py?\' -exec rm -rf {} \;')


def chown():  
    """Sets proper permissions"""
    sudo('chown -R www-data:www-data %s' % PROJECT_ROOT)


def restart():  
    sudo('supervisorctl reread')
    sudo('supervisorctl reload')
    sudo('service memcached restart')
    sudo('service nginx restart')


@task
def deploy():  
    """
    Deploys the latest tag to the production server
    """
    sudo('chown -R %s:%s %s' % (env.user, env.user, PROJECT_ROOT))

    with cd(PROJECT_ROOT):
        run('git pull origin master')
        with source_virtualenv():
            with prefix('export DJANGO_SETTINGS_MODULE={}.settings.{}'.format(PROJECT_NAME, env.environment)):
                run('source .env/bin/activate && pip install -r requirements/production.txt')
                run('./manage.py migrate')
                run('./manage.py collectstatic --noinput')

    chown()
    restart()


@task
def bootstrap():  
    """Bootstrap the latest code at the app servers"""
    sudo(
        'apt-get update && apt-get install git supervisor nginx memcached libjpeg8-dev postgresql libpq-dev python-dev python-pip python-virtualenv libfreetype6-dev libncurses5-dev'
    )

    sudo('mkdir -p {}'.format(PROJECT_ROOT))
    sudo('chown -R {}:{} {}'.format(env.user, env.user, PROJECT_ROOT))
    run('git clone {} {}'.format(REPO, PROJECT_ROOT))

    with cd(PROJECT_ROOT):
        run('git pull origin master')
        run('virtualenv .env')
        with source_virtualenv():
            with prefix('export DJANGO_SETTINGS_MODULE={}.settings.{}'.format(PROJECT_NAME, env.environment)):
                run('source .env/bin/activate && pip install -r requirements/production.txt')
                run('./manage.py migrate')
                run('./manage.py collectstatic --noinput')

    chown()

    # Deploy web and app server configs
    for service in ('celerybeat', 'celerycam', 'celeryd', PROJECT_NAME):
        sudo('ln -s {project_root}/deploy/{environment}/{service}.conf /etc/supervisor/conf.d/{service}.conf'.format(
            project_root=PROJECT_ROOT, environment=env.environment, service=service))
    sudo('ln -s {project_root}/deploy/{environment}/nginx.conf /etc/nginx/sites-enabled/{project_name}.conf'.format(
        project_root=PROJECT_ROOT, environment=env.environment, project_name=PROJECT_NAME))

    restart()

Feel free to ask any questions.

Michael Samoylov

Python, JavaScript and Swift Expert with 12+ years of experience.

Vilnius, Lithuania https://monmar.tech

Subscribe to Michael Samoylov

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!