CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular
In diesem Artikel teile ich meine Erfahrungen bei der Einrichtung von CI/CD mit dem Plesk-Panel und GitHub Actions. Heute lernen wir, ein einfaches Projekt mit dem unauffälligen Namen „Helloworld“ bereitzustellen. Es ist mit dem Python-Framework Flask geschrieben, verwendet Celery-Worker und hat ein Frontend in Angular 8.

Links zu den Repositories: Backend, Frontend.

Im ersten Teil des Artikels werfen wir einen Blick auf unser Projekt und seine Komponenten. Im zweiten Teil klären wir, wie man Plesk einrichtet und die notwendigen Erweiterungen und Komponenten (DB, RabbitMQ, Redis, Docker usw.) installiert.

Im dritten Teil werden wir schließlich die Pipeline für die Bereitstellung unseres Projekts auf den Server in die Entwicklungs- und Produktionsumgebung konfigurieren. Anschließend starten wir die Website auf dem Server.

Und ja, ich habe vergessen, mich vorzustellen. Mein Name ist Oleg Borzov, ich bin Fullstack-Entwickler im CRM-Team für Hypothekenmanager bei Domclick.

Projektübersicht

Zunächst betrachten wir die beiden Repositories des Projekts – Backend und Frontend – und gehen den Code durch.

Backend-Teil: Flask+Celery

Für das Backend habe ich ein recht populäres Setup unter Python-Entwicklern gewählt: das Flask-Framework (für die API) und Celery (für die Aufgabenwarteschlange). Als ORM kommt SQLAlchemy zum Einsatz. Für Migrationen wird Alembic verwendet. Für die JSON-Validierung in den Endpunkten nutzen wir Marshmallow.

In Repository Es gibt eine Datei Readme.md mit einer detaillierten Beschreibung der Struktur und Anweisungen zum Starten des Projekts.

API der Webanwendung ist ziemlich einfach und besteht aus 6 Endpunkten:

  • /ping — zur Überprüfung der Erreichbarkeit;
  • Endpunkte für Registrierung, Authentifizierung, Deauthentifizierung und um den autorisierten Benutzer abzurufen;
  • ein Endpunkt zum Versenden von E-Mails, der eine Aufgabe in die Celery-Warteschlange einreiht.

Der Celery-Teil ist noch einfacher, dort gibt es nur eine Aufgabe send_mail_task.

Im Ordner /conf liegen zwei Unterordner:

  • docker mit zwei Docker-Dateien (base.dockerfile für den Aufbau eines selten ändernden Basisimages und Dockerfile für die Haupt-Bauten);
  • .env_files — mit Dateien für Umgebungsvariablen für verschiedene Umgebungen.

Im Stammverzeichnis des Projekts befinden sich vier docker-compose-Dateien:

  • docker-compose.local.db.yml zum Hochfahren einer lokalen Datenbank für die Entwicklung;
  • docker-compose.local.workers.yml zum Hochfahren eines lokalen Workers, einer Datenbank, Redis und RabbitMQ;
  • docker-compose.test.yml zum Ausführen von Tests bei der Bereitstellung;
  • docker-compose.yml für das Deployment.

Und der letzte interessante Ordner für uns — .ci-cd. Es enthält Shell-Skripte für die Bereitstellung:

  • deploy.sh — Start der Migration und des Deployments. Wird auf dem Server nach dem Zusammenstellen und dem Ausführen der Tests in Github Actions gestartet;
  • rollback.sh — Rücksetzung der Container auf die vorherige Version der Bereitstellung;
  • curl_tg.sh — Versand von Benachrichtigungen über die Bereitstellung an Telegram.

Frontend auf Angular

Repository mit dem Frontend ist deutlich einfacher als das Backend. Das Frontend besteht aus drei Seiten:

  • Hauptseite mit einem Formular zum Senden von E-Mails und einem Ausloggen-Button.
  • Login-Seite.
  • Registrierungsseite.

Die Hauptseite wirkt minimalistisch:

CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular
Im Stammverzeichnis sind zwei Dateien enthalten Dockerfile und docker-compose.yml, sowie ein uns vertrauter Ordner .ci-cd mit etwas weniger Skripten als im Backend-Repository (Skripte zum Testen wurden entfernt).

Projekt in Plesk anlegen

Wir beginnen mit der Konfiguration von Plesk und der Erstellung eines Abonnements für unsere Website.

