4.1. Docker - Django

../_images/docker_logo_ani.gif

In diesem Teil wird versucht, Docker in Verbindung mit dem Python Django Framework für das Deployment auf einem Server einzurichten. Hierfür werden verschiedene Docker-Container (Nginx, Python, GUnicorn, PostgreSqlDB..) erstellt und mit Docker-Compose ein komplettes System zusammen gesetzt, welches Systemunabhängig auf dem Server eines Kunden deployed werden kann.

Inhalt

4.1.1. Installation

Im nachfolgenden Projekt wird der APT-Packetmanager verwendet, falls Sie einen anderen Packetmanager verwenden, lesen Sie bitte die Installationsdokumentation von Docker an.

Um die neueste Version von Docker zu installieren, sollten zunächst alle vorherigen Docker-Installationen vom Ihrem System entfernt werden.

$ sudo apt-get remove docker docker-engine docker.io containerd runc

4.1.2. Linux Mint

Wie Docker auf der Homepage erwähnt, untstützt und tested die Docker-Community Installationen lediglich auf Mainstream Plattformen wie Ubunut, Debian, Windows usw. Linux Mint ist ein Abkömmling von Ubuntu mit einer eignen Oberfläche und eigenen Settings und Ressourcen. Aus diesem Grund funktioniert die Installationsanleitung von Docker nicht für Linux Mint, wesshalb ich hier eine kurze Installationsanleitung verfasst habe.

  1. Das System auf den neusten Stand bringen

    $ sudo apt-get update
    
  2. Site-Packages für den Zugriff über Https

    $ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
    
  3. Hinzufügen des Docker GPG-Keys

    $ sudo apt-get install apt-transport-https ca-certificates
    
  4. Den Key verifizieren

    $ sudo apt-key fingerprint 0EBFCD88
    
  5. Repository hinzufügen

    $ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
    
  6. Den Packetmanager neu laden

    $ sudo apt-get update
    
  7. Docker und Docker-Compose installieren

    $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose
    

4.1.3. Andere Betriebssysteme

Für die meisten anderen Betriebssystem kann der Intstallationsanleitung der Docker Dokumentation gefolgt werden, um Docker und Docker-Compose zu installieren.

4.1.4. Projektstruktur

4.1.4.1. docker-compose.yml

Die docker-compose.yml Datei dient des Aufbaus für Docker-Compose. Hier werden einige Konfigurationsdaten eingestellt. Es wird eine Datenbank benötigt, auf welche die Applikation zugreifen kann, um beispielsweiße Userdaten oder ähnliches abzuspeichern. Zusätzlich wird die Dango-Applikation in einem Container gestartet. Dazu benötigen wir eine eigenz kozipierte DockerFile, um lokal Daten zu verarbeiten. Des Weiteren wird ein GUnicorn-Wsgi-Webserver benötigt, um die Tasks von Django zu verarbeitent. Dieser startet dann die Webapplikation. Um Statische Dateien konventionell ablegen zu können, benötigen wir noch einen Web-Server, hier Nginx.

version: '3.1'
volumes:
  pgdata:
  static_files:                                         # Volume für static files
  media_content:                                        # Volume für media files
services:
  postgre_db:                                           # DNS für Datenbank-Service
    image: library/postgres:latest                      # Image für Postgre-DB
    environment:
      POSTGRES_DB: postgreDB                            # Datenbank Name
      POSTGRES_USER: user                               # Datenbank User Name
      POSTGRES_PASSWORD: password                       # Datenbank User Passwort
    volumes:
      - pgdata:/var/utils/posgresql/data                # Default Volume für Postgres Datenbank
    ports:
      - 5432:5432                                       # Port für Zugriff auf die Datenbank
  django_app:                                           # DNS für Web-Applikation
      build:
        context: .                                      # Root Verzeichnis des Projekts
        dockerfile: docker/webapp/Dockerfile            # Dockerfile, wird benötigt, um Container zu bauen
      restart: always                                   # Starte Applikation neu, wenn Fehler auftritt
      volumes:
      - ./webapp:/webapp                                # Das Volumen/Die App, welche eingebunden werden soll
      - static_files:/static_files                      # Volumen für static file
      - media_content:/media_content                    # Volumen für media files
      ports:
      - 8000:8000                                           # Port, auf welchem die Webseite ereicht werden kann
      command: gunicorn -w 4 webapp.wsgi -b 0.0.0.0:8000    # GUnicorn Middleware-Webserver für Produktion
  nginx:                                                    # DNS für Nginx Server
      build:
        context: .                                      # Root Verzeichnis für Nginx Server
        dockerfile: docker/nginx/Dockerfile             # Dockerfile, wird benötigt um Server zu konfigurieren
      volumes:
        - static_files:/static_files                    # shared volume mit django-web-applikation für static files
        - media_content:/media_content                  # shared volume mit django-web-applikation für media files
      ports:
        - 8080:80                                       # Leitet port 8080 an Port 80 weiter

4.1.4.2. nginx Verzeichnis

Das Nginx Verzeichnis beinhaltet alle wichtigen Dateien, um den Webserver zu starten. Sowie das Image, welches für Docker verwendet wird.

4.1.4.2.1. DockerFile

