Deploying Django applications with Capistrano
Yesterday, I cooked up a deploy.rb so that Capistrano can deploy a Django application. While there is a Python app called http://docs.fabfile.org/0.9.0/ from what I could tell, it was very general to running commands on multiple servers, and not really specific to checking out a web framework and deploying it to one or more servers.
First, my deploy.rb, and then my notes about how I used it. I have changed only one or two things from my real code. My application is called "clientportal" and the host running it is called "clientportal.isp.example.net". On the server, it runs as a user called "clientportal".
This code does not yet invoke the Django database migrations, which it ought to, and I'll do another blog post once I figure out that part.
set :application, "clientportal"
set :me, "#{ENV['LOGNAME']}"
set :repository, "git+ssh://#{me}@code.credil.org/git/path/to/repo/clientportal"
set :scm, :git
set :user, :clientportal
set :ssh_options, { :forward_agent => true }
set :use_sudo, false
set :git_enable_submodules, true
set :deploy_to, "/home/#{user}/#{application}"
role :web, "clientportal.isp.example.net" # Your HTTP server, Apache/etc
role :app, "clientportal.isp.example.net"
# This is where Rails migrations will run
role :db, "clientdb.isp.example.net", :primary => true
namespace :deploy do
task :start do ; end
task :stop do ; end
# this overrides a rails specific thing.
task :finalize_update do ; end
task :migrate do ; end
task :restart, :roles => :app, :except => { :no_release => true } do
# something to restart django.
run "sudo /usr/sbin/apache2ctl graceful"
end
task :update_database_yml, :roles => [:app,:web] do
db_config = "/home/#{user}/settings.py"
run "cp #{db_config} #{release_path}/settings.py"
run "ln -f -s #{release_path} /home/clientportal/clientportal/clientportal"
puts "Ran update database settings"
end
end
after "deploy:update_code", "deploy:update_database_yml"
Some details. First, I put my settings.py file into my /home/clientportal directory. I do not check this file into my repo, because it always specific to the installation (it's different on your laptop than on the devel server or the production server). Also see my:
Like http://blog.perplexedlabs.com/2010/02/08/deployment-using-capistrano-and-webistrano-via-rails-and-phusion-passenger/ I had to adjust my django.wsgi file as well. I wound up with:
import site
site.addsitedir('/usr/local/pythonenv/CLIENTPORTAL/lib/python2.5/site-packages')
import os, sys
sys.path.append('/home/clientportal/clientportal')
sys.path.append('/home/clientportal/clientportal/current')
os.environ['DJANGO_SETTINGS_MODULE'] = 'clientportal.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
The important changes were to the path that was added. It used to add $HOME/clientportal and $HOME to the path, but now it is one directory deeper, and you will notice above in the update_database_yml task that it creates a symlink in $HOME/clientportal with the name "clientportal" that is essentially the same as "current".
This is necessary because the settings are loaded as "clientportal.settings", and python basically turns the . into a / when looking for the file. I could have just changed the name of the settings file, but we had other modules that were loaded using the clientportal. namespace.
Note that the server already had it's apache configured to do what was needed. I would normally package these config files up into a .deb file, but I haven't done that yet for this project, it being my first django project.
I am not sure if I actually have to restart apache. I added that for good luck, and and I added:
clientportal ALL=NOPASSWD: /usr/sbin/apache2ctl gracefulto sudoers.
My apache config looks like:
<VirtualHost *:443>
ServerAdmin webmaster@localhost
ServerName clientportal.isp.example.net
ServerAlias portal1.isp.example.net
ServerAlias portal.example.net
DocumentRoot /home/clientportal/clientportal/current
<Directory "/home/clientportal/clientportal/current">
Options Indexes FollowSymLinks
Options -MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ErrorLog /var/log/apache2/error.log
Alias /media/ /home/clientportal/clientportal/current/media/
WSGIScriptAlias / /home/clientportal/clientportal/current/wsgi/django.wsgi
<Directory /home/clientportal/clientportal/current/apache/>
Order allow,deny
Allow from all
</Directory>
...
Some other links I found, but I didn't use much: http://groups.google.com/group/django-developers/browse_thread/thread/f34e59275e04f9c5?pli=1 http://gnuvince.wordpress.com/2008/01/10/deploying-django/
Syndicated 2011-03-02 12:06:00 (Updated 2011-03-17 18:14:24) from Michael's musings