Installation von Erweiterungen

In Plesk benötigen wir vier Erweiterungen:

  • Docker zum Verwalten und zur visuellen Darstellung des Zustands der Container in der Plesk-Administration;
  • Git zur Konfiguration des Deploy-Schrittes auf dem Server;
  • Let's Encrypt zur Generierung (und automatischen Verlängerung) von kostenlosen TLS-Zertifikaten;
  • Firewall zur Konfiguration der Filterung eingehender Daten.

Diese können über die Plesk-Administration im Abschnitt Erweiterungen installiert werden:

CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular
Wir werden die detaillierte Konfiguration von Erweiterungen nicht behandeln; für unsere Demo-Zwecke sind die Standardeinstellungen ausreichend.

Erstellung eines Abonnements und einer Website

Als Nächstes müssen wir ein Abonnement für unsere Website helloworld.ru erstellen und das Subdomain dev.helloworld.ru hinzufügen.

  1. Wir erstellen ein Abonnement für die Domain helloworld.ru und geben den Benutzername und das Passwort für den Systembenutzer an:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular
    Unten auf der Seite setzen wir ein Häkchen Sichern Sie die Domain mit Let's Encrypt, wenn wir HTTPS für die Website einrichten möchten:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  2. Dann erstellen wir in diesem Abonnement das Subdomain dev.helloworld.ru (für das ebenfalls ein kostenloses TLS-Zertifikat ausgestellt werden kann):

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

Installation von Serverkomponenten

Wir haben einen Server mit OS Debian Stretch 9.12 und installiertem Control Panel Plesk Obsidian 18.0.27.

Wir müssen für unser Projekt installieren und konfigurieren:

  • PostgreSQL (in unserem Fall wird es einen Server mit zwei DBs für die dev- und prod-Umgebung geben).
  • RabbitMQ (dasselbe, eine Instanz mit verschiedenen vhosts für die Umgebungen).
  • Zwei Instanzen Redis (für die dev- und prod-Umgebung).
  • Docker-Registry (für die lokale Speicherung der erstellten Docker-Images).
  • UI-Interface für Docker-Registry.

PostgreSQL

Im Lieferumfang von Plesk ist bereits eine PostgreSQL-Datenbank enthalten, jedoch nicht in der neuesten Version (zum Zeitpunkt der Erstellung dieses Artikels unterstützte Plesk Obsidian die Postgres-Versionen 8.4–10.8. Für unsere Anwendung möchten wir jedoch die neueste Version (12.3 zum Zeitpunkt des Schreibens dieses Artikels), weshalb wir sie manuell installieren werden.

Es gibt viele detaillierte Anleitungen zur Installation von Postgres auf Debian im Internet (Nummer 00 oder), daher werde ich sie nicht im Detail beschreiben, sondern einfach die Befehle angeben:

wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | sudo apt-key add -
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main" >> /etc/apt/sources.list.d/pgdg.list'

sudo apt-get update
sudo apt-get install postgresql postgresql-contrib

Da die Standardkonfiguration in PostgreSQL eher durchschnittlich ist, sollten wir die Konfiguration unbedingt anpassen. Dabei hilft uns Rechner: Geben Sie die Parameter Ihres Servers ein und ersetzen Sie die Einstellungen in der Datei /etc/postgresql/12/main/postgresql.confdurch die vorgeschlagenen. Hier sollte angemerkt werden, dass solche Kalkulatoren kein Allheilmittel sind und die Datenbank gezielt angepasst werden sollte, basierend auf Ihrer Hardware, Anwendung und Komplexität der Abfragen. Für den Anfang reicht das jedoch aus.

Neben den vom Kalkulator vorgeschlagenen Einstellungen ändern wir auch in postgresql.confden standardmäßig angegebenen Port 5432 auf einen anderen (in unserem Beispiel — 53983).

Nach der Änderung der Konfigurationsdatei starten wir den postgresql-Server mit dem Befehl:

service postgresql restart

Wir haben PostgreSQL installiert und konfiguriert. Jetzt erstellen wir Datenbanken, Benutzer für die Entwicklungs- und Produktionsumgebungen und weisen den Benutzern die nötigen Berechtigungen zur Verwaltung der Datenbanken zu:

$ su - postgres
postgres:~$ create database hw_dev_db_name;
CREATE DATABASE
postgres:~$ create user hw_dev_db_user with password 'hw_dev_db_password';
CREATE ROLE
postgres:~$ grant ALL privileges ON database hw_dev_db_name to hw_dev_db_user;
GRANT
postgres:~$ create database hw_prod_db_name;
CREATE DATABASE
postgres:~$ create user hw_prod_db_user with password 'hw_prod_db_password';
CREATE ROLE
postgres:~$ grant ALL privileges ON database hw_prod_db_name to hw_prod_db_user;
GRANT

RabbitMQ

Nun kommen wir zur Installation von RabbitMQ — dem Nachrichtenbroker für Celery. Die Installation auf Debian gestaltet sich recht einfach:

wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
sudo dpkg -i erlang-solutions_1.0_all.deb

sudo apt-get update
sudo apt-get install erlang erlang-nox

sudo add-apt-repository 'deb http://www.rabbitmq.com/debian/ testing main'
wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -

sudo apt-get update
sudo apt-get install rabbitmq-server

Nach der Installation müssen wir vhosts, Benutzer anlegen und die entsprechenden Berechtigungen vergeben:

sudo rabbitmqctl add_user hw_dev_amqp_user hw_dev_amqp_password 
sudo rabbitmqctl set_user_tags hw_dev_amqp_user administrator
sudo rabbitmqctl add_vhost hw_dev_vhost
sudo rabbitmqctl set_permissions -p hw_dev_vhost hw_dev_amqp_user ".*" ".*" ".*"

sudo rabbitmqctl add_user hw_prod_amqp_user hw_prod_amqp_password 
sudo rabbitmqctl set_user_tags hw_prod_amqp_user administrator
sudo rabbitmqctl add_vhost hw_prod_vhost
sudo rabbitmqctl set_permissions -p hw_prod_vhost hw_prod_amqp_user ".*" ".*" ".*"

Redis

Lassen Sie uns nun die letzte Komponente für unsere Anwendung – Redis – installieren und konfigurieren. Es wird als Backend zur Speicherung der Ergebnisse von Celery-Tasks verwendet.

Wir werden zwei Docker-Container mit Redis für die Entwicklungs- und Produktionsumgebungen mithilfe des Docker Plesk-Extensions.

  1. Gehen Sie zu Plesk, navigieren Sie zu den Erweiterungen, suchen Sie nach der Docker-Erweiterung und installieren Sie diese (wir benötigen die kostenlose Version):

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  2. Navigieren Sie zur installierten Erweiterung, suchen Sie nach dem Image redis bitnami und installieren Sie die neueste Version:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  3. Gehen Sie in den heruntergeladenen Container und passen Sie die Konfiguration an: Geben Sie den Port, die maximale zugewiesene Größe des RAM, das Passwort in den Umgebungsvariablen an und montieren Sie das Volume:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  4. Führen Sie die Schritte 2-3 für den Produktionscontainer aus, ändern Sie dabei nur die Einstellungen: Port, Passwort, RAM-Größe und den Pfad zum Volume-Ordner auf dem Server:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

Docker Registry

Neben den grundlegenden Diensten wäre es sinnvoll, auf dem Server ein eigenes Docker-Image-Repository zu installieren. Glücklicherweise sind Speicherplatz auf Servern derzeit recht günstig (sicherlich günstiger als ein Abonnement bei DockerHub), und der Prozess der Installation eines privaten Repositories ist sehr einfach.

Wir möchten, dass folgende Komponenten installiert sind:

Dafür:

  1. Wir erstellen in Plesk zwei Subdomains in unserem Abonnement: docker.helloworld.de und docker-ui.helloworld.de, und richten für sie Let's Encrypt-Zertifikate ein.
  2. In den Ordner der Subdomain docker.helloworld.de fügen wir die Datei hinzu docker-compose.yml mit folgendem Inhalt:
    version: "3"
    
    services:
      docker-registry:
        image: "registry:2"
        restart: always
        ports:
          - "53985:5000"
        environment:
          REGISTRY_AUTH: htpasswd
          REGISTRY_AUTH_HTPASSWD_REALM: basic-realm
          REGISTRY_AUTH_HTPASSWD_PATH: /auth/.htpasswd
          REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
        volumes:
          - ./docker-registry.htpasswd:/auth/.htpasswd
          - ./data:/data
    
      docker-registry-ui:
        image: konradkleine/docker-registry-frontend:v2
        restart: always
        ports:
          - "53986:80"
        environment:
          VIRTUAL_HOST: '*, https://*'
          ENV_DOCKER_REGISTRY_HOST: 'docker-registry'
          ENV_DOCKER_REGISTRY_PORT: 5000
        links:
          - 'docker-registry'
    

  3. Unter SSH generieren wir die Datei .htpasswd für die Basis-Authentifizierung im Docker-Repository:
    htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
  4. Wir bauen die Container auf und starten sie:
    docker-compose up -d
  5. Und wir müssen Nginx auf unsere Container umleiten. Dies kann über Plesk erfolgen.

Die folgenden Schritte sind für die Subdomains docker.helloworld.de und docker-ui.helloworld.de durchzuführen:

Im Abschnitt Entwicklertools unserer Website gehen wir zu Docker-Proxy-Regeln:

CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular
Und fügen eine Regel für die Proxyweiterleitung des eingehenden Traffics zu unserem Container hinzu:

CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  1. Wir überprüfen, ob wir uns von unserem lokalen Computer aus in unseren Container anmelden können:
    $ docker login docker.helloworld.ru -u hw_docker_admin -p hw_docker_password
    WARNUNG! Die Verwendung von --password über die CLI ist unsicher. Verwenden Sie --password-stdin.
    Anmeldung erfolgreich
  2. Wir testen außerdem die Funktion des Subdomains docker-ui.helloworld.ru:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular
    Wenn Sie auf Browse repositories klicken, wird ein Anmeldefenster angezeigt, in das Sie Ihren Benutzernamen und Ihr Passwort für das Repository eingeben müssen. Danach werden Sie auf eine Seite mit der Liste der Repositories weitergeleitet (diese wird vorerst leer sein):

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

Ports im Plesk Firewall öffnen

Nach der Installation und Konfiguration der Komponenten müssen wir Ports öffnen, damit die Komponenten aus Docker-Containern und dem externen Netzwerk zugänglich sind.

Lassen Sie uns am Beispiel der zuvor installierten Firewall-Erweiterung für Plesk sehen, wie das geht.

  1. Gehen wir zu Tools & Settings > Settings > Firewall:
    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular
  2. Gehen wir zu Plesk Firewall-Regeln ändern > Benutzerdefinierte Regel hinzufügen und öffnen die folgenden TCP-Ports für das Docker-Subnetz (172.0.0.0/8):
    RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
    Redis: 32785, 32786

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  3. Wir fügen außerdem eine Regel hinzu, die dem externen Zugriff die Ports für PostgreSQL und die Verwaltungsoberfläche von RabbitMQ öffnet:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  4. Wir wenden die Regeln mit der Schaltfläche Änderungen anwenden an:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

CI/CD in GitHub Actions einrichten

Kommen wir zum spannendsten Teil — der Einrichtung der Pipeline für kontinuierliche Integration und Bereitstellung unseres Projekts auf dem Server.

Dieser Pipeline wird aus zwei Teilen bestehen:

  • dem Erstellen des Images und dem Ausführen von Tests (für das Backend) – auf der Github-Seite;
  • dem Starten von Migrationsprozessen (für das Backend) und dem Deployen von Containern – auf dem Server.

Deployment in Plesk

Beginnen wir zunächst mit dem zweiten Punkt (da dieser den ersten beeinflusst).

Den Deployment-Prozess richten wir mit Hilfe der Git-Erweiterung für Plesk ein.

Betrachten wir ein Beispiel mit der Produktionsumgebung für das Backend-Repository.

  1. Wir gehen in das Abonnement unserer Website Helloworld und navigieren zum Unterabschnitt Git:

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  2. Fügen Sie im Feld „Remote Git repository“ den Link zu unserem Github-Repository ein und ändern Sie den Standardordner httpdocs in einen anderen (zum Beispiel, /httpdocs/hw_back):

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  3. Kopieren Sie den SSH Public Key vom vorherigen Schritt und fügen Sie ihn in die Einstellungen von Github ein.
  4. Klicken Sie auf OK auf dem Bildschirm im Punkt 2, danach werden Sie zur Repository-Seite in Plesk weitergeleitet. Jetzt müssen wir das Aktualisieren des Repositories bei Commits in den Master-Branch einrichten. Dazu gehen wir zu Repository-Einstellungen und speichern den Wert Webhook-URL (diese benötigen wir später bei der Einrichtung von Github Actions):

    CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

  5. Im Feld Action auf dem Bildschirm des vorherigen Punktes geben wir das Skript zum Starten des Deployments ein:
    cd {REPOSITORY_ABSOLUTE_PATH}
    .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID} 

    wo:

    {REPOSITORY_ABSOLUTE_PATH} — Pfad zum Verzeichnis des Produktions-Backend-Repositories auf dem Server;
    {ENV} — Umgebung (dev/prod), in unserem Fall prod;
    {DOCKER_REGISTRY_HOST} — Host unseres Docker-Repositories
    {TG_BOT_TOKEN} — Token des Telegram-Bots;
    {TG_CHAT_ID} — ID des Chats/Kanals für Benachrichtigungen.

    Beispielscript:

    cd /var/www/vhosts/helloworld.ru/httpdocs/hw_back/
    .ci-cd/deploy.sh dev docker.helloworld.ru docker_user docker_password 12345678:AAbcdEfghCH1vGbCasdfSAs0K5PALDsaw -1001234567890
  6. Fügen Sie den Benutzer aus unserem Abonnement zur Docker-Gruppe hinzu (damit er Container verwalten kann):
    sudo usermod -aG docker helloworld_admin

Die Entwicklungsumgebung für das Backend-Repository und das Frontend wird ähnlich konfiguriert.

Deployment-Pipeline in Github Actions

Nun richten wir den ersten Teil unseres CI/CD-Pipelines in Github Actions ein.

Backend

Die Pipeline wird in der Datei deploy.yml.

beschrieben. Aber bevor wir sie durchgehen, fügen wir die benötigten Secret-Variablen in Github hinzu. Gehen Sie dazu zu Einstellungen -> Geheimnisse:

  • DOCKER_REGISTRY — Host unseres Docker-Repositories (docker.helloworld.ru);
  • DOCKER_LOGIN — Benutzername für das Docker-Repository;
  • DOCKER_PASSWORD — Passwort dafür;
  • DEPLOY_HOST — Host, auf dem das Plesk-Admin-Panel verfügbar ist (z. B. helloworld.ru:8443 oder 123.4.56.78:8443);
  • DEPLOY_BACK_PROD_TOKEN — Token für das Deployment im Prod-Repository auf dem Server (wir haben es in Deployment in Plesk Punkt 4 erhalten);
  • DEPLOY_BACK_DEV_TOKEN — Token für das Deployment im Dev-Repository auf dem Server.

Der Deploy-Prozess ist einfach und besteht aus drei Hauptschritten:

  • Erstellung und Veröffentlichung des Images in unserem Repository;
  • Ausführung von Tests in einem Container auf Basis des neu erstellten Images;
  • Bereitstellung in die erforderliche Umgebung je nach Branch (dev/master).

