One place for hosting & domains

      DjangoAnwendung

      Bereitstellen einer skalierbaren und sicheren Django-Anwendung mit Kubernetes


      Einführung

      In diesem Tutorial stellen Sie eine containerisierte Django-Umfrageanwendung in einem Kubernetes-Cluster bereit.

      Django ist ein leistungsfähiges Web-Framework, das Ihnen dabei helfen kann, Ihre Python-Anwendung schnell bereitzustellen. Es enthält mehrere praktische Funktionen wie einen objektrelationalen Mapper, eine Benutzerauthentifizierung und eine anpassbare Verwaltungsoberfläche für Ihre Anwendung. Es beinhaltet auch ein Caching-Framework und fördert ein sauberes App-Design durch seinen URL Dispatcher und das Vorlagensystem.

      In Erstellen einer Django- und Gunicorn-Anwendung mit Docker wurde die Django Tutorial Umfrageanwendung gemäß der Zwölf-Faktor-Methodik zur Erstellung skalierbarer Cloud-nativer Web-Apps modifiziert. Diese containerisierte Einrichtung wurde mit einem Nginx Reverse-Proxy und Let’s Encrypt-signierten TLS-Zertifikaten in Skalieren und Sichern einer Django-Anwendung mit Docker, Nginx und Let’s Encrypt skaliert und gesichert. In diesem letzten Tutorial der Reihe Von Containern zu Kubernetes mit Django wird die modernisierte Django-Umfrageanwendung in einem Kubernetes-Cluster bereitgestellt.

      Kubernetes ist ein leistungsstarker Open-Source-Container-Orchestrator, der die Bereitstellung, das Skalieren und die Verwaltung von containerisierten Anwendungen automatisiert. Mit Kubernetes-Objekten wie ConfigMaps und Secrets können Sie die Konfiguration zentralisieren und von Ihren Containern entkoppeln, während Controller wie Deployments fehlgeschlagene Container automatisch neu starten und eine schnelle Skalierung von Container-Replikaten ermöglichen. Die TLS-Verschlüsselung wird mit einem Ingress-Objekt und dem Open-Source Ingress-Controller ingress-nginx aktiviert. Das Kubernetes Add-on cert-manager erneuert und stellt Zertifikate mit der kostenlosen Zertifizierungsstelle Let’s Encrypt aus.

      Voraussetzungen

      Um dieser Anleitung zu folgen, benötigen Sie:

      • Einen Kubernetes 1.15+-Cluster mit aktivierter rollenbasierter Zugriffskontrolle (RBAC). In diesem Setup wird ein DigitalOcean Kubernetes-Cluster verwendet, doch Sie können einen Cluster auch mit einer anderen Methode erstellen.
      • Das Befehlszeilen-Tool kubectl, das auf Ihrem lokalen Rechner installiert und für die Verbindung mit Ihrem Cluster konfiguriert ist. Weitere Informationen zur Installation von kubectl finden Sie in der offiziellen Dokumentation. Wenn Sie einen DigitalOcean Kubernetes-Cluster verwenden, lesen Sie bitte Verbinden mit einem DigitalOcean Kubernetes-Cluster, um zu erfahren, wie Sie sich mit kubectl mit Ihrem Cluster verbinden können.
      • Einen registrierten Domänennamen. In diesem Tutorial wird durchgängig your_domain.com verwendet. Einen Domänennamen können Sie kostenlos bei Freenom erhalten oder Sie nutzen eine Domänenregistrierungsstelle Ihrer Wahl.
      • Einen ingress-nginx Ingress-Controller und den TLS-Zertifizierungsmanager cert-manager, die in Ihrem Cluster installiert und zur Ausgabe von TLS-Zertifikaten konfiguriert sind. Um zu erfahren, wie Sie einen Ingress mit cert-manager installieren und konfigurieren, konsultieren Sie bitte Einrichten eines Nginx Ingress mit Cert-Manager in DigitalOcean Kubernetes.
      • Einen A-DNS-Datensatz mit your_domain.com, der auf die öffentliche IP-Adresse des Ingress Load Balancers verweist. Wenn Sie DigitalOcean zum Verwalten der DNS-Datensätze Ihrer Domäne verwenden, konsultieren Sie bitte Verwalten von DNS-Datensätzen, um zu erfahren, wie Sie A-Datensätze erstellen.
      • Einen S3-Objektspeicher-Bucket wie beispielsweise einen DigitalOcean Space zur Speicherung der statischen Dateien Ihres Django-Projekts und einen Satz von Zugriffsschlüsseln für diesen Space. Um zu erfahren, wie Sie einen Space erstellen können, lesen Sie die Produktdokumentation Erstellen von Spaces. Um zu erfahren, wie Sie Zugriffsschlüssel für Spaces erstellen können, lesen Sie Zugriff auf Spaces mit Zugriffsschlüsseln gemeinsam nutzen. Mit geringfügigen Änderungen können Sie jeden Objektspeicherdienst verwenden, der das Plugin django-storages verwendet.
      • Eine PostgreSQL-Server-Instanz, Datenbank und Benutzer für Ihre Django-Anwendung. Mit geringfügigen Änderungen können Sie jede Datenbank verwenden, die Django unterstützt.
      • Ein Docker Hub-Konto und ein öffentliches Repository. Weitere Informationen zu deren Erstellung finden Sie in Repositories in der Docker-Dokumentation.
      • Die auf Ihrem lokalen Rechner installierte Docker-Engine. Weitere Informationen finden Sie unter Installieren und Verwenden von Docker unter Ubuntu 18.04.

      Sobald Sie diese Komponenten eingerichtet haben, können Sie mit diesem Leitfaden beginnen.

      Schritt 1 — Klonen und Konfigurieren der Anwendung

      In diesem Schritt klonen wir den Anwendungscode von GitHub und konfigurieren Einstellungen wie Datenbankzugangsdaten und Objektspeicherschlüssel.

      Der Anwendungscode und das Dockerfile befinden sich im Zweig polls-docker der Django Tutorial Umfrageanwendung GitHub-Repository. Dieses Repository enthält Code für die Beispiel-Umfrageanwendung aus der Django-Dokumentation, in der Sie lernen, wie Sie eine Umfrageanwendung von Grund auf erstellen.

      Der Zweig polls-docker enthält eine dockerisierte Version der Umfrageanwendung. Um zu erfahren, wie die Umfrageanwendung modifiziert wurde, um effektiv in einer containerisierten Umgebung zu arbeiten, lesen Sie bitte Erstellen einer Django- und Gunicorn-Anwendung mit Docker.

      Beginnen Sie mit der Verwendung von git zum Klonen des Zweigs polls-docker der Django Tutorial Umfrageanwendung GitHub-Repository auf Ihren lokalen Rechner:

      • git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

      Navigieren Sie in das Verzeichnis django-polls:

      Dieses Verzeichnis enthält den Python-Code der Django-Anwendung, ein Dockerfile, das Docker zum Erstellen des Container-Images verwendet, sowie eine Datei env, die eine Liste von Umgebungsvariablen enthält, die an die laufende Umgebung des Containers übergeben werden müssen. Prüfen Sie das Dockerfile:

      Output

      FROM python:3.7.4-alpine3.10 ADD django-polls/requirements.txt /app/requirements.txt RUN set -ex && apk add --no-cache --virtual .build-deps postgresql-dev build-base && python -m venv /env && /env/bin/pip install --upgrade pip && /env/bin/pip install --no-cache-dir -r /app/requirements.txt && runDeps="$(scanelf --needed --nobanner --recursive /env | awk '{ gsub(/,/, "nso:", $2); print "so:" $2 }' | sort -u | xargs -r apk info --installed | sort -u)" && apk add --virtual rundeps $runDeps && apk del .build-deps ADD django-polls /app WORKDIR /app ENV VIRTUAL_ENV /env ENV PATH /env/bin:$PATH EXPOSE 8000 CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "mysite.wsgi"]

      Dieses Dockerfile verwendet das offizielle Python 3.7.4 Docker-Image als Basis und installiert die Python-Paketanforderungen von Django und Gunicorn, wie sie in der Datei django-polls/requirements.txt definiert sind. Anschließend entfernt es einige unnötige Builddateien, kopiert den Anwendungscode in das Image und legt den Ausführungspfad PATH fest. Schließlich gibt es an, dass Port 8000 verwendet wird, um eingehende Container-Verbindungen zu akzeptieren und gunicorn mit 3 Workern ausgeführt wird, die Port 8000 abhören.

      Um mehr über die einzelnen Schritte in diesem Dockerfile zu erfahren, lesen Sie bitte Schritt 6 von Erstellen einer Django- und Gunicorn-Anwendung mit Docker.

      Erstellen Sie nun das Image mit docker build:

      Wir benennen das Image polls mit dem Flag -t und übergeben im aktuellen Verzeichnis als Build-Kontext den Satz von Daten, auf den beim Erstellen des Images verwiesen werden soll.

      Nachdem Docker das Image erstellt und mit Tags versehen hat, listen wir die verfügbaren Images mit docker images auf:

      Sie sollten die polls-Images aufgelistet sehen:

      OutputREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
      polls               latest              80ec4f33aae1        2 weeks ago         197MB
      python              3.7.4-alpine3.10    f309434dea3a        8 months ago        98.7MB
      

      Bevor wir den Django-Container ausführen, müssen wir seine Betriebsumgebung mithilfe der im aktuellen Verzeichnis vorhandenen Datei env konfigurieren. Diese Datei wird an den Befehl docker run übergeben, der zum Ausführen des Containers verwendet wird, und Docker injiziert die konfigurierten Umgebungsvariablen in die Betriebsumgebung des Containers.

      Öffnen Sie die Datei env mit nano oder Ihrem bevorzugten Editor:

      django-polls/env

      DJANGO_SECRET_KEY=
      DEBUG=True
      DJANGO_ALLOWED_HOSTS=
      DATABASE_ENGINE=postgresql_psycopg2
      DATABASE_NAME=polls
      DATABASE_USERNAME=
      DATABASE_PASSWORD=
      DATABASE_HOST=
      DATABASE_PORT=
      STATIC_ACCESS_KEY_ID=
      STATIC_SECRET_KEY=
      STATIC_BUCKET_NAME=
      STATIC_ENDPOINT_URL=
      DJANGO_LOGLEVEL=info
      

      Geben Sie die fehlenden Werte für die folgenden Schlüssel ein:

      • DJANGO_SECRET_KEY: Setzen Sie diesen auf einen eindeutigen, nicht vorhersagbaren Wert, wie in den Django-Dokumentationen beschrieben. Eine Methode zur Generierung dieses Wertes wird in Anpassen der Anwendungseinstellungen in dem Tutorial Skalierbare Django-Anwendung angeboten.
      • DJANGO_ALLOWED_HOSTS: Diese Variable sichert die Anwendung und verhindert HTTP-Host-Header-Angriffe. Setzen Sie diese Variable für Testzwecke auf *, einen Platzhalter, der auf alle Hosts zutrifft. In der Produktion sollten Sie diese Variable auf your_domain.com setzen. Um mehr über diese Django-Einstellungen zu erfahren, konsultieren Sie die Core-Einstellungen der Django-Dokumentation.
      • DATABASE_USERNAME: Setzen Sie diesen auf den in den vorbereitenden Schritten erstellten PostgreSQL Datenbankbenutzer.
      • DATABASE_NAME: Setzen Sie diesen auf polls oder den in den vorbereitenden Schritten erstellten Namen der PostgreSQL-Datenbank.
      • DATABASE_PASSWORD: Setzen Sie dieses auf das in den vorbereitenden Schritten erstellte Passwort für den PostgreSQL Benutzer.
      • DATABASE_HOST: Setzen Sie diesen Wert auf den Hostnamen Ihrer Datenbank.
      • DATABASE_PORT: Setzen Sie diesen Wert auf den Port Ihrer Datenbank.
      • STATIC_ACCESS_KEY_ID: Setzen Sie dies auf den Zugriffsschlüssel Ihres Space oder Objektspeichers.
      • STATIC_SECRET_KEY: Setzen Sie dies auf den Zugriffsschlüssel Ihres Space- oder Objektspeicher-Secret.
      • STATIC_BUCKET_NAME: Setzen Sie dies auf den Namen Ihres Space- oder Objektspeicher-Buckets.
      • STATIC_ENDPOINT_URL: Setzen Sie diese auf die entsprechende Endpunkt-URL des Space oder Objektspeichers, z. B. https://space-name.nyc3.digitaloceanspaces.com, wenn sich Ihr Space in der Region nyc3 befindet.

      Wenn Sie die Bearbeitung abgeschlossen haben, speichern und schließen Sie die Datei.

      Im nächsten Schritt führen wir den konfigurierten Container lokal aus und erstellen das Datenbankschema. Wir laden ebenfalls statische Assets wie Stylesheets und Images in den Objektspeicher hoch.

      Schritt 2 — Erstellen des Datenbankschemas und Hochladen von Assets in den Objektspeicher

      Nachdem der Container erstellt und konfiguriert ist, verwenden wir nun docker run, um den CMD-Satz in dem Dockerfile zu überschreiben und das Datenbankschema mit den Befehlen manage.py makemigrations und manage.py migrate zu erstellen:

      • docker run --env-file env polls sh -c "python manage.py makemigrations && python manage.py migrate"

      Wir führen das Container-Image polls:latest aus, übergeben die von uns gerade modifizierte Umgebungsvariablendatei und überschreiben den Dockerfile-Befehl mit sh -c "python manage.py makemigrations && python manage.py migrate", wodurch das durch den Anwendungscode definierte Datenbankschema erstellt wird.

      Wenn Sie dies zum ersten Mal ausführen, sollten Sie Folgendes sehen:

      Output

      No changes detected Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying polls.0001_initial... OK Applying sessions.0001_initial... OK

      Dies zeigt an, dass das Datenbankschema erfolgreich erstellt wurde.

      Wenn Sie migrate zu einem späteren Zeitpunkt ausführen, führt Django eine Nulloperation durch, es sei denn, das Datenbankschema wurde geändert.

      Als Nächstes führen wir eine weitere Instanz des Anwendungscontainers aus und verwenden darin eine interaktive Shell, um einen Administratorbenutzer für das Django-Projekt zu erstellen.

      • docker run -i -t --env-file env polls sh

      Dadurch erhalten Sie eine Shell-Eingabeaufforderung innerhalb des laufenden Containers, die Sie zum Erstellen des Django-Benutzers verwenden können:

      • python manage.py createsuperuser

      Geben Sie einen Benutzernamen, eine E-Mail-Adresse und ein Passwort für Ihren Benutzer ein. Drücken Sie nach dem Erstellen des Benutzers STRG+D, um den Container zu verlassen und zu beenden.

      Schließlich generieren wir die statischen Dateien für die Anwendung und laden sie mit collectstatic in den DigitalOcean Space hoch. Beachten Sie, dass dies möglicherweise einige Zeit dauern kann.

      • docker run --env-file env polls sh -c "python manage.py collectstatic --noinput"

      Nachdem diese Dateien generiert und hochgeladen sind, erhalten Sie folgende Ausgabe.

      Output

      121 static files copied.

      Wir können die Anwendung nun ausführen:

      • docker run --env-file env -p 80:8000 polls

      Output

      [2019-10-17 21:23:36 +0000] [1] [INFO] Starting gunicorn 19.9.0 [2019-10-17 21:23:36 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1) [2019-10-17 21:23:36 +0000] [1] [INFO] Using worker: sync [2019-10-17 21:23:36 +0000] [7] [INFO] Booting worker with pid: 7 [2019-10-17 21:23:36 +0000] [8] [INFO] Booting worker with pid: 8 [2019-10-17 21:23:36 +0000] [9] [INFO] Booting worker with pid: 9

      Hier führen wir den in dem Dockerfile definierten Standardbefehl gunicorn ---bind :8000 --workers 3 mysite.wsgi:application aus und geben den Container-Port 8000 frei, sodass Port 80 auf Ihrem lokalen Rechner dem Port 8000 des Containers polls zugeordnet wird.

      Sie sollten nun über Ihren Webbrowser zu der Anwendung polls navigieren können, indem Sie http://localhost in die URL-Leiste eingeben. Da für den Pfad / keine Route definiert ist, erhalten Sie wahrscheinlich einen 404 Page Not Found-Fehler, der zu erwarten ist.

      Navigieren Sie zu http://localhost/polls, um die Benutzeroberfläche der Umfrageanwendung zu sehen:

      Oberfläche der Umfrageanwendung

      Um die administrative Oberfläche anzuzeigen, besuchen Sie http://localhost/admin. Sie sollten das Authentifizierungsfenster für den Administrator der Umfrageanwendung sehen:

      Authentifizierungsseite für Polls-Administrator

      Geben Sie den administrativen Benutzernamen und das Passwort ein, das Sie mit dem Befehl createsuperuser erstellt haben.

      Nach der Authentifizierung können Sie auf die administrative Oberfläche der Umfrageanwendung zugreifen:

      Administrative Hauptoberfläche von Polls

      Beachten Sie, dass statische Assets für die Anwendungen admin und polls direkt aus dem Objektspeicher bereitgestellt werden. Um dies zu bestätigen, konsultieren Sie Prüfen der statischen Dateizustellung von Spaces.

      Wenn Sie die Erkundung abgeschlossen haben, drücken Sie STRG+C im Terminalfenster, in dem der Docker-Container ausgeführt wird, um den Container zu beenden.

      Nachdem das Docker-Image der Django-Anwendung getestet, die statischen Assets in den Objektspeicher hochgeladen und das Datenbankschema konfiguriert und für die Verwendung mit Ihrer Anwendung bereit ist/sind, können Sie Ihr Django-App-Image in eine Bildregistrierung wie Docker Hub hochladen.

      Schritt 3 — Verschieben des Django-App-Images zu Docker Hub

      Um Ihre Anwendung unter Kubernetes bereitzustellen, muss Ihr App-Image in eine Registrierung wie Docker Hub hochgeladen werden. Kubernetes zieht das App-Image aus seinem Repository und stellt es dann in Ihren Cluster bereit.

      Sie können eine private Docker-Registrierung verwenden, wie die DigitalOcean Container Registry, die derzeit kostenlos in Early Access ist, oder eine öffentliche Docker-Registrierung wie Docker Hub. Mit Docker Hub können Sie auch private Docker-Repositorys erstellen. Ein öffentliches Repository erlaubt jedem, die Container-Images zu sehen und abzurufen, während Sie mit einem privaten Repository den Zugriff auf Sie und Ihre Teammitglieder beschränken können.

      In diesem Tutorial verschieben wir das Django-Image in das öffentliche Docker Hub-Repository, das in den Voraussetzungen erstellt wurde. Sie können Ihr Image auch in ein privates Repository verschieben, aber das Abrufen von Images aus einem privaten Repository liegt außerhalb des Rahmens dieses Artikels. Um mehr über die Authentifizierung von Kubernetes mit Docker Hub und das Abrufen von privaten Images zu erfahren, lesen Sie bitte Abrufen eines Images aus einer privaten Registrierung aus den Kubernetes-Dokumenten.

      Beginnen Sie mit der Anmeldung an Docker Hub auf Ihrem lokalen Rechner:

      Output

      Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username:

      Geben Sie Ihren Docker Hub-Benutzernamen und Ihr Passwort ein, um sich anzumelden.

      Das Django-Image hat derzeit die Markierung polls:latest. Um es in Ihr Docker Hub-Repository zu verschieben, markieren Sie das Image erneut mit Ihrem Docker Hub-Benutzernamen und dem Repository-Namen:

      • docker tag polls:latest your_dockerhub_username/your_dockerhub_repo_name:latest

      Verschieben Sie das Image in das Repository:

      • docker push sammy/sammy-django:latest

      In diesem Tutorial ist der Docker Hub-Benutzername sammy und der Repository-Name ist sammy-django. Sie sollten diese Werte durch Ihren eigenen Docker Hub-Benutzernamen und Repository-Namen ersetzen.

      Sie sehen eine Ausgabe, die sich aktualisiert, wenn Image-Schichten in Docker Hub verschoben werden.

      Nachdem Ihr Image nun für Kubernetes unter Docker Hub verfügbar ist, können Sie es in Ihrem Cluster bereitstellen.

      Schritt 4 — Einrichten der ConfigMap

      Als wir den Django-Container lokal ausgeführt haben, haben wir die Datei env an docker run übergeben, um Konfigurationsvariablen in die Laufzeitumgebung zu injizieren. Bei Kubernetes können Konfigurationsvariablen mit ConfigMaps und Secrets injiziert werden.

      ConfigMaps sollte verwendet werden, um nicht vertrauliche Konfigurationsdaten wie App-Einstellungen zu speichern, und Secrets sollte für sensible Informationen wie API-Schlüssel und Datenbank-Zugangsdaten verwendet werden. Sie werden beide auf ähnliche Weise in Container injiziert, aber Secrets haben zusätzliche Zugriffskontrolle und Sicherheitsfunktionen wie Verschlüsselung im Ruhezustand. Secrets speichern außerdem Daten in base64, während ConfigMaps Daten im Klartext speichern.

      Erstellen Sie zunächst ein Verzeichnis namens yaml, in dem wir unsere Kubernetes-Manifeste speichern werden. Navigieren Sie in das Verzeichnis.

      Öffnen Sie eine Datei namens polls-configmap.yaml in nano oder Ihrem bevorzugten Texteditor:

      • nano polls-configmap.yaml

      Fügen Sie das folgende ConfigMap-Manifest ein:

      polls-configmap.yaml

      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: polls-config
      data:
        DJANGO_ALLOWED_HOSTS: "*"
        STATIC_ENDPOINT_URL: "https://your_space_name.space_region.digitaloceanspaces.com"
        STATIC_BUCKET_NAME: "your_space_name"
        DJANGO_LOGLEVEL: "info"
        DEBUG: "True"
        DATABASE_ENGINE: "postgresql_psycopg2"
      

      Wir haben die nicht sensible Konfiguration aus der in Schritt 1 geänderten Datei env extrahiert und in ein ConfigMap-Manifest eingefügt. Das ConfigMap-Objekt wird polls-config genannt. Kopieren Sie die gleichen Werte hinein, die Sie im vorherigen Schritt in die Datei env eingegeben haben.

      Lassen Sie für Testzwecke DJANGO_ALLOWED_HOSTS auf * stehen, um die Host-Header-basierte Filterung zu deaktivieren. In einer Produktionsumgebung sollten Sie dies auf die Domäne Ihrer Anwendung setzen.

      Wenn Sie mit der Bearbeitung der Datei fertig sind, speichern und schließen Sie sie.

      Erstellen Sie die ConfigMap in Ihrem Cluster mit kubectl apply:

      • kubectl apply -f polls-configmap.yaml

      Output

      configmap/polls-config created

      Nachdem die ConfigMap erstellt wurde, erstellen wir im nächsten Schritt das von unserer Anwendung verwendete Secret.

      Schritt 5 — Einrichten des Secret

      Secret-Werte müssen base64-kodiert sein, d. h. das Erstellen von Secret-Objekten in Ihrem Cluster ist etwas aufwendiger als das Erstellen von ConfigMaps. Sie können den Vorgang aus dem vorherigen Schritt wiederholen, indem Sie Secret-Werte manuell base64-kodieren und in eine Manifestdatei einfügen. Sie können sie auch mit einer Umgebungsvariablendatei kubectl create und dem Flag --from-env-file erstellen, was wir in diesem Schritt tun werden.

      Wir verwenden erneut die Datei env von Schritt 1 und entfernen die in die ConfigMap eingefügten Variablen. Erstellen Sie eine Kopie der Datei env mit dem Namen polls-secrets im Verzeichnis yaml:

      • cp ../env ./polls-secrets

      Bearbeiten Sie die Datei in Ihrem bevorzugten Editor:

      polls-secrets

      DJANGO_SECRET_KEY=
      DEBUG=True
      DJANGO_ALLOWED_HOSTS=
      DATABASE_ENGINE=postgresql_psycopg2
      DATABASE_NAME=polls
      DATABASE_USERNAME=
      DATABASE_PASSWORD=
      DATABASE_HOST=
      DATABASE_PORT=
      STATIC_ACCESS_KEY_ID=
      STATIC_SECRET_KEY=
      STATIC_BUCKET_NAME=
      STATIC_ENDPOINT_URL=
      DJANGO_LOGLEVEL=info
      

      Löschen Sie alle in das ConfigMap-Manifest eingefügten Variablen. Wenn Sie fertig sind, sollte die Datei wie folgt aussehen:

      polls-secrets

      DJANGO_SECRET_KEY=your_secret_key
      DATABASE_NAME=polls
      DATABASE_USERNAME=your_django_db_user
      DATABASE_PASSWORD=your_django_db_user_password
      DATABASE_HOST=your_db_host
      DATABASE_PORT=your_db_port
      STATIC_ACCESS_KEY_ID=your_space_access_key
      STATIC_SECRET_KEY=your_space_access_key_secret
      

      Stellen Sie sicher, dass Sie die gleichen Werte wie in Schritt 1 verwenden. Wenn Sie fertig sind, speichern und schließen Sie die Datei.

      Erstellen Sie das Secret in Ihrem Cluster mit kubectl create secret:

      • kubectl create secret generic polls-secret --from-env-file=poll-secrets

      Output

      secret/polls-secret created

      Hier erstellen wir ein Secret-Objekt namens polls-secret und übergeben die soeben erstellte Secrets-Datei.

      Sie können das Secret mit kubectl describe inspizieren:

      • kubectl describe secret polls-secret

      Output

      Name: polls-secret Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== DATABASE_PASSWORD: 8 bytes DATABASE_PORT: 5 bytes DATABASE_USERNAME: 5 bytes DJANGO_SECRET_KEY: 14 bytes STATIC_ACCESS_KEY_ID: 20 bytes STATIC_SECRET_KEY: 43 bytes DATABASE_HOST: 47 bytes DATABASE_NAME: 5 bytes

      Zu diesem Zeitpunkt haben Sie die Konfiguration Ihrer Anwendung in Ihrem Kubernetes-Cluster mithilfe der Objekttypen Secret und ConfigMap gespeichert. Wir sind nun bereit, die Anwendung in dem Cluster bereitzustellen.

      Schritt 6 — Bereitstellen der Django-Anwendung mithilfe eines Deployment

      In diesem Schritt erstellen Sie ein Deployment für Ihre Django-Anwendung. Eine Kubernetes Deployment ist ein Controller, der zur Verwaltung von zustandslosen Anwendungen in Ihrem Cluster verwendet werden kann. Ein Controller ist eine Kontrollschleife, die Arbeitslasten reguliert, indem er sie herauf- oder herunterskaliert. Controller starten auch fehlgeschlagene Container neu und leeren sie aus.

      Deployments steuern ein oder mehrere Pods, die kleinste einsetzbare Einheit in einem Kubernetes-Cluster. Pods umschließen einen oder mehrere Container. Um mehr über die verschiedenen Arten von Arbeistlasten zu erfahren, die Sie starten können, lesen Sie bitte Eine Einführung in Kubernetes.

      Öffnen Sie zunächst eine Datei namens polls-deployment.yaml in Ihrem bevorzugten Editor:

      • nano polls-deployment.yaml

      Fügen Sie das folgende Deployment-Manifest ein:

      polls-deployment.yaml

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: polls-app
        labels:
          app: polls
      spec:
          replicas: 2
        selector:
          matchLabels:
            app: polls
        template:
          metadata:
            labels:
              app: polls
          spec:
            containers:
              - image: your_dockerhub_username/app_repo_name:latest
                name: polls
                envFrom:
                - secretRef:
                    name: polls-secret
                - configMapRef:
                    name: polls-config
                ports:
                  - containerPort: 8000
                    name: gunicorn
      

      Geben Sie den entsprechenden Container-Image-Namen ein und verweisen Sie dabei auf das Django Umfrage-Image, das Sie in Schritt 2 in Docker Hub verschoben haben.

      Hier definieren wir eine Kubernetes Deployment namens polls-app und kennzeichnen es mit dem Schlüsselwertpaar app: polls. Wir geben an, dass wir zwei Replikate des Pods ausführen möchten, der unterhalb des Felds template definiert ist.

      Durch die Verwendung von envFrom mit secretRef und configMapRef legen wir fest, dass alle Daten aus dem Secret polls-secret und der ConfigMap polls-config als Umgebungsvariablen in die Container injiziert werden sollen. Die Schlüssel ConfigMap und Secret werden zu den Namen der Umgebungsvariablen.

      Abschließend geben wir containerPort 8000 frei und nennen ihn gunicorn.

      Um mehr über die Konfiguration von Kubernetes Deployments zu erfahren, konsultieren Sie bitte Deployments aus der Kubernetes-Dokumentation.

      Wenn Sie mit der Bearbeitung der Datei fertig sind, speichern und schließen Sie sie.

      Erstellen Sie das Deployment in Ihrem Cluster mit kubectl apply -f:

      • kubectl apply -f polls-deployment.yaml
      • deployment.apps/polls-app created

      Überprüfen Sie mit kubectl get, ob das Deployment korrekt bereitgestellt wurde:

      • kubectl get deploy polls-app

      Output

      NAME READY UP-TO-DATE AVAILABLE AGE polls-app 2/2 2 2 6m38s

      Wenn Sie auf einen Fehler stoßen, oder etwas nicht so ganz funktioniert, können Sie kubectl describe verwenden, um das fehlgeschlagene Deployment zu inspizieren:

      Sie können die beiden Pods mit kubectl get pod inspizieren:

      Output

      NAME READY STATUS RESTARTS AGE polls-app-847f8ccbf4-2stf7 1/1 Running 0 6m42s polls-app-847f8ccbf4-tqpwm 1/1 Running 0 6m57s

      Zwei Replikate Ihrer Django-Anwendung sind nun im Cluster in Betrieb. Um auf die Anwendung zuzugreifen, müssen Sie einen Kubernetes-Dienst erstellen, was wir als Nächstes tun.

      Schritt 7 — Erlauben des externen Zugriffs unter Verwendung eines Dienstes

      In diesem Schritt erstellen Sie einen Dienst für Ihre Django-Anwendung. Ein Kubernetes-Dienst ist eine Abstraktion, die es Ihnen ermöglicht, einen Satz laufender Pods als Netzwerkdienst bereitzustellen. Mit einem Dienst können Sie einen stabilen Endpunkt für Ihre Anwendung erstellen, der sich nicht ändert, wenn Pods sterben und neu erstellt werden.

      Es gibt mehrere Dienstarten, einschließlich ClusterIP-Dienste, die den Dienst auf einer clusterinternen IP-Adresse bereitstellen, NodePort-Dienste, die den Dienst auf jedem Knoten an einem statischen Port, dem Nodeport, bereitstellen, und LoadBalancer-Dienste, die einen Cloud-Load-Balancer bereitstellen, um externen Datenverkehr zu den Pods in Ihrem Cluster zu leiten (über NodePorts, die er automatisch erstellt). Um mehr über diese zu erfahren, lesen Sie bitte Service in den Kubernetes-Dokumenten.

      In unserer endgültigen Einrichtung verwenden wir einen ClusterIP-Dienst, der über einen Ingress und den in den Voraussetzungen für diesen Leitfaden eingerichteten Ingress-Controller freigegeben wird. Um zu testen, ob alles korrekt funktioniert, erstellen wir zunächst einen temporären NodePort-Dienst, um auf die Django-Anwendung zuzugreifen.

      Beginnen Sie mit dem Erstellen einer Datei namens polls-svc.yaml mit Ihrem bevorzugten Editor:

      Fügen Sie das folgende Dienst-Manifest ein:

      polls-svc.yaml

      apiVersion: v1
      kind: Service
      metadata:
        name: polls
        labels:
          app: polls
      spec:
        type: NodePort
        selector:
          app: polls
        ports:
          - port: 8000
            targetPort: 8000
      

      Hier erstellen wir einen NodePort-Dienst namens polls und geben ihm die Kennzeichnung app: polls. Dann wählen wir Backend-Pods mit der Kennzeichnung app: polls, und zielen auf deren Ports 8000.

      Wenn Sie mit der Bearbeitung der Datei fertig sind, speichern und schließen Sie sie.

      Stellen Sie den Dienst mit kubectl apply bereit:

      • kubectl apply -f polls-svc.yaml

      Output

      service/polls created

      Bestätigen Sie mit kubectl get svc, dass Ihr Dienst erstellt wurde:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE polls NodePort 10.245.197.189 <none> 8000:32654/TCP 59s

      Diese Ausgabe zeigt die clusterinterne IP des Dienstes und den NodePort (32654). Um eine Verbindung mit dem Dienst herzustellen, benötigen wir die externen IP-Adressen für unsere Cluster-Knoten:

      Output

      NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME pool-7no0qd9e0-364fd Ready <none> 27h v1.18.8 10.118.0.5 203.0.113.1 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9 pool-7no0qd9e0-364fi Ready <none> 27h v1.18.8 10.118.0.4 203.0.113.2 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9 pool-7no0qd9e0-364fv Ready <none> 27h v1.18.8 10.118.0.3 203.0.113.3 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9

      Rufen Sie in Ihrem Webbrowser Ihre Umfrageanwendung mit der externen IP-Adresse eines beliebigen Knotens und dem NodePort auf. Mit der vorstehenden Ausgabe würde die URL der Anwendung lauten: http://203.0.113.1:32654/polls.

      Sie sollten die gleiche Oberfläche der Umfrageanwendung sehen, auf die Sie in Schritt 1 lokal zugegriffen haben:

      Oberfläche der Umfrageanwendung

      Sie können den gleichen Test mit der Route /admin wiederholen: http://203.0.113.1:32654/admin. Sie sollten die gleiche Admin-Oberfläche wie zuvor sehen:

      Authentifizierungsseite für Polls-Administrator

      Zu diesem Zeitpunkt haben Sie zwei Replikate des Django Umfrageanwendungs-Containers mithilfe eines Deployments bereitgestellt. Außerdem haben Sie einen stabilen Netzwerk-Endpunkt für diese beiden Replikate erstellt und ihn mit einem NodePort-Dienst von außen zugänglich gemacht.

      Der letzte Schritt in diesem Tutorial ist die Sicherung des externen Datenverkehrs zu Ihrer Anwendung mit HTTPS. Dazu verwenden wir den in den Voraussetzungen installierten Ingress-Controller ingress-nginx und erstellen ein Ingress-Objekt, um den externen Verkehr in den Kubernetes-Dienst polls zu leiten.

      Schritt 8 — Konfigurieren von HTTPS unter Verwendung von Nginx Ingress und cert-manager

      Mit Ingresses von Kubernetes können Sie den Datenverkehr von außerhalb Ihres Kubernetes-Clusters flexibel an Dienste innerhalb Ihres Clusters leiten. Dies geschieht mit der Verwendung von Ingress-Objekten, die Regeln für das Routing von HTTP- und HTTPS-Verkehr zu Kubernetes-Diensten definieren, und Ingress-Controllern, die die Regeln umsetzen, indem sie den Verkehr durch Lastverteilung an die entsprechenden Backend-Dienste weiterleiten.

      In den Voraussetzungen haben den Ingress-Controller ingress-nginx und das TLS-Zertifizierungsautomatisierungs-Add-on cert-manager installiert. Außerdem haben Sie die Staging- und Produktions-ClusterIssuers für Ihre Domäne unter Verwendung der Zertifizierungsstelle Let’s Encrypt eingerichtet und einen Ingress erstellt, um die Ausstellung von Zertifikaten und die TLS-Verschlüsselung für zwei Dummy-Backend-Dienste zu testen. Bevor Sie mit diesem Schritt fortfahren, sollten Sie den in dem Voraussetzungs-Tutorial erstellten Ingress echo-ingress löschen:

      • kubectl delete ingress echo-ingress

      Wenn Sie möchten, können Sie auch die Dummy-Dienste und -Deployments mit kubectl delete svc und kubectl delete delploy löschen, aber dies ist für die Durchführung des Tutorials nicht unbedingt erforderlich.

      Sie sollten auch einen DNS-A-Datensatz mit your_domain.com erstellt haben, der auf die öffentliche IP-Adresse des Ingress Load Balancers verweist. Wenn Sie einen DigitalOcean Load Balancer verwenden, finden Sie diese IP-Adresse im Abschnitt Load Balancers des Bedienfelds. Wenn Sie DigitalOcean auch für die Verwaltung der DNS-Datensätze Ihrer Domäne verwenden, konsultieren Sie bitte Verwalten von DNS-Datensätzen, um zu erfahren, wie Sie A-Datensätze erstellen.

      Wenn Sie DigitalOcean Kubernetes verwenden, stellen Sie außerdem sicher, dass Sie die in Schritt 5 von Einrichten eines Nginx-Ingress mit Cert-Manager unter DigitalOcean Kubernetes beschriebene Problemumgehung umgesetzt haben.

      Sobald Sie einen A-Datensatz haben, der auf den Ingress Controller Load Balancer verweist, können Sie einen Ingress für your_domain.com und den Dienst polls erstellen.

      Öffnen Sie eine Datei namens polls-ingress.yaml mit Ihrem bevorzugten Editor:

      Fügen Sie das folgende Ingress-Manifest ein:

      [polls-ingress.yaml]
      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: polls-ingress
        annotations:
          kubernetes.io/ingress.class: "nginx"
          cert-manager.io/cluster-issuer: "letsencrypt-staging"
      spec:
        tls:
        - hosts:
          - your_domain.com
          secretName: polls-tls
        rules:
        - host: your_domain.com
          http:
            paths:
            - backend:
                serviceName: polls
                servicePort: 8000
      

      Wir erstellen ein Ingress-Objekt namens polls-ingress und annotieren es, um die Steuerungsebene anzuweisen, den Ingress-Controller ingress-nginx und den ClusterIssuer „staging“ zu verwenden. Außerdem aktivieren wir TLS für your_domain.com und speichern das Zertifikat und den privaten Schlüssel in einem Secret namens polls-tls. Schließlich definieren wir eine Regel, um den Verkehr für den Host your_domain.com an den Dienst polls auf Port 8000 zu leiten.

      Wenn Sie mit der Bearbeitung der Datei fertig sind, speichern und schließen Sie sie.

      Erstellen Sie den Ingress in Ihrem Cluster mit kubectl apply:

      • kubectl apply -f polls-ingress.yaml

      Output

      ingress.networking.k8s.io/polls-ingress created

      Sie können kubectl describe verwenden, um den Status des soeben erstellten Ingress zu verfolgen:

      • kubectl describe ingress polls-ingress

      Output

      Name: polls-ingress Namespace: default Address: workaround.your_domain.com Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) TLS: polls-tls terminates your_domain.com Rules: Host Path Backends ---- ---- -------- your_domain.com polls:8000 (10.244.0.207:8000,10.244.0.53:8000) Annotations: cert-manager.io/cluster-issuer: letsencrypt-staging kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 51s nginx-ingress-controller Ingress default/polls-ingress Normal CreateCertificate 51s cert-manager Successfully created Certificate "polls-tls" Normal UPDATE 25s nginx-ingress-controller Ingress default/polls-ingress

      Sie können auch describe für das Zertifikat polls-tls ausführen, um dessen erfolgreiche Erstellung weiter zu bestätigen:

      • kubectl describe certificate polls-tls

      Output

      . . . Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Issuing 3m33s cert-manager Issuing certificate as Secret does not exist Normal Generated 3m32s cert-manager Stored new private key in temporary Secret resource "polls-tls-v9lv9" Normal Requested 3m32s cert-manager Created new CertificateRequest resource "polls-tls-drx9c" Normal Issuing 2m58s cert-manager The certificate has been successfully issued

      Dies bestätigt, dass das TLS-Zertifikat erfolgreich ausgestellt wurde und die HTTPS-Verschlüsselung nun für your_domain.com aktiv ist.

      Da wir den Staging-ClusterIssuer verwendet haben, werden die meisten Webbrowser dem gefälschten Let’s Encrypt-Zertifikat nicht vertrauen, das es ausgestellt hat, sodass die Navigation zu your_domain.com Sie zu einer Fehlerseite führt.

      Um eine Testanfrage zu senden, verwenden wir wget von der Befehlszeile aus:

      • wget -O - http://your_domain.com/polls

      Output

      . . . ERROR: cannot verify your_domain.com's certificate, issued by ‘CN=Fake LE Intermediate X1’: Unable to locally verify the issuer's authority. To connect to your_domain.com insecurely, use `--no-check-certificate'.

      Wir verwenden das vorgeschlagene Flag --no-check-certificate, um die Zertifikatsprüfung zu umgehen:

      • wget --no-check-certificate -q -O - http://your_domain.com/polls

      Output

      <link rel="stylesheet" type="text/css" href="https://your_space.nyc3.digitaloceanspaces.com/django-polls/static/polls/style.css"> <p>No polls are available.</p>

      Diese Ausgabe zeigt das HTML für die Benutzeroberflächenseite /polls und bestätigt auch, dass das Stylesheet aus dem Objektspeicher bedient wird.

      Nachdem Sie nun die Zertifikatausstellung mit dem Staging-ClusterIssuer erfolgreich getestet haben, können Sie den Ingress ändern, um den ClusterIssuer, zu verwenden.

      Öffnen Sie polls-ingress.yaml zur erneuten Bearbeitung:

      Ändern Sie die Annotation cluster-issuer:

      [polls-ingress.yaml]
      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: polls-ingress
        annotations:
          kubernetes.io/ingress.class: "nginx"
          cert-manager.io/cluster-issuer: "letsencrypt-prod"
      spec:
        tls:
        - hosts:
          - your_domain.com
          secretName: polls-tls
        rules:
        - host: your_domain.com
          http:
            paths:
            - backend:
                serviceName: polls
                servicePort: 8000
      

      Wenn Sie fertig sind, speichern und schließen Sie die Datei. Aktualisieren Sie den Ingress mit kubectl apply:

      • kubectl apply -f polls-ingress.yaml

      Output

      ingress.networking.k8s.io/polls-ingress configured

      Um den Status der Zertifikatausstellung zu verfolgen, können Sie kubectl describe certificate polls-tls und kubectl describe ingress polls-ingress verwenden:

      • kubectl describe ingress polls-ingress

      Output

      . . . Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 23m nginx-ingress-controller Ingress default/polls-ingress Normal CreateCertificate 23m cert-manager Successfully created Certificate "polls-tls" Normal UPDATE 76s (x2 over 22m) nginx-ingress-controller Ingress default/polls-ingress Normal UpdateCertificate 76s cert-manager Successfully updated Certificate "polls-tls"

      Die obige Ausgabe bestätigt, dass das neue Produktionszertifikat erfolgreich ausgestellt und im Secret polls-tls gespeichert wurde.

      Navigieren Sie in Ihrem Webbrowser zu your_domain.com/polls, um zu bestätigen, dass die HTTPS-Verschlüsselung aktiviert ist und alles wie erwartet funktioniert. Sie sollten die Oberfläche der Umfrageanwendung sehen:

      Oberfläche der Umfrageanwendung

      Überprüfen Sie, ob die HTTPS-Verschlüsselung in Ihrem Webbrowser aktiv ist. Wenn Sie Google Chrome verwenden, bestätigt die Ankunft auf der obigen Seite ohne Fehler, dass alles korrekt funktioniert. Außerdem sollten Sie ein Vorhängeschloss in der URL-Leiste sehen. Durch Klicken auf das Vorhängeschloss können Sie die Details des Let’s Encrypt-Zertifikats einsehen.

      Als letzte Bereinigungsaufgabe können Sie optional den Typ des Dienstes polls von NodePort auf den nut internen Typ ClusterIP umstellen.

      Ändern Sie polls-svc.yaml mit Ihrem Editor:

      Ändern Sie den type von NodePort auf ClusterIP:

      polls-svc.yaml

      apiVersion: v1
      kind: Service
      metadata:
        name: polls
        labels:
          app: polls
      spec:
        type: ClusterIP
        selector:
          app: polls
        ports:
          - port: 8000
            targetPort: 8000
      

      Wenn Sie mit der Bearbeitung der Datei fertig sind, speichern und schließen Sie sie.

      Stellen Sie die Änderungen mit kubectl apply bereit:

      • kubectl apply -f polls-svc.yaml --force

      Output

      service/polls configured

      Bestätigen Sie mit kubectl get svc, dass Ihr Dienst geändert wurde:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE polls ClusterIP 10.245.203.186 <none> 8000/TCP 22s

      Diese Ausgabe zeigt, dass der Diensttyp nun ClusterIP ist. Der einzige Weg darauf zuzugreifen, ist über Ihre Domäne und den in diesem Schritt erstellten Ingress.

      Zusammenfassung

      In diesem Tutorial haben Sie eine skalierbare HTTPS-gesicherte Django-Anwendung in einem Kubernetes-Cluster bereitgestellt. Statische Inhalte werden direkt aus dem Objektspeicher bedient, und die Anzahl der laufenden Pods kann über das Feld replicas in dem Deployment-Manifest polls-app schnell herauf- oder herunterskaliert werden.

      Wenn Sie einen DigitalOcean Space verwenden, können Sie auch die Bereitstellung statischer Assets über ein Content Delivery-Netzwerk aktivieren und eine benutzerdefinierte Subdomäne für Ihren Space erstellen. Lesen Sie bitte Aktivieren von CDN aus Einrichten einer skalierbaren Django-Anwendung mit von DigitalOcean verwalteten Datenbanken und Spaces, um mehr zu erfahren.

      Um den Rest der zu lesen, besuchen Sie bitte unsere Seite Von Containern zu Kubernetes mit Django.



      Source link

      Skalieren und Sichern einer Django-Anwendung mit Docker, Nginx und Let’s Encrypt


      Einführung

      In cloudbasierten Umgebungen gibt es mehrere Möglichkeiten, eine Django-Anwendung zu skalieren und zu sichern. Durch horizontale Skalierung und die Ausführung mehrerer Kopien Ihrer Anwendung können Sie ein fehlertolerantes und hochverfügbares System aufbauen und gleichzeitig den Durchsatz erhöhen, sodass Anfragen gleichzeitig verarbeitet werden können. Eine Möglichkeit zur horizontalen Skalierung einer Django-Anwendung besteht darin, zusätzliche App-Server bereitzustellen, die Ihre Django-Anwendung und Ihren WSGI-HTTP-Server (wie Gunicorn oder uWSGI) ausführen. Um eingehende Anfragen über diesen Satz von App-Servern zu leiten und zu verteilen, können Sie einen Load Balancer und Reverse Proxy wie Nginx verwenden. Nginx kann auch statische Inhalte zwischenspeichern und Transport Layer Security-Verbindungen (TLS-Verbindungen) beenden, die zur Bereitstellung von HTTPS- und sicheren Verbindungen zu Ihrer Anwendung verwendet werden.

      Die Ausführung Ihrer Django-Anwendung und des Nginx-Proxys innerhalb von Docker-Containern stellt sicher, dass sich diese Komponenten unabhängig von der Umgebung, in der sie bereitgestellt werden, gleich verhalten. Darüber hinaus bieten Container viele Funktionen, die das Paketieren und Konfigurieren Ihrer Anwendung erleichtern.

      In diesem Tutorial skalieren Sie eine containerisierte Django- und Gunicorn-Umfrageanwendung horizontal, indem Sie zwei App-Server bereitstellen, die jeweils eine Kopie eines Django- und Gunicorn-Anwendungscontainers ausführen.

      Des Weiteren aktivieren Sie HTTPS, indem Sie einen dritten Proxy-Server bereitstellen und konfigurieren, auf dem ein Nginx Reverse-Proxy-Container und ein Certbot-Client-Container ausgeführt werden. Certbot stellt TLS-Zertifikate für Nginx von der Let’s Encrypt Zertifizierungsstelle bereit. Dadurch wird sichergestellt, dass Ihre Website von SSL Labs eine hohe Sicherheitsbewertung erhält. Dieser Proxy-Server empfängt alle externen Anfragen Ihrer Anwendung und sitzt vor den beiden upstream Django-App-Servern. Schließlich härten Sie dieses verteilte System ab, indem Sie den externen Zugriff auf nur den Proxy-Server beschränken.

      Voraussetzungen

      Um dieser Anleitung zu folgen, benötigen Sie:

      • Drei Ubuntu 18.04-Server:

        • Zwei Server werden App-Server sein, die zum Ausführen Ihrer Django- und Gunicorn-Anwendung verwendet werden.
        • Ein Server wird ein Proxy-Server sein, auf dem Nginx und Certbot ausgeführt werden.
        • Alle Server sollten einen Nicht-Root-Benutzer mit sudo-Berechtigungen und eine aktive Firewall haben. Eine Anleitung für das Setup finden Sie im Leitfaden für die Ersteinrichtung des Servers.
      • Auf allen drei Servern installiertes Docker. Eine Anleitung zur Installation von Docker finden Sie in den Schritten 1 und 2 von Installieren und Verwenden von Docker unter Ubuntu 18.04.

      • Einen registrierten Domänennamen. In diesem Tutorial wird durchgängig your_domain.com verwendet. Einen Domänennamen können Sie kostenlos bei Freenom erhalten oder Sie nutzen eine Domänenregistrierungsstelle Ihrer Wahl.

      • Einen DNS-A-Eintrag mit your-domain.com, der auf die öffentliche IP-Adresse Ihres Proxy-Servers verweist. Falls Sie ein DigitalOcean-Konto nutzen, können Sie in dieser Einführung in DigitalOcean-DNS im Einzelnen nachlesen, wie Sie ihn hinzufügen.

      • Einen S3-Objektspeicher-Bucket wie beispielsweise einen DigitalOcean Space zur Speicherung der statischen Dateien Ihres Django-Projekts und einen Satz von Zugriffsschlüsseln für diesen Space. Um zu erfahren, wie Sie einen Space erstellen können, lesen Sie die Produktdokumentation Erstellen von Spaces. Um zu erfahren, wie Sie Zugriffsschlüssel für Spaces erstellen können, lesen Sie Zugriff auf Spaces mit Zugriffsschlüsseln gemeinsam nutzen. Mit geringfügigen Änderungen können Sie jeden Objektspeicherdienst verwenden, der das Plugin django-storages verwendet.

      • Eine PostgreSQL-Server-Instanz, Datenbank und Benutzer für Ihre Django-Anwendung. Mit geringfügigen Änderungen können Sie jede Datenbank verwenden, die Django unterstützt.

      Schritt 1 – Konfigurieren des ersten Django-App-Servers

      Wir klonen zunächst das Django-Anwendungs-Repository auf den ersten App-Server. Dann konfigurieren und erstellen wir das Docker-Image und testen die Anwendung durch Ausführung des Django-Containers.

      Anmerkung: Wenn Sie von Erstellen einer Django- und Gunicorn-Anwendung mit Docker fortfahren, haben Sie Schritt 1 bereits abgeschlossen und können mit Schritt 2 fortfahren, um den zweiten App-Server zu konfigurieren.

      Beginnen Sie mit der Anmeldung beim ersten der beiden Django-App-Server und verwenden Sie git, um den Zweig polls-docker der Django Tutorial Umfrageanwendung GitHub-Repository zu klonen. Dieses Repository enthält Code für die Umfrage-Beispielanwendung der Django-Dokumentation. Der Zweig polls-docker enthält eine dockerisierte Version der Umfrageanwendung. Um zu erfahren, wie die Umfrageanwendung modifiziert wurde, um effektiv in einer containerisierten Umgebung zu arbeiten, lesen Sie bitte Erstellen einer Django- und Gunicorn-Anwendung mit Docker.

      • git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

      Navigieren Sie in das Verzeichnis django-polls:

      cd django-polls
      

      Dieses Verzeichnis enthält den Python-Code der Django-Anwendung, ein Dockerfile, das Docker zum Erstellen des Container-Images verwendet, sowie eine Datei env, die eine Liste von Umgebungsvariablen enthält, die an die laufende Umgebung des Containers übergeben werden müssen. Prüfen Sie das Dockerfile mit cat:

      cat Dockerfile
      

      Output

      FROM python:3.7.4-alpine3.10 ADD django-polls/requirements.txt /app/requirements.txt RUN set -ex && apk add --no-cache --virtual .build-deps postgresql-dev build-base && python -m venv /env && /env/bin/pip install --upgrade pip && /env/bin/pip install --no-cache-dir -r /app/requirements.txt && runDeps="$(scanelf --needed --nobanner --recursive /env | awk '{ gsub(/,/, "nso:", $2); print "so:" $2 }' | sort -u | xargs -r apk info --installed | sort -u)" && apk add --virtual rundeps $runDeps && apk del .build-deps ADD django-polls /app WORKDIR /app ENV VIRTUAL_ENV /env ENV PATH /env/bin:$PATH EXPOSE 8000 CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "mysite.wsgi"]

      Dieses Dockerfile verwendet das offizielle Python 3.7.4 Docker-Image als Basis und installiert die Python-Paketanforderungen von Django und Gunicorn, wie sie in der Datei django-polls/requirements.txt definiert sind. Anschließend entfernt es einige unnötige Builddateien, kopiert den Anwendungscode in das Image und legt den Ausführungspfad PATH fest. Schließlich gibt es an, dass Port 8000 verwendet wird, um eingehende Container-Verbindungen zu akzeptieren und gunicorn mit 3 Workern ausgeführt wird, die Port 8000 abhören.

      Um mehr über die einzelnen Schritte in diesem Dockerfile zu erfahren, lesen Sie bitte Schritt 6 von Erstellen einer Django- und Gunicorn-Anwendung mit Docker.

      Erstellen Sie nun das Image mit docker build:

      Wir benennen das Image polls mit dem Flag -t und übergeben im aktuellen Verzeichnis als Build-Kontext den Satz von Daten, auf den beim Erstellen des Images verwiesen werden soll.

      Nachdem Docker das Image erstellt und mit Tags versehen hat, listen wir die verfügbaren Images mit docker images auf:

      docker images
      

      Sie sollten die polls-Images aufgelistet sehen:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE polls latest 80ec4f33aae1 2 weeks ago 197MB python 3.7.4-alpine3.10 f309434dea3a 8 months ago 98.7MB

      Bevor wir den Django-Container ausführen, müssen wir seine Betriebsumgebung mithilfe der im aktuellen Verzeichnis vorhandenen Datei env konfigurieren. Diese Datei wird an den Befehl docker run übergeben, der zum Ausführen des Containers verwendet wird, und Docker injiziert die konfigurierten Umgebungsvariablen in die Betriebsumgebung des Containers.

      Öffnen Sie die Datei env mit nano oder Ihrem bevorzugten Editor:

      nano env
      

      Wir werden die Datei wie nachfolgend beschrieben konfigurieren und Sie müssen einige zusätzliche Werte hinzufügen.

      django-polls/env

      DJANGO_SECRET_KEY=
      DEBUG=True
      DJANGO_ALLOWED_HOSTS=
      DATABASE_ENGINE=postgresql_psycopg2
      DATABASE_NAME=polls
      DATABASE_USERNAME=
      DATABASE_PASSWORD=
      DATABASE_HOST=
      DATABASE_PORT=
      STATIC_ACCESS_KEY_ID=
      STATIC_SECRET_KEY=
      STATIC_BUCKET_NAME=
      STATIC_ENDPOINT_URL=
      DJANGO_LOGLEVEL=info
      

      Geben Sie die fehlenden Werte für die folgenden Schlüssel ein:

      • DJANGO_SECRET_KEY: Setzen Sie diesen auf einen eindeutigen, nicht vorhersagbaren Wert, wie in den Django-Dokumentationen beschrieben. Eine Methode zur Generierung dieses Wertes wird in Anpassen der Anwendungseinstellungen in dem Tutorial Skalierbare Django-Anwendung angeboten.
      • DJANGO_ALLOWED_HOSTS: Diese Variable sichert die Anwendung und verhindert HTTP-Host-Header-Angriffe. Setzen Sie diese Variable für Testzwecke auf *, einen Platzhalter, der auf alle Hosts zutrifft. In der Produktion sollten Sie diese Variable auf your_domain.com setzen. Um mehr über diese Django-Einstellungen zu erfahren, konsultieren Sie die Core-Einstellungen der Django-Dokumentation.
      • DATABASE_USERNAME: Setzen Sie diesen auf den in den vorbereitenden Schritten erstellten PostgreSQL Datenbankbenutzer.
      • DATABASE_NAME: Setzen Sie diesen auf polls oder den in den vorbereitenden Schritten erstellten Namen der PostgreSQL-Datenbank.
      • DATABASE_PASSWORD: Setzen Sie dieses auf das in den vorbereitenden Schritten erstellte Passwort für den PostgreSQL Benutzer.
      • DATABASE_HOST: Setzen Sie diesen Wert auf den Hostnamen Ihrer Datenbank.
      • DATABASE_PORT: Setzen Sie diesen Wert auf den Port Ihrer Datenbank.
      • STATIC_ACCESS_KEY_ID: Setzen Sie diesen Wert auf den Zugriffsschlüssel Ihres S3-Buckets oder Space.
      • STATIC_SECRET_KEY: Setzen Sie diesen Wert auf das Zugriffsschlüsselgeheimnis Ihres S3-Bucket oder Space
      • STATIC_BUCKET_NAME: Setzen Sie diesen auf Ihren S3-Bucket- oder Space-Namen.
      • STATIC_ENDPOINT_URL: Setzen Sie diese auf die entsprechenden S3-Bucket- oder Space-Endpunkt-URL, z.B. https://space-name.nyc3.digitaloceanspaces.com, wenn sich Ihr Space in der Region nyc3 befindet.

      Wenn Sie die Bearbeitung abgeschlossen haben, speichern und schließen Sie die Datei.

      Wir verwenden nun docker run, um den CMD-Satz in dem Dockerfile zu überschreiben und das Datenbankschema mit den Befehlen manage.py makemigrations und manage.py migrate zu erstellen:

      docker run --env-file env polls sh -c "python manage.py makemigrations && python manage.py migrate"
      

      Wir führen das Container-Image polls:latest aus, übergeben die von uns gerade modifizierte Umgebungsvariablendatei und überschreiben den Dockerfile-Befehl mit sh -c "python manage.py makemigrations && python manage.py migrate", wodurch das durch den Anwendungscode definierte Datenbankschema erstellt wird. Wenn Sie dies zum ersten Mal ausführen, sollten Sie Folgendes sehen:

      Output

      No changes detected Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying polls.0001_initial... OK Applying sessions.0001_initial... OK

      Dies zeigt an, dass das Datenbankschema erfolgreich erstellt wurde.

      Wenn Sie die Migration zu einem späteren Zeitpunkt ausführen, führt Django eine Nulloperation durch, es sei denn, das Datenbankschema wurde geändert.

      Als Nächstes führen wir eine weitere Instanz des Anwendungscontainers aus und verwenden darin eine interaktive Shell, um einen Administratorbenutzer für das Django-Projekt zu erstellen.

      docker run -i -t --env-file env polls sh
      

      Dadurch erhalten Sie eine Shell-Eingabeaufforderung innerhalb des laufenden Containers, die Sie zum Erstellen des Django-Benutzers verwenden können:

      python manage.py createsuperuser
      

      Geben Sie einen Benutzernamen, eine E-Mail-Adresse und ein Passwort für Ihren Benutzer ein. Drücken Sie nach dem Erstellen des Benutzers STRG+D, um den Container zu verlassen und zu beenden.

      Schließlich generieren wir die statischen Dateien für die Anwendung und laden sie mit collectstatic in den DigitalOcean Space hoch. Beachten Sie, dass dies möglicherweise einige Zeit dauern kann.

      docker run --env-file env polls sh -c "python manage.py collectstatic --noinput"
      

      Nachdem diese Dateien generiert und hochgeladen sind, erhalten Sie folgende Ausgabe.

      Output

      121 static files copied.

      Wir können die Anwendung nun ausführen:

      docker run --env-file env -p 80:8000 polls
      

      Output

      [2019-10-17 21:23:36 +0000] [1] [INFO] Starting gunicorn 19.9.0 [2019-10-17 21:23:36 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1) [2019-10-17 21:23:36 +0000] [1] [INFO] Using worker: sync [2019-10-17 21:23:36 +0000] [7] [INFO] Booting worker with pid: 7 [2019-10-17 21:23:36 +0000] [8] [INFO] Booting worker with pid: 8 [2019-10-17 21:23:36 +0000] [9] [INFO] Booting worker with pid: 9

      Hier führen wir den in dem Dockerfile definierten Standardbefehl gunicorn ---bind :8000 --workers 3 mysite.wsgi:application aus und stellen den Container-Port 8000 frei, sodass Port 80 auf dem Ubuntu-Server dem Port 8000 des Containers poll zugeordnet wird.

      Sie sollten nun über Ihren Webbrowser zu der Anwendung polls navigieren können, indem Sie http://APP_SERVER_1_IP in der URL-Leiste eingeben. Da für den Pfad / keine Route definiert ist, erhalten Sie wahrscheinlich einen 404 Page Not Found-Fehler, der zu erwarten ist.

      Warnung: Wenn Sie die UFW-Firewall mit Docker verwenden, umgeht Docker alle konfigurierten UFW-Firewallregeln, wie in diesem GitHub-Problem dokumentiert. Dies erklärt, warum Sie Zugriff auf Port 80 Ihres Servers haben, obwohl Sie in keinem vorbereitenden Schritt explizit eine UFW-Zugriffsregel erstellt haben. In Schritt 5 werden wir diese Sicherheitslücke schließen, indem wir die UFW-Konfiguration patchen. Wenn Sie UFW nicht verwenden und die Cloud Firewalls von DigitalOcean einsetzen, können Sie diese Warnung getrost ignorieren.

      Navigieren Sie zu http://APP_SERVER_1_IP/polls, um die Benutzeroberfläche der Umfrageanwendung zu sehen:

      Oberfläche der Umfrageanwendung

      Um die administrative Oberfläche anzuzeigen, besuchen Sie http://APP_SERVER_1_IP/admin. Sie sollten das Authentifizierungsfenster für den Administrator der Umfrageanwendung sehen:

      Authentifizierungsseite für Polls-Administrator

      Geben Sie den administrativen Benutzernamen und das Passwort ein, das Sie mit dem Befehl createsuperuser erstellt haben.

      Nach der Authentifizierung können Sie auf die administrative Oberfläche der Umfrageanwendung zugreifen:

      Administrative Hauptoberfläche von Polls

      Beachten Sie, dass statische Assets für die Anwendungen admin und polls direkt aus dem Objektspeicher bereitgestellt werden. Um dies zu bestätigen, konsultieren Sie Prüfen der statischen Dateizustellung von Spaces.

      Wenn Sie die Erkundung abgeschlossen haben, drücken Sie Strg+C im Terminalfenster, in dem der Docker-Container ausgeführt wird, um den Container zu beenden.

      Nachdem Sie nun bestätigt haben, dass der App-Container wie erwartet ausgeführt wird, können Sie ihn im getrennten (detached) Modus ausführen, wodurch er im Hintergrund ausgeführt wird und Ihnen ermöglicht, sich von Ihrer SSH-Sitzung abzumelden:

      docker run -d --rm --name polls --env-file env -p 80:8000 polls
      

      Das Flag -d weist Docker an, den Container im getrennten Modus auszuführen, das Flag -rm säubert das Dateisystem des Containers nach dem Verlassen des Containers und wir benennen den Container polls.

      Melden Sie sich von dem ersten Django App-Server ab und navigieren Sie zu http://APP_SERVER_1_IP/polls, um zu bestätigen, dass der Container wie erwartet ausgeführt wird.

      Nachdem Ihr erster Django-App-Server ausgeführt wird, können Sie nun Ihren zweiten Django-App-Server einrichten.

      Schritt 2 – Konfigurieren des zweiten Django-App-Servers

      Da viele der Befehle zur Einrichtung dieses Servers die gleichen sind wie im vorherigen Schritt, werden sie hier in abgekürzter Form dargestellt. Bitte lesen Sie Schritt 1 für weitere Informationen zu einem bestimmten Befehl in diesem Schritt.

      Beginnen Sie damit, sich bei dem zweiten Django-App-Server anzumelden.

      Klonen Sie den Zweig polls-docker des GitHub-Repositorys von django-polls:

      • git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

      Navigieren Sie in das Verzeichnis django-polls:

      cd django-polls
      

      Erstellen Sie das Image mit docker build:

      Öffnen Sie die Datei env mit nano oder Ihrem bevorzugten Editor:

      nano env
      

      django-polls/env

      DJANGO_SECRET_KEY=
      DEBUG=True
      DJANGO_ALLOWED_HOSTS=
      DATABASE_ENGINE=postgresql_psycopg2
      DATABASE_NAME=polls
      DATABASE_USERNAME=
      DATABASE_PASSWORD=
      DATABASE_HOST=
      DATABASE_PORT=
      STATIC_ACCESS_KEY_ID=
      STATIC_SECRET_KEY=
      STATIC_BUCKET_NAME=
      STATIC_ENDPOINT_URL=
      DJANGO_LOGLEVEL=info
      

      Geben Sie die fehlenden Werte wie in Schritt 1 ein. Wenn Sie die Bearbeitung abgeschlossen haben, speichern und schließen Sie die Datei.

      Führen Sie den App-Container anschließend im getrennten Modus aus:

      docker run -d --rm --name polls --env-file env -p 80:8000 polls
      

      Navigieren Sie zu http://APP_SERVER_2_IP/polls, um zu bestätigen, dass der Container wie erwartet ausgeführt wird. Sie können sich sicher von dem zweiten App-Server anmelden, ohne Ihren laufenden Container zu beenden.

      Da beide Django App-Container ausgeführt werden, können Sie mit der Konfiguration des Reverse-Proxy-Containers von Nginx fortfahren.

      Schritt 3 – Konfigurieren des Nginx Docker-Containers

      Nginx ist ein vielseitiger Webserver, der eine Reihe von Funktionen wie Reverse-Proxying, Load Balancing und Caching bietet. In diesem Tutorial haben wir die statischen Assets von Django in den Objektspeicher ausgelagert, sodass wir die Caching-Funktionen von Nginx nicht verwenden werden. Wir werden Nginx jedoch als Reverse-Proxy für unsere beiden Backend-Django-App-Server verwenden und eingehende Anfragen zwischen ihnen verteilen. Darüber hinaus wird Nginx TLS-Terminierung und -Umleitung unter Verwendung eines von Certbot bereitgestellten TLS-Zertifikats durchführen. Das bedeutet, dass es die Clients zwingen wird, HTTPS zu verwenden, und eingehende HTTPS-Anfragen an Port 443 umzuleiten. Anschließend entschlüsselt Nginx HTTPS-Anfragen und leitet sie an die vorgelagerten Django-Server weiter.

      In diesem Tutorial haben wir die Designentscheidung getroffen, die Nginx-Container von den Backend-Servern zu entkoppeln. Abhängig von Ihrem Anwendungsfall können Sie sich dafür entscheiden, den Nginx-Container auf einem der Django-App-Server auszuführen, das Proxying von Anfragen sowohl lokal als auch auf dem anderen Django-Server auszuführen. Eine weitere mögliche Architektur wäre die Ausführung von zwei Nginx-Containern, einer auf jedem Backend-Server, mit einem Cloud Load Balancer davor. Jede Architektur bietet andere Sicherheits- und Leistungsvorteile und Sie sollten Ihr System einem Lasttest unterziehen, um Engpässe aufzudecken. Die in diesem Tutorial beschriebene flexible Architektur ermöglicht es Ihnen, sowohl die Backend-Django-Anwendungsschicht als auch die Nginx-Proxying-Schicht zu skalieren. Sobald der einzelne Nginx-Container zum Engpass wird, können Sie auf mehrere Nginx-Proxys skalieren und einen Cloud Load Balancer oder schnellen L4 Load Balancer wie HAProxy hinzufügen.

      Da beide Django-App-Server ausgeführt werden, können wir mit dem Einrichten des Proxy-Servers beginnen. Melden Sie sich an Ihrem Proxy-Server an und erstellen Sie ein Verzeichnis namens conf:

      mkdir conf
      

      Erstellen Sie mit nano oder Ihrem bevorzugten Editor eine Konfigurationsdatei namens nginx.conf:

      nano conf/nginx.conf
      

      Fügen Sie die folgende Nginx-Konfiguration ein:

      conf/nginx.conf

      
      upstream django {
          server APP_SERVER_1_IP;
          server APP_SERVER_2_IP;
      }
      
      server {
          listen 80 default_server;
          return 444;
      }
      
      server {
          listen 80;
          listen [::]:80;
          server_name your_domain.com;
          return 301 https://$server_name$request_uri;
      }
      
      server {
          listen 443 ssl http2;
          listen [::]:443 ssl http2;
          server_name your_domain.com;
      
          # SSL
          ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
          ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
      
          ssl_session_cache shared:le_nginx_SSL:10m;
          ssl_session_timeout 1440m;
          ssl_session_tickets off;
      
          ssl_protocols TLSv1.2 TLSv1.3;
          ssl_prefer_server_ciphers off;
      
          ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
      
          client_max_body_size 4G;
          keepalive_timeout 5;
      
              location / {
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Host $http_host;
                proxy_redirect off;
                proxy_pass http://django;
              }
      
          location ^~ /.well-known/acme-challenge/ {
              root /var/www/html;
          }
      
      }
      

      Diese Blöcke upstream, server und location konfigurieren Nginx so, dass HTTP-Anfragen an HTTPS umgeleitet werden und sorgen für einen Lastausgleich zwischen den beiden in Schritt 1 und 2 konfigurierten Django-App-Servern. Um mehr über die Nginx-Konfigurationsdatei zu erfahren, lesen Sie bitte in diesem Artikel über das Verstehen der Nginx-Konfigurationsdateistruktur und der Konfigurationskontexte. Außerdem kann dieser Artikel zum Verstehen von Nginx-Server und Location-Block-Auswahlalgorithmen hilfreich sein.

      Diese Konfiguration wurde aus Beispielkonfigurationsdateien zusammengestellt, die von Gunicorn, Certbot und Nginx bereitgestellt wurden, und ist als eine minimale Nginx-Konfiguration gedacht, um diese Architektur betriebsbereit zu machen. Die Feineinstellung dieser Nginx-Konfiguration geht über den Umfang dieses Artikels hinaus, Sie können jedoch ein Tool wie NGINXConfig verwenden, um performante und sichere Nginx-Konfigurationsdateien für Ihre Architektur zu generieren.

      Der Block upstream definiert die Gruppe von Servern, die zum Proxying von Anfragen zur Verwendung der Anweisung proxy_pass verwendet werden:

      conf/nginx.conf

      upstream django {
          server APP_SERVER_1_IP;
          server APP_SERVER_2_IP;
      }
      . . .
      

      In diesem Block nennen wir den upstream django und schließen die IP-Adressen der beiden Django-App-Server ein. Wenn die App-Server auf DigitalOcean ausgeführt werden und VPC Networking aktiviert haben, sollten Sie hier ihre privaten IP-Adressen verwenden. Um zu erfahren, wie Sie VPC-Networking auf DigitalOcean aktivieren können, lesen Sie bitte Aktivieren von VPC-Networking auf vorhandenen Droplets.

      Der erste Block server erfasst Anfragen, die nicht Ihrer Domäne entsprechen und beendet die Verbindung. Beispielsweise würde eine direkte HTTP-Anfrage an die IP-Adresse Ihres Servers von diesem Block bearbeitet werden:

      conf/nginx.conf

      . . .
      server {
          listen 80 default_server;
          return 444;
      }
      . . .
      

      Der nächste Block server leitet HTTP-Anfragen an Ihre Domäne über eine HTTP 301-Umleitung an HTTPS um. Diese Anfragen werden dann vom letzten Block server bearbeitet:

      conf/nginx.conf

      . . .
      server {
          listen 80;
          listen [::]:80;
          server_name your_domain.com;
          return 301 https://$server_name$request_uri;
      }
      . . .
      

      Diese zwei Anweisungen definieren die Pfade zum TLS-Zertifikat und geheimen Schlüssel. Diese werden mit Certbot bereitgestellt und im nächsten Schritt in den Nginx-Container eingebunden.

      conf/nginx.conf

      . . .
      ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
      . . .
      

      Bei diesen Parametern handelt es sich um die von Certbot empfohlenen SSL-Sicherheitsstandards. Um mehr über sie zu erfahren, lesen Sie bitte das Modul ngx_http_ssl_module der Nginx-Dokumentation. Mozillas Sicherheits-/Serverseitiges TLS ist ein weiterer hilfreicher Leitfaden, den Sie für die Feinabstimmung Ihrer SSL-Konfiguration verwenden können.

      conf/nginx.conf

      . . .
          ssl_session_cache shared:le_nginx_SSL:10m;
          ssl_session_timeout 1440m;
          ssl_session_tickets off;
      
          ssl_protocols TLSv1.2 TLSv1.3;
          ssl_prefer_server_ciphers off;
      
          ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
      . . .
      

      Diese beiden Anweisungen aus Gunicorns Nginx-Beispielkonfiguration legen die maximal zulässige Größe des Client-Anfragekörpers fest und weisen das Timeout für Keep-Alive-Verbindungen mit dem Client zu. Nginx schließt Verbindungen mit dem Client nach keepalive_timeout-Sekunden.

      conf/nginx.conf

      . . .
      client_max_body_size 4G;
      keepalive_timeout 5;
      . . .
      

      Der erste Block location weist Nginx zum Proxying von Anfragen über HTTP an die upstream django-Server an. Er bewahrt zusätzlich Client HTTP-Header auf, die die Ursprungs-IP-Adresse, das zur Verbindung verwendete Protokoll und den Ziel-Host erfassen:

      conf/nginx.conf

      . . .
      location / {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Host $http_host;
          proxy_redirect off;
          proxy_pass http://django;
      }
      . . .
      

      Um mehr über diese Anweisungen zu erfahren, lesen Sie bitte Bereitstellen von Gunicorn und das Modul ngx_http_proxy_module der Nginx-Dokumentation.

      Der letzte Block location erfasst Anfragen an den Pfad /well-known/acme-Challenge/, der von Certbot für HTTP-01-Challenges verwendet wird, um Ihre Domäne mit Let’s Encrypt zu verifizieren und TLS-Zertifikate bereitzustellen oder zu erneuern. Weitere Informationen über die von Certbot verwendete HTTP-01-Challenge finden Sie unter Challenge-Arten in der Let’s Encrypt-Dokumentation.

      conf/nginx.conf

      . . .
      location ^~ /.well-known/acme-challenge/ {
              root /var/www/html;
      }
      

      Wenn Sie die Bearbeitung abgeschlossen haben, speichern und schließen Sie die Datei.

      Sie können diese Konfigurationsdatei nun verwenden, um einen Nginx Docker-Container auszuführen. In diesem Tutorial verwenden wir das Image nginx:1.19.0, Version 1.19.0 des offiziellen Docker-Images, das von Nginx verwaltet wird.

      Wenn wir den Container zum ersten Mal ausführen, wird Nginx einen Fehler ausgeben und fehlschlagen, da wir die in der Konfigurationsdatei definierten Zertifikate noch nicht bereitgestellt haben. Wir werden jedoch trotzdem den Befehl zum Herunterladen des Nginx-Images lokal ausführen und testen, ob alles andere korrekt funktioniert:

      docker run --rm --name nginx -p 80:80 -p 443:443 
          -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro 
          -v /var/www/html:/var/www/html 
          nginx:1.19.0
      

      Hier nennen wir den Container nginx und ordnen die Host-Ports 80 und 443 den jeweiligen Container-Ports zu. Das Flag -v bindet die Konfigurationsdatei unter /etc/nginx/conf.d/nginx.conf in den Nginx-Container ein, für dessen Laden das Nginx-Image vorkonfiguriert ist. Es wird im Modus ro oder „read-only“ eingebunden, sodass der Container die Datei nicht verändern kann. Das Web-Stammverzeichnis /var/www/html ist ebenfalls in den Container eingebunden. Schließlich weist nginx:1.19.0 Docker an, das Image nginx:1.19.0 aus Dockerhub zu ziehen und auszuführen.

      Docker wird das Image ziehen und ausführen, dann wird Nginx einen Fehler ausgeben, wenn es das konfigurierte TLS-Zertifikat und den geheimen Schlüssel nicht findet. Im nächsten Schritt stellen wir diese mithilfe eines dockerisierten Certbot-Clients und der Zertifizierungsstelle Let’s Encrypt bereit.

      Schritt 4 – Konfigurieren von Certbot und Let’s Encrypt-Zertifikaterneuerung

      Certbot ist ein Let’s Encrypt-Client, der von der Electronic Frontier Foundation entwickelt wurde. Er stellt kostenlose TLS-Zertifikate von der Let’s Encrypt-Zertifizierungsstelle zur Verfügung, mit denen Browser die Identität Ihrer Webserver überprüfen können. Da wir auf unserem Nginx-Proxy-Server Docker installiert haben, verwenden wir das Certbot Docker-Image zur Bereitstellung und Erneuerung der TLS-Zertifikate.

      Stellen Sie zunächst sicher, dass Sie über einen DNS-A-Eintrag verfügen, der der öffentlichen IP-Adresse des Proxy-Servers zugeordnet ist. Stellen Sie dann auf Ihrem Proxy-Server eine Staging-Version der Zertifikate unter Verwendung des Docker-Images certbot bereit:

      docker run -it --rm -p 80:80 --name certbot 
               -v "/etc/letsencrypt:/etc/letsencrypt" 
               -v "/var/lib/letsencrypt:/var/lib/letsencrypt" 
               certbot/certbot certonly --standalone --staging -d your_domain.com
      

      Dieser Befehl führt das certbot Docker-Image im interaktiven Modus aus und leitet Port 80 auf dem Host an den Container-Port 80 weiter. Er erstellt zwei Host-Verzeichnisse und bindet sie in die Container ein: /etc/letsencrypt/ und /var/lib/letsencrypt/. certbot wird im Modus standalone ohne Nginx ausgeführt und verwendet die Staging-Server von Let’s Encrypt, um die Domänenvalidierung durchzuführen.

      Geben Sie, wenn Sie dazu aufgefordert werden, Ihre E-Mail-Adresse ein und stimmen Sie den Nutzungsbedingungen zu. Wenn die Domänenvalidierung erfolgreich war, sollten Sie die folgende Ausgabe sehen:

      Output

      Obtaining a new certificate Performing the following challenges: http-01 challenge for stubb.dev Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/your_domain.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/your_domain.com/privkey.pem Your cert will expire on 2020-09-15. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal.

      Sie können das Zertifikat mit cat inspizieren:

      sudo cat /etc/letsencrypt/live/your_domain.com/fullchain.pem
      

      Mit dem bereitgestellten TLS-Zertifikat können wir die im vorherigen Schritt eingebundene Nginx-Konfiguration testen:

      docker run --rm --name nginx -p 80:80 -p 443:443 
          -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro 
          -v /etc/letsencrypt:/etc/letsencrypt 
          -v /var/lib/letsencrypt:/var/lib/letsencrypt 
          -v /var/www/html:/var/www/html 
          nginx:1.19.0
      

      Dies ist derselbe Befehl, der in Schritt 3 ausgeführt wurde, mit dem Hinzufügen der beiden kürzlich erstellten Let’s Encrypt-Verzeichnisse:

      Sobald Nginx ausgeführt wird, navigieren Sie zu http://your_domain.com. Möglicherweise erhalten Sie in Ihrem Browser eine Warnung, dass die Zertifizierungsstelle ungültig ist. Dies ist zu erwarten, da wir Staging-Zertifikate und keine Produktions-Let’s Encrypt-Zertifikate bereitgestellt haben. Überprüfen Sie die URL-Leiste Ihres Browsers, um zu bestätigen, dass Ihre HTTP-Anfrage an HTTPS umgeleitet wurde.

      Drücken Sie zum Beenden von Nginx in Ihrem Terminal Strg+C und führen Sie den Client certbot erneut aus, diesmal ohne das Flag --staging:

      docker run -it --rm -p 80:80 --name certbot 
               -v "/etc/letsencrypt:/etc/letsencrypt" 
               -v "/var/lib/letsencrypt:/var/lib/letsencrypt" 
               certbot/certbot certonly --standalone -d your_domain.com
      

      Wenn Sie dazu aufgefordert werden, entweder das vorhandene Zertifikat beizubehalten oder es zu erneuern und zu ersetzen, drücken Sie 2 zum Erneuern und dann ENTER, um Ihre Wahl zu bestätigen.

      Wenn das Produktions-TLS-Zertifikat bereitgestellt ist, führen Sie den Nginx-Server erneut aus:

      docker run --rm --name nginx -p 80:80 -p 443:443 
          -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro 
          -v /etc/letsencrypt:/etc/letsencrypt 
          -v /var/lib/letsencrypt:/var/lib/letsencrypt 
          -v /var/www/html:/var/www/html 
          nginx:1.19.0
      

      Navigieren Sie in Ihrem Browser zu http://your_domain.com. Bestätigen Sie in der URL-Leiste, dass die HTTP-Anfrage an HTTPS umgeleitet wurde. Da für die Umfrageanwendung keine Standardroute konfiguriert ist, sollten Sie den Django-Fehler Page not found (Seite nicht gefunden) sehen. Navigieren Sie zu https://your_domain.com/polls und Sie sehen die Standardoberfläche der Umfrageanwendung:

      Oberfläche der Umfrageanwendung

      Zu diesem Zeitpunkt haben Sie mit dem Certbot Docker-Client ein Produktions-TLS-Zertifikat bereitgestellt und externe Anfragen an die beiden Django-App-Server durch Reverse Proxying und Lastausgleich umgeleitet.

      Die Let’s Encrypt-Zertifikate laufen alle 90 Tage ab. Um sicherzustellen, dass Ihr Zertifikat gültig bleibt, sollten Sie es regelmäßig vor dessen geplantem Ablauf erneuern. Wenn Nginx ausgeführt wird, sollten Sie den Certbot-Client im Modus webroot anstelle des Modus standalone verwenden. Das bedeutet, dass Certbot die Validierung durch die Erstellung einer Datei im Verzeichnis /var/www/html/.well-known/acme-challenge/ durchführt, und die Validierungsanforderungen von Let’s Encrypt an diesen Pfad werden von der in der Nginx-Konfiguration in Schritt 3 definierten Regel location erfasst. Certbot wird dann die Zertifikate rotieren, und Sie können Nginx neu laden, sodass es dieses neu bereitgestellte Zertifikat verwendet.

      Es gibt mehrere Möglichkeiten, um dieses Verfahren zu automatisieren und die automatische Erneuerung von TLS-Zertifikaten geht über den Umfang dieses Tutorials hinaus. Ein ähnliches Verfahren unter Verwendung des Scheduling-Dienstprogramms cron finden Sie in Schritt 6 von Sichern einer containerisierten Node.js-Anwendung mit Nginx, Let’s Encrypt, und Docker Compose.

      Drücken Sie zum Beenden des Nginx-Containers in Ihrem Terminal Strg+C. Führen Sie ihn erneut im getrennten Modus aus, indem Sie das Flag -d anhängen:

      docker run --rm --name nginx -d -p 80:80 -p 443:443 
          -v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro 
          -v /etc/letsencrypt:/etc/letsencrypt 
          -v /var/lib/letsencrypt:/var/lib/letsencrypt 
        -v /var/www/html:/var/www/html 
          nginx:1.19.0
      

      Verwenden Sie mit im Hintergrund ausgeführtem Nginx den folgenden Befehl, um einen Probelauf des Zertifikatserneuerungsverfahrens auszuführen:

      docker run -it --rm --name certbot 
          -v "/etc/letsencrypt:/etc/letsencrypt" 
        -v "/var/lib/letsencrypt:/var/lib/letsencrypt" 
        -v "/var/www/html:/var/www/html" 
        certbot/certbot renew --webroot -w /var/www/html --dry-run
      

      Wir verwenden das Plugin --webroot, geben den Web-Stammpfad ein und verwenden das Flag --dry-run zum Überprüfen der ordnungsgemäßen Funktion, ohne die Zertifikatserneuerung tatsächlich durchzuführen.

      Wenn die Erneuerungssimulation erfolgreich ist, sollten Sie die folgende Ausgabe sehen:

      Output

      Cert not due for renewal, but simulating renewal for dry run Plugins selected: Authenticator webroot, Installer None Renewing an existing certificate Performing the following challenges: http-01 challenge for your_domain.com Using the webroot path /var/www/html for all unmatched domains. Waiting for verification... Cleaning up challenges - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - new certificate deployed without reload, fullchain is /etc/letsencrypt/live/your_domain.com/fullchain.pem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/your_domain.com/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

      In einer Produktionseinstellung sollten Sie nach der Erneuerung von Zertifikaten Nginx neu laden, damit die Änderungen wirksam werden. Führen Sie zum Neuladen von Nginx den folgenden Befehl aus:

      docker kill -s HUP nginx
      

      Dieser Befehl sendet ein HUP Unix-Signal an den Nginx-Prozess, der innerhalb des Docker-Containers nginx ausgeführt wird. Nach Empfang dieses Signals lädt Nginx seine Konfiguration und erneuerten Zertifikate neu.

      Wenn HTTPS aktiviert ist und alle Komponenten dieser Architektur ausgeführt werden, besteht der letzte Schritt darin, die Einrichtung zu sperren, indem der externe Zugriff auf die beiden Backend-App-Server verhindert wird; alle HTTP-Anfragen sollten über den Nginx-Proxy laufen.

      Schritt 5 – Verhindern des externen Zugriffs auf Django-App-Server

      In der in diesem Tutorial beschriebenen Architektur erfolgt die SSL-Terminierung am Nginx-Proxy. Das bedeutet, dass Nginx die SSL-Verbindung entschlüsselt und die Pakete unverschlüsselt an die Django-App-Server weitergeleitet werden. Für viele Anwendungsfälle ist diese Sicherheitsstufe ausreichend. Für Anwendungen mit Finanz- oder Gesundheitsdaten sollten Sie eventuell eine End-to-End-Verschlüsselung implementieren. Sie können dies tun, indem Sie verschlüsselte Pakete über den Load Balancer weiterleiten und auf den App-Servern entschlüsseln oder am Proxy neu verschlüsseln und auf den Django-App-Servern wieder entschlüsseln. Diese Techniken gehen über den Rahmen dieses Artikels hinaus. Um mehr zu erfahren, lesen Sie bitte End-to-End-Verschlüsselung.

      Der Nginx-Proxy fungiert als Gateway zwischen externem Datenverkehr und dem internen Netzwerk. Theoretisch sollten keine externen Clients direkten Zugriff auf die internen App-Server haben, und alle Anfragen sollten über den Nginx-Server laufen. Der Hinweis in Schritt 1 beschreibt kurz ein offenes Problem mit Docker, bei dem Docker standardmäßig die ufw-Firewalleinstellungen umgeht und Ports extern öffnet, die möglicherweise unsicher sind. Um dieses Sicherheitsproblem zu beheben wird empfohlen, bei der Arbeit mit Docker-fähigen Servern Cloud Firewalls zu verwenden. Weitere Informationen zum Erstellen von Cloud Firewalls mit DigitalOcean finden Sie unter Erstellen von Firewalls. Sie können iptables auch direkt manipulieren, anstatt ufw zu verwenden. Um mehr über die Verwendung von iptables mit Docker zu erfahren, lesen Sie bitte Docker und iptables.

      In diesem Schritt ändern wir die UFW-Konfiguration so, dass der externe Zugriff auf die von Docker geöffneten Host-Ports blockiert wird. Bei der Ausführung von Django auf den App-Servern haben wir das Flag -p 80:8000 an docker übergeben, das Port 80 auf dem Host an den Container-Port 8000 weiterleitet. Dadurch wurde Port 80 auch für externe Clients geöffnet, was Sie unter http://your_app_server_1_IP überprüfen können. Um den direkten Zugriff zu verhindern, ändern wir die UFW-Konfiguration mithilfe der im ufw-docker GitHub-Repository beschriebenen Methode.

      Beginnen Sie damit, sich bei dem ersten Django-App-Server anzumelden. Öffnen Sie dann die Datei /etc/ufw/after.rules mit superuser-Berechtigungen, indem Sie nano oder Ihren bevorzugten Editor verwenden:

      sudo nano /etc/ufw/after.rules
      

      Geben Sie bei Aufforderung Ihr Passwort ein und drücken Sie zur Bestätigung ENTER.

      Sie sollten die folgenden ufw-Regeln sehen:

      /etc/ufw/after.rules

      #
      # rules.input-after
      #
      # Rules that should be run after the ufw command line added rules. Custom
      # rules should be added to one of these chains:
      #   ufw-after-input
      #   ufw-after-output
      #   ufw-after-forward
      #
      
      # Don't delete these required lines, otherwise there will be errors
      *filter
      :ufw-after-input - [0:0]
      :ufw-after-output - [0:0]
      :ufw-after-forward - [0:0]
      # End required lines
      
      # don't log noisy services by default
      -A ufw-after-input -p udp --dport 137 -j ufw-skip-to-policy-input
      -A ufw-after-input -p udp --dport 138 -j ufw-skip-to-policy-input
      -A ufw-after-input -p tcp --dport 139 -j ufw-skip-to-policy-input
      -A ufw-after-input -p tcp --dport 445 -j ufw-skip-to-policy-input
      -A ufw-after-input -p udp --dport 67 -j ufw-skip-to-policy-input
      -A ufw-after-input -p udp --dport 68 -j ufw-skip-to-policy-input
      
      # don't log noisy broadcast
      -A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input
      
      # don't delete the 'COMMIT' line or these rules won't be processed
      COMMIT
      

      Scrollen Sie nach unten und fügen Sie den folgenden Block mit UFW-Konfigurationsregeln ein:

      /etc/ufw/after.rules

      . . .
      
      # BEGIN UFW AND DOCKER
      *filter
      :ufw-user-forward - [0:0]
      :DOCKER-USER - [0:0]
      -A DOCKER-USER -j RETURN -s 10.0.0.0/8
      -A DOCKER-USER -j RETURN -s 172.16.0.0/12
      -A DOCKER-USER -j RETURN -s 192.168.0.0/16
      
      -A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
      
      -A DOCKER-USER -j ufw-user-forward
      
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
      
      -A DOCKER-USER -j RETURN
      COMMIT
      # END UFW AND DOCKER
      

      Diese Regeln schränken den öffentlichen Zugriff auf die von Docker geöffneten Ports ein und ermöglichen den Zugriff aus den privaten IP-Bereichen 10.0.0/8, 172.16.0.0/12 und 192.168.0.0/16. Wenn Sie VPC mit DigitalOcean verwenden, dann haben Droplets in Ihrem VPC-Netzwerk über die private Netzwerkschnittstelle Zugriff auf den offenen Port, externe Clients jedoch nicht. Weitere Informationen über VPC finden Sie in der offiziellen VPC-Dokumentation. Um mehr über die in diesem Snippet implementierten Regeln zu erfahren, lesen Sie bitte Funktionsweise in der ufw-docker README.

      Wenn Sie VPC nicht mit DigitalOcean verwenden und die öffentlichen IP-Adressen der App-Server in den Block upstream Ihrer Nginx-Konfiguration eingegeben haben, müssen Sie die UFW-Firewall explizit ändern, um den Datenverkehr vom Nginx-Server über Port 80 auf den Django-App-Servern zuzulassen. Eine Anleitung zur Erstellung von allow-Regeln mit der UFW-Firewall finden Sie unter UFW Grundlagen: Allgemeine Firewallregeln und -befehle.

      Wenn Sie die Bearbeitung abgeschlossen haben, speichern und schließen Sie die Datei.

      Starten Sie ufw neu, damit die neue Konfiguration übernommen wird:

      sudo systemctl restart ufw
      

      Navigieren Sie in Ihrem Webbrowser zu http://APP_SERVER_1_IP, um zu bestätigen, dass Sie über Port 80 nicht mehr auf die App-Server zugreifen können.

      Wiederholen Sie diesen Vorgang auf dem zweiten Django-App-Server.

      Melden Sie sich bei dem ersten App-Server ab oder öffnen Sie ein anderes Terminalfenster und melden Sie sich bei dem zweiten Django-App-Server an. Öffnen Sie dann die Datei /etc/ufw/after.rules mit superuser-Berechtigungen, indem Sie nano oder Ihren bevorzugten Editor verwenden:

      sudo nano /etc/ufw/after.rules
      

      Geben Sie bei Aufforderung Ihr Passwort ein und drücken Sie zur Bestätigung ENTER.

      Scrollen Sie nach unten und fügen Sie den folgenden Block mit UFW-Konfigurationsregeln ein:

      /etc/ufw/after.rules

      . . .
      
      # BEGIN UFW AND DOCKER
      *filter
      :ufw-user-forward - [0:0]
      :DOCKER-USER - [0:0]
      -A DOCKER-USER -j RETURN -s 10.0.0.0/8
      -A DOCKER-USER -j RETURN -s 172.16.0.0/12
      -A DOCKER-USER -j RETURN -s 192.168.0.0/16
      
      -A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
      
      -A DOCKER-USER -j ufw-user-forward
      
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
      -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
      -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
      
      -A DOCKER-USER -j RETURN
      COMMIT
      # END UFW AND DOCKER
      

      Wenn Sie die Bearbeitung abgeschlossen haben, speichern und schließen Sie die Datei.

      Starten Sie ufw neu, damit die neue Konfiguration übernommen wird:

      sudo systemctl restart ufw
      

      Navigieren Sie in Ihrem Webbrowser zu http://APP_SERVER_2_IP, um zu bestätigen, dass Sie über Port 80 nicht mehr auf die App-Server zugreifen können.

      Navigieren Sie abschließend zu https://your_domain_here/polls, um zu bestätigen, dass der Nginx-Proxy weiterhin Zugriff auf die upstream Django-Server hat. Sie sollten die Standardoberfläche der Umfrageanwendung sehen.

      Zusammenfassung

      In diesem Tutorial haben Sie mit Docker-Containern eine skalierbare Django Umfrageanwendung eingerichtet. Wenn Ihr Datenverkehr steigt und die Last auf dem System zunimmt, können Sie jede Schicht separat skalieren: die Nginx-Proxying-Schicht, die Django-Backend-Anwendungsschicht und die PostgreSQL-Datenbankschicht.

      Beim Aufbau eines verteilten Systems müssen Sie oft mehrere Designentscheidungen treffen, und mehrere Architekturen können Ihrem Anwendungsfall gerecht werden. Die in diesem Tutorial beschriebene Architektur ist als flexible Blaupause für den Entwurf skalierbarer Anwendungen mit Django und Docker gedacht.

      Möglicherweise möchten Sie das Verhalten Ihrer Container steuern, wenn sie auf Fehler stoßen, oder Container automatisch ausführen, wenn Ihr System gestartet wird. Zu diesem Zweck können Sie einen Prozessmanager wie Systemd verwenden oder Neustartrichtlinien implementieren. Weitere Informationen hierzu finden Sie unter Automatisches Starten von Containern in der Docker-Dokumentation.

      Wenn Sie im großen Maßstab mit mehreren Hosts arbeiten, die dasselbe Docker-Image ausführen, kann es effizient sein, Schritte mit einem Konfigurations-Managementtool wie Ansible oder Chef zu automatisieren. Um mehr über das Konfigurationsmanagement zu erfahren, lesen Sie bitte Eine Einführung in das Konfigurationsmanagement und Automatisieren der Servereinrichtung mit Ansible: Ein DigitalOcean-Workshop-Kit.

      Anstatt auf jedem Host dasselbe Image zu erstellen, können Sie die Bereitstellung auch mithilfe einer Image-Registrierung wie Docker Hub rationalisieren, bei der Docker-Images zentral erstellt, gespeichert und an mehrere Server verteilt werden. Zusammen mit einer Image-Registrierung kann Ihnen eine kontinuierliche Integrations- und Bereitstellungspipeline dabei helfen, Images zu erstellen, zu testen und auf Ihre App-Server zu verteilen. Weitere Informationen zu CI/CD finden Sie unter Eine Einführung in die CI/CD Best Practices.



      Source link