
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: , .
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 Es gibt eine Datei Readme.md mit einer detaillierten Beschreibung der Struktur und Anweisungen zum Starten des Projekts.
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.
ist noch einfacher, dort gibt es nur eine Aufgabe send_mail_task.
Im Ordner liegen zwei Unterordner:
dockermit zwei Docker-Dateien (base.dockerfilefür den Aufbau eines selten ändernden Basisimages undDockerfilefü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.ymlzum Hochfahren einer lokalen Datenbank für die Entwicklung;docker-compose.local.workers.ymlzum Hochfahren eines lokalen Workers, einer Datenbank, Redis und RabbitMQ;docker-compose.test.ymlzum Ausführen von Tests bei der Bereitstellung;docker-compose.ymlfür das Deployment.
Und der letzte interessante Ordner für uns — . 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
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:

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:
Dockerzum Verwalten und zur visuellen Darstellung des Zustands der Container in der Plesk-Administration;Gitzur Konfiguration des Deploy-Schrittes auf dem Server;Let's Encryptzur Generierung (und automatischen Verlängerung) von kostenlosen TLS-Zertifikaten;Firewallzur Konfiguration der Filterung eingehender Daten.
Diese können über die Plesk-Administration im Abschnitt Erweiterungen installiert werden:

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.
- Wir erstellen ein Abonnement für die Domain helloworld.ru und geben den Benutzername und das Passwort für den Systembenutzer an:

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:
- Dann erstellen wir in diesem Abonnement das Subdomain dev.helloworld.ru (für das ebenfalls ein kostenloses TLS-Zertifikat ausgestellt werden kann):

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 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 (), 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 : 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.
- 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):

- Navigieren Sie zur installierten Erweiterung, suchen Sie nach dem Image
redis bitnamiund installieren Sie die neueste Version:
- 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:

- 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:

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:
- ein passwortgeschütztes Docker-Repository, das über eine Subdomain zugänglich ist. ;
- UI-Schnittstelle zum Anzeigen von Images im Repository, erreichbar unter .
Dafür:
- 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.
- In den Ordner der Subdomain docker.helloworld.de fügen wir die Datei hinzu
docker-compose.ymlmit 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' - Unter SSH generieren wir die Datei .htpasswd für die Basis-Authentifizierung im Docker-Repository:
htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password - Wir bauen die Container auf und starten sie:
docker-compose up -d - 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:

Und fügen eine Regel für die Proxyweiterleitung des eingehenden Traffics zu unserem Container hinzu:

- 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 - Wir testen außerdem die Funktion des Subdomains docker-ui.helloworld.ru:

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):
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.
- Gehen wir zu Tools & Settings > Settings > Firewall:

- 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
- Wir fügen außerdem eine Regel hinzu, die dem externen Zugriff die Ports für PostgreSQL und die Verwaltungsoberfläche von RabbitMQ öffnet:

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

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.
- Wir gehen in das Abonnement unserer Website Helloworld und navigieren zum Unterabschnitt Git:

- Fügen Sie im Feld „Remote Git repository“ den Link zu unserem Github-Repository ein und ändern Sie den Standardordner
httpdocsin einen anderen (zum Beispiel,/httpdocs/hw_back):
- Kopieren Sie den SSH Public Key vom vorherigen Schritt und in die Einstellungen von Github ein.
- 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):
- 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 Fallprod;
{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 - 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 .
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. :8443 oder :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
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

Frontend

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: , .
Quelle: habr.com
