Frontend

Die Datei deploy.yml für das Frontend-Repository unterscheidet sich kaum von der des Backend-Repositories. Sie enthält keinen Schritt zur Ausführung von Tests und die Namen der Deploy-Tokens werden geändert. Übrigens müssen die Secrets für das Frontend-Repository separat ausgefüllt werden.

Website-Einrichtung

Traffic-Proxying über Nginx

Nun sind wir am Ende angekommen. Es bleibt nur noch, das Proxying des eingehenden und ausgehenden Traffics in unseren Container über Nginx einzurichten. Diesen Prozess haben wir bereits im Punkt 5 der Docker Registry-Einstellungen behandelt. Dasselbe muss für die Front- und Backend-Seite in den dev- und prod-Umgebungen wiederholt werden.

Ich werde Screenshots der Einstellungen bereitstellen.

Backend

CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular

Frontend

CI/CD mit GitHub Actions für ein Projekt mit Flask+Angular
Wichtiger Hinweis. Im Frontend-Container werden alle URLs proxied, außer denen, die mit /api/ beginnen — sie werden an den Backend-Container weitergeleitet (deshalb müssen alle Handler im Backend-Container mit /api/).

Ergebnisse

beginnen). Jetzt sollte unsere Website unter den Adressen helloworld.ru und dev.helloworld.ru (prod- und dev-Umgebung entsprechend) verfügbar sein.

Zusammenfassend haben wir gelernt, wie man eine einfache Anwendung mit Flask und Angular erstellt und eine Pipeline in Github Actions einrichtet, um sie auf einem Server mit Plesk bereitzustellen.

Hier sind die Links zu den Repositories mit dem Code: Backend, Frontend.

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster