I’ve been making quite a bit of improvements and changes to my Django app, GlucoseTracker, lately that the small amount of time I spent creating a deployment script using Fabric had already paid off.
Fabric is basically a library written in Python that lets you run commands on remote servers (works locally as well) via SSH. It’s very easy to use and can save you a lot of time. It eliminates the need to connect to a remote server manually, and if you have a lot of servers to update, then the time savings really add up.
Since I only have one server for my production environment, my setup and deployment process are very simple. I use GitHub to store my code, a virtualenv environment where my code is deployed to, Gunicorn for the WSGI server managed by Supervisor, PostgreSQL for the database, and Nginx for the web server.
My deployment process goes something like this:
- Run unit tests.
- Pull latest code from the master branch hosted on GitHub.
- Activate virtualenv.
- Run pip install against the requirements file (in case a new library was added or updated).
- Run South migrations for all apps (in case the there were changes in the database/table schemas).
- Restart Gunicorn with Supervisor.
Here’s what my fabric.py file looks like:
from fabric.api import local, env, cd, sudo
env.hosts = ['www.glucosetracker.net']
# The user account that owns the application files and folders.
owner = 'glucosetracker'
app_name = 'glucosetracker'
app_directory = '/webapps/glucosetracker/glucose-tracker'
settings_file = 'settings.production'
local('coverage run manage.py test -v 2 --settings=settings.test')
Deploy the app to the remote host.
1. Change to the app's directory.
2. Pull changes from master branch in git.
3. Activate virtualenv.
4. Run pip install using the requirements.txt file.
5. Run South migrations.
6. Restart gunicorn WSGI server using supervisor.
sudo('git pull', user=owner)
venv_command = 'source ../bin/activate'
pip_command = 'pip install -r requirements.txt'
sudo('%s && %s' % (venv_command, pip_command), user=owner)
south_command = 'python glucosetracker/manage.py migrate --all ' \
'--settings=%s' % settings_file
sudo('%s && %s' % (venv_command, south_command), user=owner)
sudo('supervisorctl restart glucosetracker')
To run this script, you first need to install the Fabric library:
pip install fabric
Then call the run_tests method by typing:
Make sure to run the fab command in the directory where the fabric.py file is located.
For the run_tests() method, you’ll notice that I use the function local(). Since I don’t have a staging environment I just run my tests locally. I then deploy directly to my production server.
Also note that the SSH session is not persistent, which is why you can see in my script that I combine the virtualenv activation command with the commands dependent on it being active. I also run my app using a user account named glucosetracker which has limited access to the server to minimize damage in case someone figures out a way to run malicious code through my app.
That’s pretty much it. This is just a very simple example and you can do a lot more with it. It takes very little time to get started, so even for small projects it’s definitely worth checking out. It’s really nice to be able to make even just tiny changes to your app and have it deployed in seconds by running one simple command.