Ansible Playbook for a Django Stack (Nginx, Gunicorn, PostgreSQL, Memcached, Virtualenv, Supervisor)
I decided to create a separate GitHub project for the Ansible playbook I'm currently using to fully provision a production server for my open-source app, GlucoseTracker, so it can be reused by people who are using the same stack.
You can download the playbook here: https://github.com/jcalazan/ansible-django-stack
The playbook can fully provision an Ubuntu 12.04 LTS server (will test 14.04 soon) from the base image with the following applications, which are quite popular in the Django community:
- Nginx
- Gunicorn
- PostgreSQL
- Memcached
- Virtualenv
- Supervisor
I used this awesome guide to set up my server initially (which took like half a day) before automating the entire process with Ansible. If I need to move to a new server or cloud provider, I can pretty much rebuild a fully-configured server in about 5 minutes with one command. Pretty neat.
Note: I've also ran this playbook successfully on Amazon EC2, Rackspace, and Digital Ocean virtual private servers.
TL;DR
For those who are in a hurry, simply install Ansible, Vagrant, and VirtualBox (if you don't have them already), clone the project from GitHub, and type this in from the project directory:
vagrant up
Wait a few minutes for Ansible to do its magic. Visit http://192.168.33.15 when finished. Congrats, you just deployed a fully configured Django app!
The Juicy Details
Below are some things you should know before using this playbook for your projects.
Project Structure
I have my Django project structure set up this way:
glucose-tracker\ (project directory) --> glucosetracker\ (application directory) ---> settings\ ----> base.py ----> local.py ----> dev.py --> requirements.txt file, scripts, other files and directories I don't consider part of the application
If you have the same project structure that I have, then all you really have to change is the env_vars/base file to get started, where you can set the Git repo location, project name, and the application name which are used throughout the playbook.
If you don't have the same project structure, you will need to change the group_vars/webserversfile as well (and possibly the environment specific vars file in env_vars/ if you don't split up your settings file), where you can set the path settings to match your project structure.
Environment Variables
I like to separate my environment-specific settings from the main code repo for security reasons and for easier management. For example, in my Django settings file, I set the EMAIL_HOST_PASSWORD setting to something like:
EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD']
This way, I won't have to leave the password in the code and if I need to change the email password I can do so quickly by changing the environment variable setting on the server instead of modifying the code and re-deploying it.
The way I have this setup is I created a postactivate script (see roles/web/templates/)that creates the environment variables. This gets ran after activating virtualenv so those settings are applied only to that virtualenv.
Now, because I like having all my configurations in my Ansible playbook repo, I keep these values in a vars file and encrypt them with Ansible Vault (see my previous post about this for more details).
Applying Roles
The playbooks in the repo apply all the roles. If you only want certain roles applied to your server, simply remove the ones you don't need from the roles: section.
For example, if you don't use memcached, your roles: section will look something like this.
roles: - base - db - web
Django Management Commands
In env_vars/, you will see the following settings in the environment-specific vars files:
run_django_syncdb: yes run_django_south_migration: yes run_django_collectstatic: yes
If you don't want to run some of these commands, simply set the value to no.
OpenSSL 'Heartbleed' Patch
Don't worry, the playbook already takes care of this for you. The first task in the playbook is to do an apt-get update and ensure that openssl and libssl are the latest version.
I think that pretty much covers most of the questions you might have if you decide to use this Ansible playbook for your Django projects. I might add a few more roles here in the next few weeks, such as Celery, RabbitMQ, and Solr, as we use them at work and we're currently in the process of automating our infrastructure.
If you have any questions or suggestions, please feel free to leave a comment below.
Some Useful Links: