Tag Archives: deployment

Deploying Django with Fabric

Fabric is a Python library and command-line tool for streamlining the use of SSH to deployment and sys-admin tasks. In the Django community Fabric has been picked up as the de facto standard for deploying apps, which is a place that it deserves. One thing I noticed though was that there wasn’t a lot of good examples for getting it to place nice with VirtualEnv.

Getting Started

The first thing you need is to make sure that you have Fabric installed.

pip install fabric

Once that’s done, open a file called fabfile.py and add the following imports:

from __future__ import with_statement
from fabric.api import *

Role Defs

Fabric has two functions that get used very frequently: local & run. The local() command will execute whatever you pass into in your local environment. The run() command will execute whatever you put into it in a remote environment defined in your roledefs.

A roledef defines a what a server is. For instance, if you have a nice fleshed out dev-staging-live type of environment:

evn.roledefs = {
	'dev' : ['dev.re-cycledair.com'],
	'staging' : ['staging.re-cycledair.com'],
	'live' : ['re-cycledair.com']
}

Once your roledefs are defined, you can run code on those specific servers by using the @roles decorator.

@roles("dev")
def ls_on_dev:
	run("ls") # Runs 'ls' on dev.re-cycledair.com
 
@roles("staging")
def ls_on_staging:
	run("ls") # Runs 'ls' on staging.re-cycledair.com

At this point, you want to run one of your new Fabric functions, from the directory where your fabfile is run:

fab ls_on_staging

Deployment

Now that you’ve got a handle on the trivial examples, lets make things a little more useful. We’re going to deploy to our ‘staging’ server.

@roles("staging")
def deploy_staging(tag=False):
	code_dir = '/path/to/remote/directory'
	with cd(code_dir):
		run("git fetch")
		if tag:
			run("git checkout %s" % tag)
		else:
			run("git checkout master")
			run("git pull origin master")
		with prefix('source /path/to/virtual/environment/bin/activate'):
			run("pip install -r requirements.txt")
			run("python manage.py syncdb")
			run("python manage.py migrate")
			run("python manage.py collectstatic --noinput")
			run("touch path/to/wsgi.py"

All this code is pretty self-explanatory. The @roles decorator has run execute in the context of “staging”. The run commands are just regular commands you would execute at the terminal if you were manually deploying. The only potential “gotch-ya” is the with prefix call. That basically says “execute the following statements in the context of my virtual environment”. To make everthing go:

fab deploy_staging

will deploy the head of the master branch and

fab deploy_staging:tag=1.0.0

will deploy the 1.0.0 tag.

Done

If all goes well, you can now deploy your app in seconds! If it takes longer then that, you might need to set up your ssh keys you so can login to your server without getting prompted for usernames and password.

Deploying Django 1.4 to Heroku

Note: It is assumed that your are keeping track of your changes using Git. If you aren’t, you’ll need to be to deploy to Heroku.

If there is one thing that scares beginners away from Django, its the idea of deployment. For a PHP programmer, deployment can be as simple as FTP’ing some files to a server, and boom, deployed. This isn’t to say that PHP deployment is simple. If you have to do it from scratch (get apache running, get your db installed, get PHP installed and configured, etc, etc) it can still be very complex, but many hosting companies take care of this for you. It’s almost like you never even have to think about it, which isn’t always the case for Django. That doesn’t mean its a bad thing, just…different.

So where do we start? Heroku is as good a place as any.

Heroku


Heroku is a cloud service for easy deployment of web applications. Initially it was Ruby only, but has been working hard to become a deployment service for many languages including Java, Python, and Node.js. Deploying to Heroku assumes a few things:

  1. You are familiar with Git and use it to track your code changes.
  2. You are at least passingly familiar with PostgreSQL, because that’s what you will being using. (You can use other storage devices, but PostgreSQL is the default and easiest to setup.
  3. You use PIP to manage your project’s requirements. If you aren’t doing this, you need to be. (seriously, it’s worth the effort)

Now that we have that out of the way, let’s get started. Before we can proceed further, you’ll need to get a Heroku account set up. For our testing purposes, a free account should be plenty.

  1. Go to Heroku.com and set up an account.
  2. Go to https://toolbelt.herokuapp.com and download the Herok toolbelt. Follow the directions on this page up to the “login” section.

That’s all for setting up Heroku for now. Next, we’re going to move on to configure Django so it can be deployed.

Django

Django gives you the flexibility to use almost any database under the sun. I generally develop using MySQL, but Heroku uses Postgres. As long as you haven’t been hand-tailoring queries, this shouldn’t provide any problem whatsoever. To make your project compatible with Heroku, you need to install the psycopg2 library.

pip install psycopg2

Now that you have the Postgres library installed, when your app is pushed to Heroku, Heroku will append some code to the end of your settings.py file that will point your install to the correct database.

Speaking of settings.py, you’ll also need to get your template and media paths set up correctly. To do that, add the following to the top of your settings.py and then set your paths to look like this:

import os.path
root = os.path.dirname(__file__).replace('\\','/')
 
MEDIA_ROOT = root + '/../media/'
STATIC_ROOT = root + '/../static/'
TEMPLATE_DIRS = (
    root +'/../templates',
)

We use this calculate root variable because it’s kind of a pain to know the path of your install on Heroku. This way it doesn’t matter where you deploy your app to, it should just work. Another thing to consider is static files. Heroku can be made to serve them, but having the same domain that is serving your site serve your static files is bad practice.

Wrapping it up

Now that Django is configured for Heroku deployment, all that’s left is to deploy it! The first thing we need to do is create a requirements file so that Heroku knows what packages to install. At the top level of your project, run the following:

pip freeze > requirements.txt

Great, now if you look at the generated file you can see what software Heroku is going to install for you. Next up, we’re going to create an app on Heroku (assuming you set up the Heroku tool belt correctly). In the top level directory of your project, run the following.

heroku create --stack cedar

This added your new Heroku app as a remote on your local Git repository. All you do to deploy is:

git push heroku master

Which should give you some output that looks like:

Counting objects: 10, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (10/10), 3.59 KiB, done.
Total 10 (delta 0), reused 0 (delta 0)

-----> Heroku receiving push
-----> Python/Django app detected
-----> Preparing Python interpreter (2.7.2)
-----> Creating Virtualenv version 1.7
       New python executable in .heroku/venv/bin/python2.7
       Also creating executable in .heroku/venv/bin/python
       Installing distribute........done.
       Installing pip...............done.
       Running virtualenv with interpreter /usr/local/bin/python2.7
-----> Activating virtualenv
-----> Installing dependencies using Pip version 1.0.2
       Downloading/unpacking Django==1.4 (from -r requirements.txt (line 1))
       ...
       Successfully installed Django psycopg2
       Cleaning up...
-----> Injecting Django settings...
       Injecting code into ./hellodjango/settings.py to read from DATABASE_URL
-----> Discovering process types
       Procfile declares types         -> (none)
       Default types for Python/Django -> web
-----> Compiled slug size is 9.3MB
-----> Launching... done, v4
       http://simple-spring-9999.herokuapp.com deployed to Heroku

To git@heroku.com:afternoon-sword-29.git
* [new branch]      master -> master

On the line immediately after “—–> Launching… done,…”, the url of your project is displayed. Before you go to it though, you need to run syncdb on Heroku. The Heroku toolbelt makes this pretty easy:

heroku run python manage.py syncdb

Conclusion

That’s all there is to it. If you get stuck, feel free to leave a comment. Heroku also has a great guide for getting up and running and explains some more features of the Heroku tool belt. That can be found here.