Senin, 19 Agustus 2013

Deploying Django Application into Server

Okay, this post will be very technical. I do make web applications using python and Django. So, I think it would be nice to share the experience. This guide will assume that you want to deploy the app into your own server, not some PAAS like Heroku or Google App Engine. Okay, first let's see the software stack. I this tutorial, I used Ubuntu Server. 
  1. Django (Web Framework)
  2. Gunicorn (WSGI Server)
  3. Nginx (Web Server)
  4. Supervisor (Process Manager)
  5. Fabric (Server Automation Tools)
  6. VirtualEnv (Manage Production Server)
  7. Git (Versioning Control System)
First Step - Setting up the Production Environment
The first step to deploy your app is to set up the server. You need all library you user at development at the server. In order to manage the library, we need virtualenv because every project need a different library and it could broke the system if there are more than one version of library. Virtualenv will create an environment for each app so that that will never stuck.
 sudo pip install virtualenv  

And then make a new environment by calling this command.
 virtualenv nebeng
 source nebeng/bin/activate  

After that, you can install all the dependency manually or using the pip requirements file. After you finish this step, you have created an isolated python environment for your own application.

Second Step - Configuring Fabric
Okay, the second step is get your code into the production server. In order to make your app is running, the server must get the code from your repository. For me, it is a tedious task to clone and pull the latest code on the server. You need to access the secure shell and run the command. Fabric is the solution to this problem.  Run this command to install the latest version of fabric
 pip install fabric  

Fabric let's you stay in the localhost, code the command, and let it do the work. To do this, install Fabric and put fabfile.py. Here is my fabfile.py. 
 from __future__ import with_statement  
 from fabric.api import *  
 env.hosts = ['Your server']  
 env.password = 'Your password'  
 env.directory = '/home/edwin/nebeng/app/nebeng'  
 env.activate = 'source /home/edwin/nebeng/bin/activate'  
 APPPATH = '/home/edwin/nebeng/app/nebeng'  
 def migrate():  
   with cd(env.directory):  
     with prefix(env.activate):  
       run('python manage.py migrate')  
       run("sudo supervisorctl restart nebeng")  
 def update():  
   with cd(APPPATH):  
     run("git pull")  
     run("sudo supervisorctl restart nebeng")  
 def deploy():  
   code_dir = '/home/suitmedia/edwin/nebeng/app'  
   with settings(warn_only=True):  
     if run("test -d %s" % code_dir).failed:  
       run("git clone git@bitbucket.edwin/nebeng.git %s" % code_dir)  
   with cd(code_dir):  
     run("git pull")  
     run("cd nebeng")  
     run("sudo supervisorctl restart nebeng")  

This is my full fabfile.py. I will explaining a little and explain the rest at this guide. the env.directory is your application root directory. the env.activate is the location of the virtualenv file that I will explain it later. The migrate() function is to do database migration. The run() function is fabric function to do command from ssh. If you look into the command, you will see the supervisorctl command. It is the process manager I talked above. I will explain it later. For now, go to your console, go to your project directory, and run "fab deploy". It will invoke the deploy() function. The function will clone  the app from the repository.

Third Step - Configuring the Application and Web Server

Okay, after cloning the code into the server, we need to set the app and web server. Gunicorn the application server is used for handling the request into a response object. The Nginx web server, will listen to your default HTTP port, 80 and sent the request to the appropriate local application port based on its namespace. okay first install gunicorn using this command
 pip install gunicorn  

and create a "gunicorn.py" file in your root app directory and put this code.
 import multiprocessing  
 bind = "0.0.0.0:10000"  
 workers = multiprocessing.cpu_count() * 2 + 1  

Simple, it is the Gunicorn configuration file. This is very minimum configuration for production. With this configuration, you can run the app, but if you want more advanced configuration, you can see it here. After that, running the Gunicorn with this command at the app root directory will run the server.
 gunicorn_django -c gunicorn.py  

After that, we need set up the Nginx. Install Nginx in every way you want. Then, open the nginx.conf. Mine's at /etc/nginx/nginx.conf and put this code.
  server {  
       listen 80;  
       server_name nebeng.test.com;  
       client_max_body_size 50m;  
       location /static/ {  
        alias /home/edwin/nebeng/app/nebeng/static/;  
        expires 30d;  
       }  
       location /media/ {  
        alias /home/edwin/nebeng/app/nebeng/media/;  
        expires 30d;  
       }  
       location / {  
        proxy_pass http://0.0.0.0:10000;  
        proxy_set_header Host $host;  
        proxy_buffers 8 16k;  
        proxy_buffer_size 32k;  
       }  
  }  

This configuration will let the nebeng.test.com into the port number 10000. The static and media files will be served by Nginx. After changing the Nginx configuration file, do not forget to reload the file using.
 sudo nginx -s reload  

Last Step - Configuring Supervisor the Process Manager

Okay, after setting the Nginx and Gunicorn, you need something to control the application server. You need ther server running in the background process and if the server reboot, your application server needs to start running immediately. Supervisor will do all these things for you. Install the Supervisor by running this command.
 sudo pip install supervisor  

And then, create the configuration file at /etc/supervisor/conf.d/. You can name the file anything. For example, nebeng.conf. Here are the codes.
 [program:nebengers]  
 command = /home/edwin/nebeng/app/nebeng/script.sh  
 directory = /home/edwin/nebeng/app/nebeng  
 user = suitmedia  
 autostart = true  
 autorestart = true  
 stdout_logfile = /home/edwin/nebeng/app/nebeng/log/s_out.log  
 stderr_logfile = /home/edwin/nebeng/app/nebeng/log/s_err.log  

Then, we need a script file to run the Gunicorn. Create a "script.sh" file in the root directory of your app and put this code.
 #!/bin/bash  
 set -e  
 LOGFILE=/home/edwin/nebeng/app/nebeng/log/nebeng.log  
 LOGDIR=$(dirname $LOGFILE)  
 cd /home/edwin/nebeng/app/nebeng/  
 source ../../bin/activate  
 test -d $LOGDIR || mkdir -p $LOGDIR  
 exec gunicorn_django -c gunicorn.py --log-file=$LOGFILE  

The script is quite simple. It would create a log directory is it was not created. Then, run the Gunicorn. Do not forget to make the script executable using chmod +x script.sh. To invoke the supervisor, you need to load the configuration files first. Run
 sudo supervisorctl reload  

Then, to start the Gunicorn server, run
 sudo supervisorctl restart nebeng

It is done! Now you can use all the fabric command or you can write a custom command for yourself. You can check into nebeng.test.com to check whether the configuration is good or not. Check the log files, or maybe playing with configuration files. I will post the troubleshoot page later. Thanks. :D

Tidak ada komentar:

Posting Komentar