
In diesem Artikel teile ich meine Erfahrung bei der Einrichtung von CI/CD mit der Plesk-Verwaltungskonsole und GitHub Actions. Heute lernen wir, ein einfaches Projekt mit dem wenig einfallsreichen Namen „Helloworld“ zu deployen. Es wurde mit dem Python-Framework Flask, mit Workern auf Celery und einem Frontend auf Angular 8 geschrieben.
Links zu den Repositories: , .
Im ersten Teil des Artikels werfen wir einen Blick auf unser Projekt und seine Teile. Im zweiten Teil werden wir uns damit beschäftigen, wie man Plesk einrichtet und die erforderlichen Erweiterungen und Komponenten installiert (Datenbank, RabbitMQ, Redis, Docker usw.).
Im dritten Teil werden wir schließlich klären, wie man eine Pipeline zum Deployen unseres Projekts auf dem Server in die Dev- und Prod-Umgebung einrichtet. Anschließend starten wir die Website auf dem Server.
Übrigens, ich habe vergessen, mich vorzustellen. Mein Name ist Oleg Borzov, ich bin Fullstack-Entwickler im CRM-Team für Hypothekenmanager bei Domklik.
Projektübersicht
Zunächst betrachten wir die beiden Repositories des Projekts – das Backend und das Frontend – und gehen den Code durch.
Backend-Teil: Flask+Celery
Für den Backend-Teil habe ich eine unter Python-Entwicklern recht beliebte Kombination gewählt: Das Framework Flask (für die API) und Celery (für die Aufgabenwarteschlange). Als ORM kommt SQLAlchemy zum Einsatz. Für Migrationen wird Alembic verwendet. Zur Validierung von JSON in den Handlers – Marshmallow.
Im Es gibt eine Datei Readme.md mit einer ausführlichen Beschreibung der Struktur und Anweisungen zum Starten des Projekts.
eher einfach, besteht aus 6 Endpunkten:
/ping— zum Überprüfen der Verfügbarkeit;- Endpunkte für Registrierung, Authentifizierung, De-Authentifizierung und Abruf des authentifizierten Benutzers;
- ein Endpunkt zum Versenden von E-Mails, der eine Aufgabe in die Celery-Warteschlange legt.
noch einfacher, es gibt nur eine Aufgabe send_mail_task.
Im Verzeichnis liegen zwei Unterordner:
dockermit zwei Docker-Dateien (base.dockerfilezum Erstellen eines selten geänderten Basisimages undDockerfilefür die Hauptbuilds);.env_files— mit Umgebungsvariablen-Dateien für verschiedene Umgebungen.
Im Wurzelverzeichnis des Projekts befinden sich vier docker-compose-Dateien:
docker-compose.local.db.ymlzur Einrichtung einer lokalen Datenbank für die Entwicklung;docker-compose.local.workers.ymlzum lokalen Hochfahren von Workern, Datenbank, Redis und RabbitMQ;docker-compose.test.ymlzum Ausführen von Tests beim Deployen;docker-compose.ymlzum Deployen.
Und der letzte interessante Ordner für uns ist — . Darin befinden sich Shell-Skripte für das Deployen:
deploy.sh— startet Migrationen und das Deployen. Wird auf dem Server nach dem Build und dem Ausführen von Tests in GitHub Actions ausgeführt;rollback.sh— rollt die Container auf die vorherige Version des Builds zurück;curl_tg.sh— Benachrichtigungen über das Deployment in Telegram senden.
Frontend in Angular
ist viel einfacher als das Backend. Das Frontend besteht aus drei Seiten:
- Die Hauptseite mit einem Formular zum Versenden von E-Mails und einem Abmeldebutton.
- Login-Seite.
- Registrierungsseite.
Die Hauptseite sieht minimalistisch aus:

Im Root-Verzeichnis liegen zwei Dateien Dockerfile und docker-compose.yml, sowie ein uns bekanntes Verzeichnis .ci-cd mit etwas weniger Skripten als im Backend-Repository (die Skripte zum Starten von Tests wurden entfernt).
Wir richten ein Projekt in Plesk ein
Beginnen wir mit der Konfiguration von Plesk und dem Erstellen eines Abonnements für unsere Website.
Installation von Erweiterungen
In Plesk benötigen wir vier Erweiterungen:
Dockerzum Verwalten und visuellen Anzeigen des Zustands von Containern im Plesk-Adminbereich;Gitzur Konfiguration des Deployment-Schritts auf dem Server;Let's Encryptzur Generierung (und automatischen Verlängerung) kostenloser TLS-Zertifikate;Firewallzur Konfiguration der Filterung des eingehenden Datenverkehrs.
Sie können sie über das Plesk-Adminpanel im Abschnitt Erweiterungen installieren:

Wir werden die detaillierte Konfiguration der Erweiterungen nicht betrachten, die Standardeinstellungen sind für unsere Demo-Zwecke ausreichend.
Erstellung eines Abonnements und einer Website
Als nächstes müssen wir ein Abonnement für unsere Website helloworld.ru erstellen und die Unterdomain dev.helloworld.ru hinzufügen.
- Wir erstellen ein Abonnement für die Domain helloworld.ru und geben den Benutzernamen 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 die Unterdomain dev.helloworld.ru (für die ebenfalls ein kostenloses TLS-Zertifikat ausgestellt werden kann):

