
In questo articolo condividerò la mia esperienza nella configurazione di CI/CD utilizzando il pannello di controllo Plesk e Github Actions. Oggi impareremo a distribuire un semplice progetto dal nome poco originale «Helloworld». È scritto nel framework Python Flask, con worker su Celery e frontend su Angular 8.
Link ai repository: , .
Nella prima parte dell'articolo daremo un'occhiata al nostro progetto e alle sue parti. Nella seconda, vedremo come configurare Plesk e installare le estensioni e i componenti necessari (DB, RabbitMQ, Redis, Docker, ecc.).
Nella terza parte, finalmente, scopriremo come configurare il pipeline per la distribuzione del nostro progetto sul server nell'ambiente dev e prod. E poi lanceremo il sito sul server.
E sì, ho dimenticato di presentarmi. Mi chiamo Oleg Borzov, sono uno sviluppatore fullstack nel team CRM per i gestori di mutui presso Domklik.
Panoramica del progetto
Per iniziare, diamo un'occhiata ai due repository del progetto — backend e frontend — e facciamo una rapida revisione del codice.
Parte backend: Flask+Celery
Per la parte backend ho scelto una combinazione piuttosto popolare tra gli sviluppatori Python: il framework Flask (per API) e Celery (per la queue tasks). Viene utilizzato SQLAlchemy come ORM. Alembic viene utilizzato per le migrazioni. Per la validazione del JSON nelle route viene impiegato Marshmallow.
In c'è un file Readme.md con una descrizione dettagliata della struttura e delle istruzioni per l'avvio del progetto.
abbastanza semplice, composta da 6 route:
/ping— per controllare la disponibilità;- route per registrazione, autenticazione, de-auth e per ottenere l'utente autenticato;
- route per inviare email, che inserisce un task nella coda Celery.
ancora più semplice, c'è solo un task send_mail_task.
Nella cartella ci sono due sottocartelle:
dockercon due Dockerfile (base.dockerfileper la costruzione di un'immagine di base che cambia raramente eDockerfileper le build principali);.env_files— con file delle variabili ambientali per diversi ambienti.
Nella radice del progetto ci sono quattro file docker-compose:
docker-compose.local.db.ymlper avviare un DB locale per lo sviluppo;docker-compose.local.workers.ymlper avviare localmente il worker, DB, Redis e RabbitMQ;docker-compose.test.ymlper eseguire test durante il deployment;docker-compose.ymlper la distribuzione.
E l'ultima cartella interessante per noi è . In essa ci sono script shell per il deployment:
deploy.sh— avvio delle migrazioni e del deployment. Viene eseguito sul server dopo la build e l'esecuzione dei test in Github Actions;rollback.sh— rollback dei container alla versione precedente della build;curl_tg.sh— invio di notifiche sul deployment a Telegram.
Frontend su Angular
is significantly simpler than the backend. The front consists of three pages:
- The main page with an email submission form and a logout button.
- Login page.
- Registration page.
The main page looks minimalistic:

There are two files in the root Dockerfile e docker-compose.yml, as well as the familiar folder .ci-cd with slightly fewer scripts than in the backend repository (scripts for running tests have been removed).
Setting up a project in Plesk
Let's start by configuring Plesk and creating a subscription for our website.
Installing extensions
We will need four extensions in Plesk:
Dockerto manage and visually display the status of containers in the Plesk admin panel;Gitto set the deployment step on the server;Let's Encryptfor generating (and auto-renewing) free TLS certificates;Firewallfor configuring incoming traffic filtering.
They can be installed through the Plesk admin panel in the Extensions section:

We will not go into detailed configuration of the extensions; the default settings will suffice for our demo purposes.
Creating a subscription and website
Next, we need to create a subscription for our website helloworld.ru and add the subdomain dev.helloworld.ru.
- We create a subscription for the domain helloworld.ru and specify the username-password for the system user:

At the bottom of the page, we check the box Secure the domain with Let’s Encrypt, if we want to set up HTTPS for the site:
- Next, in this subscription, we create the subdomain dev.helloworld.ru (for which a free TLS certificate can also be issued):

Installing server components
We have a server with OS Debian Stretch 9.12 and the control panel installed Plesk Obsidian 18.0.27.
We need to install and configure for our project:
- PostgreSQL (in our case, it will be one server with two databases for the dev and prod environments).
- RabbitMQ (the same, one instance with different vhosts for the environments).
- Two instances of Redis (for the dev and prod environments).
- Docker Registry (for local storage of built Docker images).
- UI for Docker registry.
PostgreSQL
Plesk already comes with a PostgreSQL DBMS, although not the most recent version (at the time of writing, Plesk Obsidian Postgres versions 8.4–10.8). We want the latest version for our application (12.3 at the time of writing), so we will install it manually.
There are plenty of detailed instructions for installing Postgres on Debian online (), so I won't describe them in detail, just provide the commands:
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
Poiché in PostgreSQL le impostazioni predefinite sono piuttosto mediocri, è indispensabile modificare la configurazione. A questo ci aiuterà : bisogna inserire i parametri del proprio server e sostituire le impostazioni nel file /etc/postgresql/12/main/postgresql.confcon quelle suggerite. È importante dire che tali calcolatori non sono una panacea e il database deve essere ottimizzato in modo più mirato, a seconda dell'hardware, dell'applicazione e della complessità delle query. Ma per iniziare, questo è sufficiente.
Oltre alle impostazioni suggerite dal calcolatore, modifichiamo anche , affinché il tuo database di test non voglia effettuare un backup silenziosamente.la porta predefinita 5432 in un'altra (nel nostro esempio — 53983).
Dopo aver modificato il file di configurazione, riavviamo il postgresql-server con il comando:
service postgresql restart
Abbiamo installato e configurato PostgreSQL. Ora creiamo un database, utenti per gli ambienti dev e prod, e concediamo agli utenti diritti di gestione del database:
$ 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
Passiamo all'installazione di RabbitMQ — il broker di messaggi per Celery. Si installa su Debian piuttosto facilmente:
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
Dopo l'installazione, dobbiamo creare vhosts, utenti e concedere i diritti necessari:
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
Ora installiamo e configuriamo l'ultimo componente per la nostra applicazione — Redis. Sarà utilizzato come backend per memorizzare i risultati dei task di Celery.
Installeremo due contenitori Docker con Redis per gli ambienti dev e prod utilizzando l'estensione Docker per Plesk.
- Accediamo a Plesk, andiamo alla sezione Estensioni, cerchiamo l'estensione Docker e la installiamo (abbiamo bisogno della versione gratuita):

- Andiamo all'estensione installata, troviamo tramite ricerca l'immagine
redis bitnamie installiamo l'ultima versione:
- Entriamo nel container scaricato e modifichiamo la configurazione: indichiamo la porta, la dimensione massima della RAM, la password nelle variabili d'ambiente e montiamo il volume:

- Eseguiamo i passaggi 2-3 per il container prod, nelle impostazioni cambiamo solo i parametri: porta, password, dimensione della RAM e percorso della cartella volume sul server:

Docker Registry
Oltre ai servizi di base, sarebbe utile installare sul server un proprio repository di immagini Docker. Dato che lo spazio sui server è attualmente piuttosto economico (sicuramente più economico di un abbonamento a DockerHub), e il processo di installazione di un repository privato è molto semplice.
Vogliamo installare:
- un repository Docker protetto da password, accessibile tramite sottodominio ;
- Interfaccia UI per visualizzare le immagini nel repository, accessibile all'indirizzo .
Per questo:
- Creeremo in Plesk due sottodomini nel nostro abbonamento: docker.helloworld.ru e docker-ui.helloworld.ru, e configureremo per loro i certificati Let’s Encrypt.
- Nella cartella del sottodominio docker.helloworld.ru aggiungiamo il file
docker-compose.ymlcon il seguente contenuto: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' - Tramite SSH generiamo il file .htpasswd per l'autenticazione Base nel repository Docker:
htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password - Costruiamo e avviamo i container:
docker-compose up -d - E dobbiamo indirizzare Nginx ai nostri container. Possiamo farlo tramite Plesk.
Le seguenti operazioni devono essere eseguite per i sottodomini docker.helloworld.ru e docker-ui.helloworld.ru:
Nella sezione Strumenti per sviluppatori del nostro sito andiamo su Regole Proxy Docker:

E aggiungiamo una regola per il proxy del traffico in entrata nel nostro container:

- Verifichiamo di poter accedere al nostro container dalla macchina locale:
$ docker login docker.helloworld.ru -u hw_docker_admin -p hw_docker_password ATTENZIONE! L'uso di --password tramite CLI è insicuro. Utilizzare --password-stdin. Login riuscito - Verifichiamo anche il funzionamento del sottodominio docker-ui.helloworld.ru:

Quando clicchi su Browse repositories, il browser visualizzerà una finestra di autorizzazione in cui dovrai inserire il nome utente e la password per il repository. Successivamente, verrai reindirizzato a una pagina con l'elenco dei repository (che al momento sarà vuota):
Aprire le porte nel Firewall di Plesk
Dopo l'installazione e la configurazione dei componenti, dobbiamo aprire le porte affinché i componenti siano accessibili dai container Docker e dalla rete esterna.
Vediamo come fare, prendendo come esempio l'estensione Firewall precedentemente installata in Plesk.
- Passiamo a Strumenti & Impostazioni > Impostazioni > Firewall:

- Passiamo a Modifica delle Regole del Firewall di Plesk > Aggiungi Regola Personalizzata e apriamo le seguenti porte TCP per la subnet Docker (172.0.0.0/8):
RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
Redis: 32785, 32786
- Aggiungiamo anche una regola che apra al mondo esterno le porte per PostgreSQL e il pannello di gestione di RabbitMQ:

- Applichiamo le regole premendo il pulsante Applica Modifiche:

Configurazione CI/CD in Github Actions
Iniziamo con la parte più interessante: configurare il pipeline di integrazione continua e delivery del nostro progetto sul server.
Questo pipeline sarà composto da due parti:
- costruzione dell'immagine e esecuzione dei test (per il backend) — lato Github;
- esecuzione delle migrazioni (per il backend) e deploy dei container — sul server.
Deploy in Plesk
Iniziamo con il secondo punto (dato che il primo ne dipende).
Configureremo il processo di deploy utilizzando l'estensione Git per Plesk.
Consideriamo un esempio con l'ambiente Prod per il repository Backend.
- Accediamo all'abbonamento del nostro sito Helloworld e andiamo alla sezione Git:

- Incolliamo nel campo "Remote Git repository" il link al nostro repository Github e cambiamo la cartella predefinita
httpdocsin un'altra (ad esempio,/httpdocs/hw_back):
- Copia la chiave pubblica SSH dal passaggio precedente e inseriscila nelle impostazioni di Github.
- Clicca su OK nella schermata al punto 2, dopo di che verrai reindirizzato alla pagina del repository in Plesk. Ora dobbiamo configurare l'aggiornamento del repository con i commit nel branch master. Per fare ciò, passiamo a Impostazioni del Repository e salviamo il valore
Webhook URL(ci servirà più avanti nella configurazione di Github Actions):
- Nel campo Actions nella schermata del passaggio precedente, inseriamo lo script per avviare il deploy:
cd {REPOSITORY_ABSOLUTE_PATH} .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID}dove:
{REPOSITORY_ABSOLUTE_PATH}— il percorso della cartella del repository backend prod sul server;
{ENV}— ambiente (dev/prod), nel nostro casoprod;
{DOCKER_REGISTRY_HOST}— host del nostro repository docker
{TG_BOT_TOKEN}— token del bot di Telegram;
{TG_CHAT_ID}— ID della chat/canale per inviare notifiche.Esempio di script:
cd /var/www/vhosts/helloworld.ru/httpdocs/hw_back/ .ci-cd/deploy.sh dev docker.helloworld.ru docker_user docker_password 12345678:AAbcdEfghCH1vGbCasdfSAs0K5PALDsaw -1001234567890 - Aggiungiamo un utente dal nostro abbonamento al gruppo Docker (in modo che possa gestire i container):
sudo usermod -aG docker helloworld_admin
L'ambiente Dev per il repository backend e frontend è configurato in modo simile.
Pipeline di deployment in Github Actions
Procediamo alla configurazione della prima parte del nostro CI/CD pipeline in Github Actions.
Backend
Il pipeline è descritto nel .
Ma prima di esaminarlo, dobbiamo riempire le variabili Secret di cui abbiamo bisogno in Github. A tal fine, andiamo su Impostazioni -> Segreti:
DOCKER_REGISTRY— l'host del nostro repository Docker (docker.helloworld.ru);DOCKER_LOGIN— login per il repository Docker;DOCKER_PASSWORD— password per esso;DEPLOY_HOST— l'host in cui è disponibile il pannello di amministrazione Plesk (esempio: :8443 o :8443);DEPLOY_BACK_PROD_TOKEN— token per il deployment nel repository di produzione sul server (lo abbiamo ottenuto in Deployment in Plesk p. 4);DEPLOY_BACK_DEV_TOKEN— token per il deployment nel repository di sviluppo sul server.
Il processo di deployment è semplice e consiste in tre passaggi principali:
- build e pubblicazione dell'immagine nel nostro repository;
- esecuzione dei test nel container basato sull'immagine appena costruita;
- deployment nell'ambiente necessario a seconda del ramo (dev/master).
Frontend
differisce poco da quello backend. Manca il passaggio di esecuzione dei test e i nomi dei token per il deployment vengono modificati. I segreti per il repository frontend, tra l'altro, devono essere riempiti separatamente.
Configurazione del sito
Proxy del traffico tramite Nginx
Bene, siamo arrivati alla fine. Resta solo da configurare il proxy del traffico in entrata e in uscita nel nostro container tramite Nginx. Questo processo è stato già esaminato nel punto 5 della configurazione del Docker Registry. Lo stesso deve essere ripetuto per le parti backend e frontend negli ambienti dev e prod.
Mostrerò degli screenshot delle impostazioni.
Backend

Frontend

Importante precisazione. Nel container frontend verranno proxy tutti gli URL, tranne quelli che iniziano con /api/ — essi saranno router nel container backend (perciò nel container backend tutti i gestori devono iniziare con /api/).
Conclusioni
Ora il nostro sito dovrebbe essere accessibile agli indirizzi helloworld.ru e dev.helloworld.ru (rispettivamente per gli ambienti prod e dev).
In conclusione, abbiamo appreso come preparare una semplice applicazione su Flask e Angular e configurare un pipeline in Github Actions per il suo deployment su un server gestito da Plesk.
Ripeterò i link ai repository con il codice: , .
Fonte: habr.com
