Um einen eigenn Docker-Container zu erzeugen, wird eine DockerFile benötigt. Es sind verschiedene Kommandos möglich und die Datei folgt einer strikten Syntax. Mehr über die DockerFile kann hier in der DockerFile-Dokumentation in Erfahrung gebracht werden.

FROM nginx:latest                                           # Docker Image für Nginx-Web-Server

RUN rm /etc/nginx/conf.d/default.conf                       # Löschen der Standart Konfigurationsdatei

COPY ./docker/nginx/webapp.conf /etc/nginx/conf.d/          # Kopieren unserer Konfigurationsdatei

4.1.4.2.2. Nginx-Konfiguration

Um den Server mit den nötigen Einstellungen auszustatten, wie beispielsweiße dem nötigen Static und Media Kontent abzuspeichern, muss der Server konfiguriert werden. Dies lässt sich mit einer .conf Datei bewältigen. Mehr über die Konfiguration von Nginx kann in der Nginx-Dokumentation nachgelesen werden.

server {
listen 80;                                  # Port auf dem http requests eingehen
server_name localhost;                      # Name des Servers
access_log  /var/log/nginx/example.log;     # Verzeichnis für logs
server_tokens off;                          # Verhindert, dass Serverinformationen nach außen sichtbar sind.

location /media/ {                          # Verzeichnis für media content
    autoindex off;                          # Abschalten der automatisch generierten Index Seite (Dort werden die Dateien im Verzeichnis angezeigt: html, css, ...)
    alias /media_content/;                  # Weiterleitung an den tatsächlichen Speicherort
}

location /static/ {                         # Wie bei media Dateien
    autoindex off;
    alias /static_files/;
}

location / {                                # Root Verzeichnis
    try_files $uri $uri/ @python_django;    # Wenn requested URI eine Datei oder ein Ordner ist, wird dieser versandt. Andernfalls weiterleitung an @python_django
}

location @python_django {
    proxy_pass http://django_app:8000;                              # Weiterleitung an GUnicorn Server auf Port 8000
    proxy_pass_request_headers on;                                  # Der Host wird geforwarded (Beispiel -> Django_app.com)
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    # Der Request wird an Django weitergeleitet (Django hat keine Ahnung von Proxy, deshalb werden IP's weitergeleitet werden)
    proxy_set_header Host $http_host;                               # Proxy kennt den Host-Header nicht, deshalb muss auch dieser weitergeleitet werden
    proxy_set_header X-Forwarded-Proto $scheme;                     # Beispiel wenn nginx hat ssl proxy, dann muss das an django weitergeleitet werden
    proxy_redirect off;                                             # Sollte von Django übernommen werden
}
}

4.1.4.3. django_app Verzeichnis

In diesem Verzeichnis werden alle DockerFile für das Deployment sowie für die Entwicklung hinterlegt. Besonders für die Entwicklung wird eine spezielle Konfiguration benötigt.

DockerFile

FROM python:3.8.3-buster
MAINTAINER user@localhost

COPY ./django_app /django_app

WORKDIR /django_app

RUN pip install -r requirements/deploy.txt                  # hier requirements/deploy.txt oder requirements/dev.txt
                                                            # Um die benötigten Python-Packages zu installieren.
                                                            # deploy.txt benötigt beispielsweiße gunicorn, dev jedoch nicht.
COPY ./docker/webapp/entrypoint.sh /entrypoint.sh

RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

Um beim Start des Dockers eine Ausgabe auf der Konsole zu sehen, macht es Sinn ein solches Entryskript zu verwenden.

entrypoint.sh

#!/bin/bash

echo "Running command '$*'"
exec /bin/bash -c "$*"

4.1.5. Django

Auch in Django müssen ein paar Änderungen vorgenommen werden. Zunächst muss die Datenbank richtig initialisiert werden. In diesem Beispiel verwenden wir eine Postgresql Datenbank. Eine relationale Datenbank, die von den Django Entwicklern empfohlen wird. Um da zu bewerkstelligen, muss die Datenbank in der settings.py eingerichtet werden.

DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'NAME': 'database_name',
    'USER': 'user_name',
    'PASSWORD': 'user_password',
    'HOST': 'postgre_db',           # Der Hostname, welcher in der docker-compose.yml als Service für die Datenbank eingetragen wurde
    'PORT': '5432',                 # Der Port, welcher für die Datenbank gedacht wurde --> docker-compose.yml
    }
}

Des weiteren müssen die Static und Media Files noch umgeleitet werden. Dazu benötigen wir die Volumes, welche in der docker-compose.yml festgelegt wurden. In diesem Projekt, sähe das wie folgt in der settings.py Datei aus.

STATIC_ROOT = '/static_files/'
MEDIA_ROOT = '/media_content/'

Zu guterletzt sollte der Debugmodus von Django noch deaktiviert werden. Dies kann ebenfall in der settings.py vorgenommen werden.

DEBUG = False

4.1.6. Docker-Compose

Um die die Docker-Container jetzt zusammenzusetzen benötigen wir docker compose. Um die Umgebung für die Produktion zu erstellen, muss dieses zunächst gebuilded werden.

$ docker-compose build

Um den Service nun zustarten, genügt es in der Konsole folgenden Befehl einzugeben.

$ docker-compose up

Der Nginx-Webserver läuft jetzt mit 4 Gunicorn Workern stabil und kann auf einem beliebiegen Server installiert werden.