J'accepte Notre site sauvegarde des traceurs textes (cookies) sur votre appareil afin de vous garantir de meilleurs contenus et à des fins de collectes statistiques.Vous pouvez désactiver l'usage des cookies en changeant les paramètres de votre navigateur. En poursuivant votre navigation sur notre site sans changer vos paramètres de navigateur vous nous accordez la permission de conserver des informations sur votre appareil.
N'oubliez pas si vous avez besoin d'aide pour mettre votre application en production ou vous voulez qu'on le fasse pour vous ? Ouvrez un ticket !
Dans ce tutoriel nous allons voir comment packager notre application Django avec Gunicorn dans une image docker.
Le principal avantage d'utiliser docker plutôt qu'une VM est que nous ne devrons pas installer toutes les dépendances "à la main". Nous pourrons également déployer le nombre d'instances que nous voulons sans devoir tout réinstaller, et si nous faisons une mise à jour il faut simplement mettre à jour la version de l'image.
Tout d'abord les prérequis:
- un compte docker sur le docker hub ( https://hub.docker.com/register/ )
- je suppose que vous avez déjà une application django, donc ce tutoriel ne parlera pas de commander développer avec django
- docker installé sur la machine de travail ( j'utilise une machine CentOS 7 ) et pour info les commandes sur CentOS sont:
yum install -y epel-release && yum install -y python-pip docker && service docker start
Je vais appeler mon projet "tutorial" veillez à remplacer ce nom par celui de votre projet. Pour le créer :
django-admin startproject tutorial
Comme tout bon fan de django je crée mon fichier requierements.txt qui contiendra les dépendances de mon application, le mien est assez simple :)
$ cat requirements.txt
django
gunicorn
La structure de mon projet ressemble à cela maintenant:
.
├── tutorial
│ ├── tutorial
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ └── manage.py
└── requirements.txt
Bon on s'emballe pas j'ai que l'admin d'activé dans mon projet rien de plus !
Je l'appelle start.sh:
#!/bin/bash
# Start Gunicorn processes
echo Demarrage de Gunicorn ...
exec gunicorn tutorial.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 3
Petite précision concernant le nombre de workers, ils dépendent du nombre de cpu core disponible et on les calculs suivant la formule :
(2 x nombre_de_core) + 1
Attention de changer le nom "tutorial' par le nom de votre projet. Je rends également le fichier exécutable :
chmod +x start.sh
Et je le lance pour afin d'être sur que cela fonctionne:
[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
Tout semble ok, mon application est accessible via l'adresse IP locale et sur le port 8000.
Avant de créer une image docker il faut écrire un fichier Dockerfile afin de lui dire quoi mettre dans mon image. Nous appellerons ce fichier "Dockerfile" que nous allons créer dans le root de notre projet.
#Dockerfile
FROM python:2-onbuild
Ici rien de spécial juste qu'on met python dans notre Dockerfile car django c'est du python, et cette image va automatiquement copier notre projet dans le répertoire /usr/src/app de notre image Docker et exécuter pour nous "pip install -r requierements.txt" pur installer nos dépendances.
Maintenant nous allons ajouter notre script ./start.sh à notre image pour démarrer gunicorn:
COPY start.sh /start.sh
Et comme on veut faire tourner notre app sur le port 8000 on le précise dans notre Dockerfile afin d'exposer le port:
EXPOSE 8000
Voilà tout est en place, sauf que notre script on ne l'a pas exécuté, pour ce faire on en donne l'instruction dans la Dockerfile:
CMD ["/start.sh"]
Cela parait long, mais en fait c'est rapide une fois qu'on a compris, et si on regarde il y a presque moins de commande que pour préparer notre machine de dev. Maintenant que notre Dockerfile est complétée, elle ressemble à ceci :
# Dockerfile
FROM python:2.7-onbuild
COPY start.sh /start.sh
EXPOSE 8000
CMD ["/start.sh"]
Bon c'est bien beau mais mise à part un fichier texte me direz vous on a rien d'autre, bougez pas l'image est presque la.
Attention on vérifie qu'on est bien dans le root de notre projet django et on lance notre commande pour construire notre container :
docker build -t hebus/django-tutorial .
et ça donne après le téléchargement de la dépendance par docker de notre 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
Voila notre image docker est prête, nous allons maintenant la publier sur le Docker hub afin de pouvoir la récupérer sur notre serveur de production :
on s'assure d'abord d'être connecté au dockerhub en faisant
docker login
et ensuite on publie:
docker push hebus/django-tutorial
et ce qui donne comme résultat:
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
Voila notre image est disponnible pour la production !
J'utiliserais le cloud hebus pour le déploiement de mon image avec une instance "tiny" ( à adapter selon vos besoins) sans stockage étant donné que je n’ai pas de base de données ( mise à part une sqlite mais qui ne me sert pas étant donné que c'est un tutorial ), dans la partie 2 de cet article nous verrons comment déployer PostgreSQL avec et sans clusteur de réplication.
mon fichier de déploiement est le suivant:
{
"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
}
}
Veiller à bien renseigner le nom de votre image pour moi c'est "hebus/django-tutorial".
Et la dernière étape, la création de mon LoadBalancer pour accéder à mon App :
Et maintenant je vérifie que mon site est bien accessible dans le cloud en mettant l'adresse renseignée soit tutorial-django.apps.hebus.io
Et voilà vous avez déployé votre application simplement dans le cloud Hebus à l'aide de docker et kubernetes ( sans le savoir :) ).
Dans un prochain article, nous verrons comment ajouter du stockage persistant à notre application et la connecter à une base de données PostgreSQL. Également vous découvrirez la fonctionnalité de répliquas, alors stay tuned !