Cookies disclaimer

I agree Our site saves small pieces of text information (cookies) on your device in order to deliver better content and for statistical purposes. You can disable the usage of cookies by changing the settings of your browser. By browsing our website without changing the browser settings you grant us permission to store that information on your device.

Deployment of a Django application docker





Don't forget if you need help putting your application in production, or you want it to do for you ? Open a ticket !

In this tutorial we will see how to package our Django application with Gunicorn in an image docker.

The main advantage of using docker instead of a VM is that we won't have to install all the dependencies "by hand". We can also deploy the number of instances as we want without having to reinstall everything, and if we do an update it should just update the version of the image.

First the prerequisites:

- a docker on the docker hub ( https://hub.docker.com/register/ )

 - I assume that you already have a django application, so this tutorial does not speak in order to develop with django

- docker installed on the working machine ( I use a machine CentOS 7 ) and for info the commands on CentOS are:

yum install -y epel-release &&  yum install -y python-pip docker && service docker start

        

1) I'm going to create a django application basic for this tutorial: 

I'm going to call my project "tutorial" make sure to replace that name with the name of your project. To create it :

django-admin startproject tutorial

 

2) Check his file requierments.txt:

Like any good fan of django I create my file requierements.txt that will contain the dependencies of my application, mine is pretty simple :)

$ cat requirements.txt 
django
gunicorn

The structure of my project looks like this now:

.
├── tutorial
│   ├── tutorial
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   └── manage.py
└── requirements.txt

Hey it beats not I have the admin enabled in my project, nothing more !

3) We create the file that will start gunicorn:

I call it start.sh:

#!/bin/bash

# Start Gunicorn processes
echo Demarrage de Gunicorn ...
exec gunicorn tutorial.wsgi:application \
    --bind 0.0.0.0:8000 \
    --workers 3

Small precision about the number of workers, they depend on the number of cpu core available and on the calculations according to the formula :

(2 x nombre_de_core) + 1

Attention to change the name "tutorial" by the name of your project. I also make the file executable :

chmod +x start.sh

And I run it for to be sure this work:

[hebus@hebus tutorial]# ./start.sh 
Starting Gunicorn.
[2016-10-07 09:46:42 +0000] [2984] [INFO] Starting gunicorn 19.6.0
[2016-10-07 09:46:42 +0000] [2984] [INFO] Listening at: http://0.0.0.0:8000 (2984)
[2016-10-07 09:46:42 +0000] [2984] [INFO] Using worker: sync
[2016-10-07 09:46:42 +0000] [2989] [INFO] Booting worker with pid: 2989
[2016-10-07 09:46:42 +0000] [2990] [INFO] Booting worker with pid: 2990
[2016-10-07 09:46:42 +0000] [2991] [INFO] Booting worker with pid: 2991

 

Everything seems to be ok, my application is accessible via the local IP address and port 8000.

 

4) Now, we are going to create our image on Docker:

Before you create an image docker it is necessary to write a file Dockerfile in order to tell him what to put in my image. We will call this file "Dockerfile" that we will create in the root of our project.

#Dockerfile

FROM python:2-onbuild

Here nothing special just that it puts python in our Dockerfile, because django is python, and this image will automatically copy our project in the directory /usr/src/app in the image to Docker and run for us, "pip install-r requierements.txt" pure install our dependencies.

Now we will add our script ./start.sh in our image to start gunicorn:

COPY start.sh /start.sh

And as we want to run our app on port 8000 specified in our Dockerfile to expose a port:

EXPOSE 8000

Here everything is in place, except that our script was not executed, to do this it gives the instruction in the Dockerfile:

CMD ["/start.sh"]

It seems long, but in fact it is fast once one has understood it, and if you look there is almost less order to prepare our machine for dev. Now that our Dockerfile is complete, it looks like this :

# Dockerfile

FROM python:2.7-onbuild

COPY start.sh /start.sh

EXPOSE 8000

CMD ["/start.sh"]

Well this is all well and good, but apart from a text file you tell me there was nothing else, not move the image that is almost.

Attention checks that it is in the root of our django project and launch our command to build our container :

docker build -t hebus/django-tutorial .

and it gives after the download of the dependency by a dockworker in our image "python:2-onbuild" :

Sending build context to Docker daemon 20.48 kB
Step 1 : FROM python:2.7-onbuild
# Executing 3 build triggers...
Step 1 : COPY requirements.txt /usr/src/app/
 ---> Using cache
Step 1 : RUN pip install --no-cache-dir -r requirements.txt
 ---> Running in 5ab77f8a3286
Collecting django==1.10 (from -r requirements.txt (line 1))
  Downloading Django-1.10-py2.py3-none-any.whl (6.8MB)
Collecting gunicorn==19.6.0 (from -r requirements.txt (line 2))
  Downloading gunicorn-19.6.0-py2.py3-none-any.whl (114kB)
Installing collected packages: django, gunicorn
Successfully installed django-1.10 gunicorn-19.6.0
Step 1 : COPY . /usr/src/app
 ---> a0ec5736a5f1
Removing intermediate container 5ab77f8a3286
Removing intermediate container 59f02577e9f4
Step 2 : COPY start.sh /start.sh
 ---> acfd9b5d2992
Removing intermediate container d89002950ae4
Step 3 : EXPOSE 8000
 ---> Running in 6c3fe86134b6
 ---> 6914909a31d6
Removing intermediate container 6c3fe86134b6
Step 4 : CMD /start.sh
 ---> Running in ce396ed25ff6
 ---> e86a6ec23b71
Removing intermediate container ce396ed25ff6
Successfully built e86a6ec23b71

Here is our image loader is ready, we will now publish it on the Docker hub to be able to pick it up on our production server :

we ensure first and foremost be connected to the dockerhub by

docker login

and then we publish:

docker push hebus/django-tutorial 

and what that gives as a result:

The push refers to a repository [docker.io/hebus/django-tutorial]
bc9f1af55455: Pushed 
f3bef6e0fbd2: Pushed 
d81abf869dbb: Pushed 
f01b3d92255a: Pushed 
9d56c7adb2fa: Mounted from library/python 
24ab1022ada9: Mounted from library/python 
6a269e827c98: Mounted from library/python 
2c2153fbd032: Mounted from library/python 
d9a069c1d0fc: Mounted from library/python 
a5eb0fc1decb: Mounted from library/python 
b2ac5371e0f2: Mounted from library/python 
142a601d9793: Mounted from library/python 
latest: digest: sha256:0a75e281f6ea82f8554a149942a5b519b782c23047be89e465e298e0b49e38d7 size: 2818

Here is our image is avaialble for the production !

 

5) Deployment in the cloud:

I would use the cloud hebus for the deployment of my image with an instance of "tiny" ( to adapt according to your needs) without storage since I don't have a database ( except sqlite, but I cannot not be used because it is a tutorial ), in part 2 of this article we will see how to deploy PostgreSQL with and without clusteur replication.

my deployment file is the following:

{
      "name": "django", 
      "spec": {
            "template": {
                  "spec": {
                        "containers": [
                              {
                                    "name": "django", 
                                    "image": "hebus/django-tutorial", 
                                    "volumeMounts": [], 
                                    "env": [], 
                                    "imagePullPolicy": "Always", 
                                    "ports": [
                                          {
                                                "containerPort": 8000, 
                                                "name": "django"
                                          }
                                    ], 
                                    "resources": {
                                          "limits": {
                                                "cpu": "0.9", 
                                                "memory": "0.9Gi"
                                          }
                                    }
                              }
                        ], 
                        "volumes": []
                  }
            }, 
            "replicas": 1
      }
}

 

Be sure to provide the name of your image, for me it is "hebus/django-tutorial".

And the last step, the creation of my LoadBalancer to access my App :

 

And now I check that my site is well accessible in the cloud by putting the address entered is tutorial-django.apps.hebus.io

 

 

And here you have deployed your application, simply in the cloud Hebus using docker and kubernetes ( without even knowing it :) ).

In a next article, we will see how to add persistent storage to our application and connect to a PostgreSQL database. Also you will discover the functionality of replicas, so stay tuned !