Installation der Serverkomponenten
Wir haben einen Server mit OS Debian Stretch 9.12 und dem installierten Verwaltungspanel 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 Datenbanken für die dev- und prod-Umgebung geben).
- RabbitMQ (das gleiche, eine Instanz mit verschiedenen vhosts für die Umgebungen).
- Zwei Instanzen von Redis (für die dev- und prod-Umgebung).
- Docker Registry (für die lokale Speicherung der erstellten Docker-Images).
- UI-Schnittstelle für die Docker-Registry.
PostgreSQL
Im Lieferumfang von Plesk ist bereits eine PostgreSQL-Datenbank enthalten, jedoch nicht die neueste Version (zum Zeitpunkt der Erstellung des Artikels unterstützte Plesk Obsidian Detaillierte Anleitungen zur Installation von Postgres auf Debian finden sich zahlreich im Internet (
Beispiel), deshalb werde ich sie nicht im Detail beschreiben, sondern nur die Befehle anführen:
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 ziemlich durchschnittlich ist, ist es erforderlich, die Konfiguration unbedingt anzupassen. Dabei hilft uns : Sie müssen die Parameter Ihres Servers eingeben und die Einstellungen in der Datei /etc/postgresql/12/main/postgresql.confdurch die vorgeschlagenen ersetzen. Hier muss ich anmerken, dass solche Rechner keine Wunderwaffe sind und die Datenbank gezielt an Ihre Hardware, Ihre Anwendung und die Komplexität der Abfragen angepasst werden sollte. Aber für den Anfang reicht das aus.
Neben den vom Rechner vorgeschlagenen Einstellungen ändern wir auch in postgresql.confden standardmäßig eingetragenen 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 eine DB, Benutzer für die Entwicklungs- und Produktionsumgebung und vergeben den Benutzern die Rechte zum Verwalten der DB:
$ 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
Kommen wir zur Installation von RabbitMQ - einem Nachricht broker für Celery. Die Installation auf Debian ist 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 erstellen und die erforderlichen Berechtigungen festlegen:
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
Jetzt installieren und konfigurieren wir die letzte Komponente für unsere Anwendung - Redis. Es wird als Backend für die Speicherung von Ergebnissen der Celery-Aufgaben verwendet.
Wir werden zwei Docker-Container mit Redis für Dev- und Prod-Umgebungen mithilfe des Erweiterung starten Docker für Plesk.
- Gehe zu Plesk, gehe zum Abschnitt Erweiterungen, suche nach der Docker-Erweiterung und installiere sie (wir benötigen die kostenlose Version):

- Gehe zur installierten Erweiterung, finde das Abbild über die Suche
redis bitnamiund installiere die neueste Version:
- Gehe in den heruntergeladenen Container und passe die Konfiguration an: gib den Port, die maximal zugewiesene RAM-Größe, das Passwort in den Umgebungsvariablen an und mounte das Volume:

- Führe die Schritte 2-3 für den Prod-Container aus, ändere nur die Parameter in den 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 Repository für Docker-Images einzurichten. Glücklicherweise sind die Plätze auf den Servern jetzt recht günstig (sicherlich günstiger als ein Abonnement bei DockerHub) und der Prozess zur Installation eines privaten Repositories ist sehr einfach.
Wir möchten folgendes installieren:
- ein durch ein Passwort geschütztes Docker-Repository, das über eine Subdomain zugänglich ist ;
- eine Benutzeroberfläche zur Anzeige von Images im Repository, zugänglich unter der Adresse .
Dafür:
- Erstelle in Plesk zwei Subdomains in unserem Abonnement: docker.helloworld.ru und docker-ui.helloworld.ru, und richte für sie Let's Encrypt-Zertifikate ein.
- Füge in den Ordner der Subdomain docker.helloworld.ru 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' - Wir generieren über SSH die Datei .htpasswd für die Basis-Authentifizierung im Docker-Repository:
htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password - Wir bauen und starten die Container:
docker-compose up -d - Und wir müssen Nginx auf unsere Container umleiten. Das kann über Plesk erfolgen.
Die folgenden Schritte müssen für die Subdomains docker.helloworld.ru und docker-ui.helloworld.ru durchgeführt werden:
Im Abschnitt Dev-Tools unserer Website gehen zu Docker Proxy-Regeln:

Und wir fügen eine Regel zum Proxy des eingehenden Traffics in unseren Container hinzu:

- Wir überprüfen, dass wir uns von einem lokalen Rechner aus in unseren Container einloggen 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 - Lassen Sie uns auch die Funktionalität der Subdomain docker-ui.helloworld.ru überprüfen:

Wenn Sie auf Repositories durchsuchen klicken, zeigt der Browser ein Anmeldefenster an, in das Sie den Benutzernamen und das Passwort für das Repository eingeben müssen. Danach werden wir auf die Seite mit der Liste der Repositories weitergeleitet (diese wird zunächst leer sein):
Öffnen Sie die Ports in der Plesk-Firewall
Nach der Installation und Konfiguration der Komponenten müssen wir die Ports öffnen, damit die Komponenten von Docker-Containern und aus dem externen Netzwerk erreichbar sind.
Sehen wir uns an, wie man dies am Beispiel der zuvor installierten Firewall-Erweiterung für Plesk macht.
- Gehen Sie zu Tools & Einstellungen > Einstellungen > Firewall:

- Gehen Sie zu Ändern Sie die Plesk-Firewallregeln > Benutzerdefinierte Regel hinzufügen und öffnen Sie 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 werden auch eine Regel hinzufügen, die die Ports für PostgreSQL und das Management-Panel von RabbitMQ für die externe Welt öffnet:

- Wenden Sie die Regeln mit der Schaltfläche Änderungen anwenden an:

CI/CD-Konfiguration in Github Actions
Kommen wir zum interessantesten Teil — der Konfiguration des Pipelines für die kontinuierliche Integration und Bereitstellung unseres Projekts auf dem Server.
Diese Pipeline wird aus zwei Teilen bestehen:
- Bau des Abbilds und Ausführung von Tests (für das Backend) — auf der Seite von Github;
- Ausführung der Migrationen (für das Backend) und Bereitstellung der Container — auf dem Server.
Bereitstellung in Plesk
Lassen Sie uns zunächst den zweiten Punkt bearbeiten (da der erste davon abhängt).
Wir werden den Bereitstellungsprozess mit der Git-Erweiterung für Plesk konfigurieren.
Sehen wir uns ein Beispiel mit der Prod-Umgebung für das Backend-Repository an.
- Gehen Sie zu unserem Helloworld-Webseiten-Abonnement und navigieren Sie zum Git-Unterbereich:

- 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-Öffentlichen Schlüssel aus dem vorherigen Schritt und Klicken Sie im Punkt 2 auf OK, danach werden wir auf die Repository-Seite in Plesk weitergeleitet. Jetzt müssen wir die Aktualisierung des Repositories bei Commits in den Master-Zweig einrichten. Dazu gehen wir zu
- Repository-Einstellungen und speichern den Wert Webhook-URL
(dies wird später bei der Konfiguration der Github Actions benötigt):Geben Sie im Feld Aktionen auf dem vorherigen Bildschirm das Skript zum Starten der Bereitstellung 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}
— der Pfad zum Prod-Ordner des Backend-Repositories auf dem Server;{ENV}
— die Umgebung (dev/prod), in unserem Fall— Umgebung (dev/prod), in unserem Fallprod;
{DOCKER_REGISTRY_HOST}— der Host unseres Docker-Repositorys
{TG_BOT_TOKEN}— Token des Telegram-Bots;
{TG_CHAT_ID}— ID des Chats/Kanals für den Versand von Benachrichtigungen.Beispiel-Skript:
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 einen 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
Gehen wir zur Konfiguration des ersten Teils unserer CI/CD-Pipeline in Github Actions über.
Backend
Die Pipeline wird in .
Aber bevor wir dazu kommen, fügen wir in Github die benötigten Secret-Variablen ein. Dazu gehen wir zu Einstellungen -> Secrets:
DOCKER_REGISTRY— der Host unseres Docker-Repositorys (docker.helloworld.ru);DOCKER_LOGIN— Benutzername für das Docker-Repository;DOCKER_PASSWORD— Passwort dafür;DEPLOY_HOST— der Host, auf dem das Plesk-Admin-Panel verfügbar ist (Beispiel: :8443 oder :8443);DEPLOY_BACK_PROD_TOKEN— Token für das Deployment im Prod-Repository auf dem Server (wir haben ihn in Punkt 4 der Bereitstellung in Plesk erhalten);DEPLOY_BACK_DEV_TOKEN— Token für das Deployment im Dev-Repository auf dem Server.
Der Deployment-Prozess ist einfach und besteht aus drei Hauptschritten:
- Erstellen und Veröffentlichen des Images in unserem Repository;
- Ausführen von Tests im Container basierend auf dem frisch erstellten Image;
- Bereitstellung in die jeweilige Umgebung je nach Branche (dev/master).
Frontend
unterscheidet sich kaum vom Backend. Der Schritt zum Ausführen von Tests fehlt und die Namen der Token für das Deployment ändern sich. Die Secrets für das Front-Repository müssen übrigens separat ausgefüllt werden.
Website-Konfiguration
Traffic über Nginx proxyen
Nun, wir sind am Ende angekommen. Es bleibt nur noch, den eingehenden und ausgehenden Traffic über Nginx in unseren Container zu proxyen. Diesen Prozess haben wir bereits im Punkt 5 der Konfiguration des Docker Registry behandelt. Dasselbe muss für den Backend- und Frontend-Bereich in den Dev- und Prod-Umgebungen wiederholt werden.
Ich werde Screenshots der Einstellungen bereitstellen.
Backend

Frontend

Wichtige Klarstellung. Im Frontend-Container werden alle URLs außer denjenigen, die mit /api/ beginnen— diese werden in den Backend-Container proxyed (deshalb müssen im Backend-Container alle Handler mit /api/).
Ergebnisse
beginnen. Jetzt sollte unsere Website unter den Adressen helloworld.ru und dev.helloworld.ru (Prod- und Dev-Umgebungen entsprechend) verfügbar sein.
Insgesamt haben wir gelernt, wie man eine einfache Anwendung mit Flask und Angular erstellt und eine Pipeline in Github Actions für deren Bereitstellung auf einem Server unter Plesk einrichtet.
Ich werde die Links zu den Repositories mit dem Code wiederholen: , .
Quelle: habr.com
















