Déployer avec Dango avec Docker, Nginx, et Gunicorn Django

Django Docker Docker Compose Gunicorn Nginx

Franck

Date publication: Oct. 21, 2019, 12:31 p.m.
Dernière mise à jour: Oct. 25, 2019, 12:31 p.m.


docker - Photo by Moritz Kindler on Unsplash

Comment déployer une application Django avec Docker, Nginx et Gunicorn


Aujourdhui, je vous propose de configurer votre environnement de production pour une application Django avec Docker, Docker compose, Nginx et Gunicorn.

Voici le principe, Docker va contenir les services Django, Nginx et Gunicorn. Nginx va servir de serveur proxy et Gunicorn sera le serveur qui fournira l'application Django.

Pour commencer voici la structure des dossiers du projet.

- app
  - monapp
    .env
    settings.py
  - requirements
    base.txt
    dev.txt
    prod.txt
  manage.py
- nginx
  default.conf
- static
docker-compose.yml
DockerFile

Le fichier Docker.

FROM python:3.7

# Création de variable d'environnement
ENV APP_ROOT /src
ENV CONFIG_ROOT /config

# Création du dossier de configuration
RUN mkdir $CONFIG_ROOT

# Copie des fichiers requirements.txt
COPY /app/requirements/*.txt $CONFIG_ROOT/

# installation des fichiers requirements.txt
RUN pip install -r $CONFIG_ROOT/prod.txt

# Création du dossier root
RUN mkdir $APP_ROOT
WORKDIR $APP_ROOT

ADD /app/ $APP_ROOT

# Changer [APP_DJANGO] par votre application (Ex. monapp).
CMD python manage.py makemigrations;python manage.py migrate;gunicorn [APP_DJANGO].wsgi -b 0.0.0.0:8000

Le fichier docker-compose.

version: "3"

services:
  nginx:
    image: nginx:1.17
    container_name: ngx
    ports:
      - "80:80"
    volumes:
      - ./app:/src
      - ./nginx:/etc/nginx/conf.d
      - ./static:/static
    depends_on:
      - app

  app:
    build: .
    container_name: django-gunicorn
    restart: always
    env_file:
      - ./app/[DJANGO_APP]/.env
    ports:
      - "8000:8000"
    command:
      "gunicorn --workers=2 --bind=0.0.0.0:8000 [DJANGO_APP].wsgi:application"
    volumes: 
      - ./app:/src
      - ./static:/static

  db:
    image: postgres
    container_name: database
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - 5432:5432

volumes:
  pgdata:

Explication du fichier docker-compose.

Le premier service est Nginx, celui-ci va servir de serveur proxy, il écoute le prot 80 car c'est lui qui recoit la requete client. Nous configurons aussi le volume static car c'est aussi lui qui fournira les fichiers statique de Django. Voir en dessous pour la configuration des fichiers statique dans Nginx.
Nous avons par la suite le service app, celui-ci est l'application Django, comme on peut le voir, nous avons aussi le volume static pour que l'application Django et Nginx partagent le même volume. Puis nous lancons la commande gunicorn pour que l'application Django puisse fonctionner grace au fichier wsgi.
Le dernier service est la base de donnée dans note cas avec Postgres.

 

La configuration Nginx grâce au fichier default.conf

server {
    listen 80;
    server_name localhost;
    
    location /static/ {
        autoindex off;
        alias /static/;
    }

    location / {
        try_files $uri $uri/ @python_django;
    }

    location @python_django {
        proxy_pass http://app:8000;
        proxy_pass_request_headers on;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
    }
}

Explication du fichier default.conf

Ici, nous voyons que nous écoutons le port 80. Ensuite nous configurons les fichiers statique pour que Django et surtout Gunicorn puisse les afficher. Pour finir nous configurons nginx pour envoyer les requêtes vers le port 8000 de Gunicorn. Le proxy pass prend app:8000 qui est finalement le service dans le fichier docker-compose.

 

Le fichier base.txt

Django
psycopg2
Pillow
django-ckeditor

Explications du fichier base.txt

Dans ce fichier nous mettons la configuration commune entre la dev et la prod pour que Django puisse fonctionner. Nous avons bien entendu Django, suivi de la base de donnée, la gestion des images et le Wysiwyg ckeditor.

 

Le fichier dev.txt

-r base.txt

django-debug-toolbar
Dans le fichier dev nous ajoutons aussi, la barre de débogage.

 

Le fichier prod.txt

-r base.txt

python-dotenv==0.10.3
gunicorn==19.9.0
Dans le fichier prod, nous ajoutons 2 choses, la première est la possibilité de créer des fichier .env qui vont contenir nos différentes variables d'environnement.
la deuxième est tout simplement le serveur Gunicorn

 

Le fichier settings.py dans l'application.

SECRET_KEY = os.getenv('SECRET_KEY')

DEBUG = os.getenv('DEBUG')
ALLOWED_HOSTS = ['*']

# Application definition
INSTALLED_APPS = [
    'blog.apps.BlogConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'ckeditor',
    'ckeditor_uploader',
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('POSTGRES_NAME', 'postgres'),
        'USER': os.getenv('POSTGRES_USER', 'postgres'),
        'HOST': os.getenv('POSTGRES_HOST', 'db'),
        'PORT': os.getenv('POSTGRES_PORT', 5432),
    }
}

CKEDITOR_UPLOAD_PATH = "uploads/"

STATIC_URL = '/static/'
STATIC_ROOT = '/static/'

# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "mediafiles")

Le fichier settings.py ici raccourci avec seulement les variables qui ont besoin d'être changées. On peut constater que pour récupérer les variables d'environnement, nous faisons ceci:
os.getenv('SECRET_KEY')

Mais voici un exemple de fichier .env

SECRET_KEY=maclesecrete
DEBUG=False

Ensuite il vous suffit de faire quelques lignes de commandes.

docker-compose build 

docker-compose up -d

docker-compose run app python3 manage.py makemigrations

docker-compose run app python3 manage.py migrate

docker-compose run app python3 manage.py collectstatic

Ensuite tout devrait fonctionner pour l'environnement de production.