Deploy Python Application with Gunicorn and Supervisor on Ubuntu

Suppose we have to deploy 3 python applications on a Ubuntu server. The applications and their python versions are as follows:

1. Analytics application (analytics.example.com): python2
2. Android API (android.example.com): python3.5
3. Auth API (auth.example.com): python3.6

What will be the solution? How can we run 3 different python applications on 3 different python versions on same machine?

Here is a simple solution to achieve this goal. I'm assuming you know about python virtual environments and wsgi. If not Google will help you on this. The following steps should work with most of Ubuntu versions.

Here are our plans to achieve our goal:

1. We'll create 3 separate virtual environment to run these applications
2. We'll use gunicorn inside these virtual environments to run these applications on 3 different ports e.g. 8001, 8002, 8003
3. We'll use supervisor to start, stop and monitor these 3 applications running on gunicorn

Lets assume we've the codes for these applications in the following directories.

1. /var/www/apps/analytics-app
2. /var/www/apps/android-api-app
3. /var/www/apps/auth-api-app

Lets start.

Step 1: Create virtual environments

Creating a python virtual environment is simple. We need to navigate to the application directory and run the virtual environment command there along with name of the virtual environment and python version.
For example to create virtual environment for the android-api-app, we need to follow these steps:

1. cd /var/www/apps/android-api-app
2. virtualenv -p python3 venv

This will create a venv directory which is our python3 virtual environment. We can activate the environment with

$ source venv/bin/activate 

And deactivate with command

(venv) $ deactivate

Please note that you may face some difficulties to create virtual environment for a specific python versions and for specific Ubuntu versions. Therefore you may need to give some extra efforts to resolve these issues. For now I'm assuming that you've successfully created 3 virtual environments for each of your applications inside venv directory of your application directory.

You now need to install your required python packages e.g. Django, Flask etc in each of these virtual environments. Usually the following command will do the job:

(venv) $ pip install -r requirements.txt

Step 2: Use Gunicorn as server

Your application codes are ready, virtual environments have been created, required packages are installed inside these virtual environments. Now you need to install gunicorn inside your virtual environments. This is actually very easy with pip. Here is example command for each of the above apps:

$ cd /var/www/apps
$ source analytics-app/venv/activate
(venv) $ pip install gunicorn
(venv) $ deactivate
$ source android-api-app/venv/activate
(venv) $ pip install gunicorn
(venv) $ deactivate
$ source auth-api-app/venv/activate
(venv) $ pip install gunicorn
(venv) $ deactivate

Once gunicorn is installed, make sure you can run your python application using gunicorn from your virtual environment. Gunicorn will run your application using wsgi. Following command from application root directory will do this:

(venv) $ gunicorn wsgi:app

The above command may vary depending on your framework and how you write the wsgi application. You should also be able to run the gunicorn application direct from your venv binary. Here is the command that'll do so. It also shows how you can confgure the host ip, port and number of gunicorn workers.

$ venv/bin/gunicorn --bind 0.0.0.0:8000 -w 4 wsgi:app

If you are able to run gunicorn, Congratulations! You've completed a big step!

Step 3: Mange gunicorn with Supervisor

We can run 3 gunicorn in daemon mode. It'll solve our purpose. But managing and running the services will be a bit complicated. For example, in order to check whether a particular app is running or not we've to see the process list. Also to stop a app, we've to kill the process. If any of our gunicorn process dies, we've to restart them again manually.

It would be really nice if we have something which will continuously monitor all of our gunicorn processes, show us their current statuses, allow us to control them from a single place. Supervisor is something that'll help us on this.

We need to install supervisor first. We can install from pip or we can choose an ubuntu distribution. Here I'm going to use the ubuntu distribution.

Install the supervisor with the following command:

$ sudo apt-get install supervisor

This will actually install two softwares - supervisord and supervisorctl. supervisord is the daemon process that'll monitor and run the gunicorn processes. supervisorctl is the controller interface to interact with supervisord e.g. start, stop, restart.

We've to write a configuration file for supervisord. The file will contain which applications we want to run and how to run them.

For our 3 applications, our configuration file may look like the following:

[supervisord]
logfile = /home/nayan/supervisor/log/supervisord.log

[program:analytics-app]
environment=ANALYTICS_APP_CONFIG=/home/nayan/app_config/analytics_app.cfg
directory=/var/www/apps/analytics-app
command=/var/www/apps/analytics-app/venv/bin/gunicorn --bind 0.0.0.0:8001 wsgi:app

[program:android-api-app]
directory=/var/www/apps/android-api-app
command=/var/www/apps/android-api-app/venv/bin/gunicorn --bind 0.0.0.0:8002 wsgi:app

[program:auth-api-app]
directory=/var/www/apps/auth-api-app
command=/var/www/apps/auth-api-app/venv/bin/gunicorn --bind 0.0.0.0:8003 wsgi:app

[unix_http_server]
file = /home/nayan/supervisor/supervisor.sock
chmod = 0777
username = nayan
password = 123456

[supervisorctl]
serverurl = unix:///home/nayan/supervisor/supervisor.sock
username = nayan
password = 123456

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface


Lets see what we've defined in the above file.

The first section is [supervisord]. Here we've provided the path to our log file. The process start/stop logs will go there. This path show exist and should be writable for user.

In the program sections we've declared our 3 apps and provided the commands to run them. The environment variable also shows how you can set environment variables before running the applications. This is useful if you (and you should) put the sensitive configuration variables e.g. db configurations to external file.

The unix_http_server and other sections are used for controlling supervisord. You've to make sure that the serverurl path actually exists and is writable.

The detailed explanation about this configuration files are beyond the scope of this document. You can learn about more details in the supervisor documentation here http://supervisord.org

Our supervisor configuration file is ready. Put it in your preferred location e.g. /home/nayan/supervisor/supervisor.conf

Now we'll start the supervisord with our configuration file. Following command will do the job:

$ supervisord -c /home/nayan/supervisor/supervisor.conf

This will start the supervisord which will monitor and manage the 3 gunicorn applications. To see actually what is happening, run the following command:

$ supervisorctl -c /home/nayan/supervisor/supervisor.conf

This will connect to supervisord and open a shell. Running status command from this shell will show you list of applications. Example:

$ supervisor> status
$ analytics-app                    RUNNING   pid 19596, uptime 1:15:20
$ android-api-app                  RUNNING   pid 19598, uptime 1:15:20
$ auth-api-app                     RUNNING   pid 19601, uptime 1:15:20
$ supervisor> 

You can find other supervisorctl commands by typing help in this shell.

If you've successfully completed the above steps, you are done. Now check your applications. You should see them running on 8001, 8002 and 8003 ports.


Comments

Popular posts from this blog

Run tasks in background in Spring

Conditional field inclusion in Jackson and Spring Boot

How to configure Wildfly 10 to use MySQL