CI/CD in Github Actions voor een project op Flask+Angular

CI/CD in Github Actions voor een project op Flask+Angular
In dit artikel deel ik mijn ervaring met het instellen van CI/CD met behulp van het Plesk-bedieningspaneel en GitHub Actions. Vandaag gaan we leren hoe we een eenvoudig project met de onopvallende naam «Helloworld» kunnen implementeren. Het is geschreven in het Python-framework Flask, met workers op Celery en een frontend op Angular 8.

Links naar de repositories: backend, frontend.

In het eerste deel van het artikel bekijken we ons project en de onderdelen ervan. In het tweede deel zullen we onderzoeken hoe we Plesk kunnen instellen en de noodzakelijke uitbreidingen en componenten (DB, RabbitMQ, Redis, Docker, etc.) kunnen installeren.

In het derde deel zullen we eindelijk onderzoeken hoe we een pipeline kunnen instellen voor het implementeren van ons project op de server in dev- en prod-omgevingen. En daarna starten we de site op de server.

En ja, ik ben vergeten me voor te stellen. Ik heet Oleg Borzov, ik ben fullstack-ontwikkelaar in het CRM-team voor hypotheekbeheerder in Domklik.

Projectoverzicht

Laten we beginnen met de twee repositories van het project - de backend en de frontend - en de code doornemen.

Backend-gedeelte: Flask+Celery

Voor het backend-gedeelte heb ik een vrij populaire stack gekozen onder Python-ontwikkelaars: het Flask-framework (voor API) en Celery (voor de taakqueue). SQLAlchemy wordt gebruikt als ORM. Alembic wordt toegepast voor migraties. Voor JSON-validatie in de endpoints wordt Marshmallow gebruikt.

In de repository Er is een bestand Readme.md met een gedetailleerde beschrijving van de structuur en instructies voor het starten van het project.

API van het webgedeelte is vrij eenvoudig, bestaat uit 6 endpoints:

  • /ping — voor de beschikbaarheidscontrole;
  • endpoints voor registratie, autorisatie, de-autorisatie en het verkrijgen van de geautoriseerde gebruiker;
  • een endpoint voor het versturen van e-mail dat een taak in de Celery-queue plaatst.

Celery-gedeelte is nog eenvoudiger, er is slechts één taak send_mail_task.

In de map /conf bevat twee submappen:

  • docker met twee Docker-bestanden (base.dockerfile voor het bouwen van een zelden veranderend basisimage en Dockerfile voor de hoofdconstructies);
  • .env_files — met bestanden voor omgevingsvariabelen voor verschillende omgevingen.

In de hoofdmap van het project bevinden zich vier docker-compose-bestanden:

  • docker-compose.local.db.yml voor het opzetten van een lokale DB voor ontwikkeling;
  • docker-compose.local.workers.yml voor het lokaal opzetten van een worker, DB, Redis en RabbitMQ;
  • docker-compose.test.yml voor het uitvoeren van tests tijdens de implementatie;
  • docker-compose.yml voor de implementatie.

En de laatste interessante map voor ons — .ci-cd. Hierin bevinden zich shell-scripts voor implementatie:

  • deploy.sh — het starten van migraties en implementatie. Wordt uitgevoerd op de server na de bouw en het uitvoeren van tests in GitHub Actions;
  • rollback.sh — het terugdraaien van containers naar de vorige versie van de build;
  • curl_tg.sh — het versturen van meldingen over de implementatie naar Telegram.

Frontend op Angular

Repository met de frontend is veel eenvoudiger dan de backend. De frontend bestaat uit drie pagina's:

  • De homepage met een formulier voor het verzenden van e-mail en een uitlogknop.
  • Inlogpagina.
  • Registratiepagina.

De homepage ziet er eenvoudig uit:

CI/CD in Github Actions voor een project op Flask+Angular
In de root liggen twee bestanden Dockerfile en docker-compose.yml, evenals de bekende map .ci-cd met iets minder scripts dan in het backend-repository (de scripts voor het uitvoeren van tests zijn verwijderd).

We starten het project in Plesk

Laten we beginnen met het instellen van Plesk en het creëren van een abonnement voor onze site.

Installeren van extensies

In Plesk hebben we vier extensies nodig:

  • Docker voor het beheren en visueel weergeven van de status van containers in de Plesk-admin;
  • Git voor het instellen van de deploy-stap op de server;
  • Let's Encrypt voor het genereren (en automatisch verlengen) van gratis TLS-certificaten;
  • Firewall voor het instellen van filtering van binnenkomend verkeer.

Ze kunnen worden geïnstalleerd via de Plesk-admin in de sectie Extensies:

CI/CD in Github Actions voor een project op Flask+Angular
We zullen de gedetailleerde instellingen van de extensies niet bespreken; voor onze demo-doeleinden zijn de standaardinstellingen voldoende.

Aanmaken van een abonnement en site

Vervolgens moeten we een abonnement maken voor onze site helloworld.nl en daar het subdomein dev.helloworld.nl aan toevoegen.

  1. We creëren een abonnement voor het domein helloworld.nl en geven de login-wachtwoord op voor de systeemgebruiker:

    CI/CD in Github Actions voor een project op Flask+Angular
    Onder aan de pagina vink je het vakje aan Beveilig het domein met Let’s Encrypt, als we HTTPS voor de site willen instellen:

    CI/CD in Github Actions voor een project op Flask+Angular

  2. Vervolgens maken we in dit abonnement het subdomein dev.helloworld.nl aan (waarvoor ook een gratis TLS-certificaat kan worden uitgegeven):

    CI/CD in Github Actions voor een project op Flask+Angular

Installeren van servercomponenten

We hebben een server met OS Debian Stretch 9.12 en een geïnstalleerde beheerpanelen Plesk Obsidian 18.0.27.

We moeten voor ons project installeren en instellen:

  • PostgreSQL (in ons geval zal er één server zijn met twee DB's voor dev- en prod-omgevingen).
  • RabbitMQ (hetzelfde, één instantie met verschillende vhosts voor omgevingen).
  • Twee instanties van Redis (voor dev- en prod-omgevingen).
  • Docker Registry (voor lokale opslag van samengestelde Docker-images).
  • UI-interface voor Docker registry.

PostgreSQL

Bij Plesk wordt al een PostgreSQL-database meegeleverd, maar niet de nieuwste versie (op het moment van schrijven ondersteunde Plesk Obsidian Postgres versies 8.4–10.8). We willen echter de nieuwste versie voor onze applicatie (12.3 op het moment van schrijven), dus we zullen deze handmatig installeren. Er zijn tal van gedetailleerde instructies voor het installeren van Postgres op Debian online (

), dus ik zal ze niet uitgebreid beschrijven, maar gewoon de commando's geven:bijvoorbeeld), daarom zal ik ze niet in detail beschrijven, ik geef gewoon de opdrachten:

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

Aangezien de standaardinstellingen in PostgreSQL nogal gemiddeld zijn, is het noodzakelijk om de configuratie aan te passen. Dit kan ons helpen calculator: je moet de parameters van je server invoeren en de instellingen in het bestand /etc/postgresql/12/main/postgresql.confvervangen door de voorgestelde. Het is belangrijk op te merken dat dergelijke calculators geen wondermiddel zijn, en de database verder geoptimaliseerd moet worden op basis van jouw hardware, applicaties en de complexiteit van de queries. Maar voor een start is dit voldoende.

Naast de door de calculator voorgestelde instellingen, veranderen we in postgresql.confde standaardpoort 5432 naar een andere (in ons voorbeeld — 53983).

Na het wijzigen van het configuratiebestand herstarten we postgresql-server met de volgende opdracht:

service postgresql restart

We hebben PostgreSQL geïnstalleerd en geconfigureerd. Nu maken we een database, gebruikers voor dev- en prod-omgevingen, en geven we de gebruikers de rechten om de database te beheren:

$ 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

Laten we verder gaan met de installatie van RabbitMQ — de berichtenbroker voor Celery. Het wordt behoorlijk eenvoudig geïnstalleerd op Debian:

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

Na de installatie moeten we vhosts, gebruikers aanmaken en de benodigde rechten toekennen:

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

Laten we nu de laatste component voor onze applicatie installeren en configureren — Redis. Dit zal als backend dienen voor het opslaan van de resultaten van Celery-taken.

We zullen twee Docker-containers met Redis opzetten voor de dev- en prod-omgevingen met behulp van de extensie Docker voor Plesk.

  1. Ga naar Plesk, navigeer naar het gedeelte Extensies, zoek de Docker-extensie en installeer deze (we hebben de gratis versie nodig):

    CI/CD in Github Actions voor een project op Flask+Angular

  2. Ga naar de geïnstalleerde extensie, vind via de zoekfunctie de afbeelding redis bitnami en installeer de laatste versie:

    CI/CD in Github Actions voor een project op Flask+Angular

  3. Ga naar de gedownloade container en pas de configuratie aan: geef de poort op, de maximale toegewezen hoeveelheid RAM, het wachtwoord in de omgevingsvariabelen en mount de volume:

    CI/CD in Github Actions voor een project op Flask+Angular

  4. Voer stappen 2-3 uit voor de prod-container, wijzig alleen de parameters in de instellingen: poort, wachtwoord, RAM-grootte en het pad naar de map volume op de server:

    CI/CD in Github Actions voor een project op Flask+Angular

Docker Registry

Naast de basisservices zou het goed zijn om een eigen Docker-image repository op de server te plaatsen. Gelukkig is de opslagruimte op servers nu redelijk goedkoop (zeker goedkoper dan een abonnement op DockerHub), en het proces van het installeren van een privé-repository is heel eenvoudig.

We willen dat we hebben geïnstalleerd:

Daarvoor:

  1. Laten we in Plesk twee subdomeinen aanmaken in ons abonnement: docker.helloworld.ru en docker-ui.helloworld.ru, en laten we certificaten van Let's Encrypt voor hen instellen.
  2. In de map van het subdomein docker.helloworld.ru voegen we het bestand toe docker-compose.yml met de volgende inhoud:
    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. Genereer met SSH het bestand .htpasswd voor Basic-authenticatie in de Docker-repository:
    htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
  4. Laten we de containers bouwen en opstarten:
    docker-compose up -d
  5. En we moeten Nginx doorsturen naar onze containers. Dit kan via Plesk.

De volgende stappen moeten worden uitgevoerd voor de subdomeinen docker.helloworld.ru en docker-ui.helloworld.ru:

In de sectie Dev Tools van onze website gaan we naar Docker Proxy Rules:

CI/CD in Github Actions voor een project op Flask+Angular
En we voegen een regel toe voor het proxen van het binnenkomende verkeer naar onze container:

CI/CD in Github Actions voor een project op Flask+Angular

  1. Controleer of we kunnen inloggen op onze container vanaf de lokale machine:
    $ docker login docker.helloworld.ru -u hw_docker_admin -p hw_docker_password
    WARNING! Using --password via the CLI is insecure. Use --password-stdin.
    Login Succeeded
  2. Laten we ook de werking van het subdomein docker-ui.helloworld.ru controleren:

    CI/CD in Github Actions voor een project op Flask+Angular
    Wanneer u op Browse repositories klikt, toont de browser een venster voor authenticatie waarin u de gebruikersnaam en het wachtwoord voor de repository moet invoeren. Daarna worden we doorgestuurd naar de pagina met de lijst van repositories (deze zal voorlopig leeg zijn):

    CI/CD in Github Actions voor een project op Flask+Angular

Poorten openen in Plesk Firewall

Na het installeren en configureren van de componenten moeten we de poorten openen, zodat de componenten toegankelijk zijn vanuit Docker-containers en het externe netwerk.

Laten we bekijken hoe dit moet, aan de hand van de eerder geïnstalleerde Firewall-extensie voor Plesk.

  1. We gaan naar Tools & Settings > Instellingen > Firewall:
    CI/CD in Github Actions voor een project op Flask+Angular
  2. We gaan naar Pas Plesk Firewall-regels aan > Voeg aangepaste regel toe en open de volgende TCP-poorten voor de Docker-subnet (172.0.0.0/8):
    RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
    Redis: 32785, 32786

    CI/CD in Github Actions voor een project op Flask+Angular

  3. Laten we ook een regel toevoegen die de buitenwereld toegang geeft tot de PostgreSQL-poorten en de managementpanelen van RabbitMQ:

    CI/CD in Github Actions voor een project op Flask+Angular

  4. Pas de regels toe met de knop Wijzigingen toepassen:

    CI/CD in Github Actions voor een project op Flask+Angular

CI/CD-configuratie in Github Actions

Laten we beginnen met het spannendste gedeelte — het configureren van de continue integratie- en leveringspipeline voor ons project op de server.

Deze pipeline zal uit twee delen bestaan:

  • het bouwen van een image en het uitvoeren van tests (voor de backend) — aan de Github-kant;
  • migraties uitvoeren (voor de backend) en containers implementeren — op de server.

Implementatie in Plesk

Laten we eerst de tweede punt behandelen (aangezien de eerste daarvan afhankelijk is).

We zullen het implementatieproces configureren met behulp van de Git-extensie voor Plesk.

Laten we een voorbeeld bekijken met de Prod-omgeving voor de Backend-repository.

  1. We gaan naar het abonnement van onze Helloworld-website en navigeren naar het Git-subgedeelte:

    CI/CD in Github Actions voor een project op Flask+Angular

  2. Plak de link naar onze Github-repository in het veld 'Remote Git repository' en wijzig de standaardmap httpdocs in een andere (bijvoorbeeld, /httpdocs/hw_back):

    CI/CD in Github Actions voor een project op Flask+Angular

  3. Kopieer de SSH Public key van de vorige stap en toevoegen voeg deze toe in de instellingen van Github.
  4. Klik op OK op het scherm in punt 2, waarna we worden doorgestuurd naar de repositorypagina in Plesk. Nu moeten we de repository instellen zodat deze wordt bijgewerkt bij commits naar de master branch. Ga hiervoor naar Repository-instellingen en sla de waarde op Webhook URL (deze hebben we later nodig bij de configuratie van Github Actions):

    CI/CD in Github Actions voor een project op Flask+Angular

  5. Voer in het veld Acties op het scherm van de vorige stap het script in voor het starten van de implementatie:
    cd {REPOSITORY_ABSOLUTE_PATH}
    .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID} 

    waarbij:

    {REPOSITORY_ABSOLUTE_PATH} — het pad naar de map van de prod backend-repository op de server;
    {ENV} — omgeving (dev/prod), in ons geval prod;
    {DOCKER_REGISTRY_HOST} — de host van onze docker repository
    {TG_BOT_TOKEN} — de token van de Telegram-bot;
    {TG_CHAT_ID} — de ID van de chat/kanaal voor het verzenden van meldingen.

    Voorbeeld van het 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
  6. Laten we de gebruiker uit ons abonnement aan de Docker-groep toevoegen (zodat hij de containers kan beheren):
    sudo usermod -aG docker helloworld_admin

De ontwikkelomgeving voor de backend-repository en frontend wordt op dezelfde manier ingesteld.

Pipeline voor deployment in Github Actions

Laten we beginnen met het instellen van het eerste deel van onze CI/CD-pipeline in Github Actions.

Backend

De pipeline wordt beschreven in het bestand deploy.yml.

Maar voordat we dat bekijken, vullen we de benodigde geheimen in Github in. Ga hiervoor naar Instellingen -> Geheimen:

  • DOCKER_REGISTRY — het hostadres van onze Docker-repository (docker.helloworld.ru);
  • DOCKER_LOGIN — login voor de Docker-repository;
  • DOCKER_PASSWORD — wachtwoord hiervoor;
  • DEPLOY_HOST — het hostadres waar het Plesk-dashboard beschikbaar is (bijvoorbeeld: helloworld.ru:8443 of 123.4.56.78:8443);
  • DEPLOY_BACK_PROD_TOKEN — token voor deployment naar de prod-repository op de server (we hebben dit gekregen in Deploy in Plesk punt 4);
  • DEPLOY_BACK_DEV_TOKEN — token voor deployment naar de dev-repository op de server.

Het deploymentproces is eenvoudig en bestaat uit drie hoofd stappen:

  • het bouwen en publiceren van de afbeelding in onze repository;
  • het uitvoeren van tests in een container op basis van de vers gebouwde afbeelding;
  • de deployment naar de juiste omgeving afhankelijk van de tak (dev/master).

Frontend

Het bestand deploy.yml voor de front-end repository verschilt nauwelijks van de back-end. Het bevat geen stap voor het uitvoeren van tests en de namen van de tokens voor deployment zijn anders. Geheimen voor de front-end repository moeten trouwens apart worden ingevuld.

Website-instellingen

Traffic proxydelen via Nginx

Nou, we zijn aan het einde gekomen. We moeten alleen nog het inkomende en uitgaande verkeer naar onze container via Nginx instellen. Dit proces hebben we al besproken in punt 5 van de Docker Registry-instellingen. Dit moet voor de back-end en front-end in de dev- en prod-omgevingen worden herhaald.

Ik geef enkele screenshots van de instellingen.

Backend

CI/CD in Github Actions voor een project op Flask+Angular

Frontend

CI/CD in Github Actions voor een project op Flask+Angular
Belangrijke opmerking. In de frontend-container worden alle URL's geproxyd naar de backend-container, behalve die beginnen met /api/ — deze worden naar de backend-container geproxyd (daarom moeten alle handlers in de backend-container beginnen met /api/).

Conclusies

Nu moet onze site bereikbaar zijn via de adressen helloworld.ru en dev.helloworld.ru (respectievelijk prod- en dev-omgeving).

Samenvattend hebben we geleerd hoe we een eenvoudige applicatie op Flask en Angular kunnen voorbereiden en een pipeline in Github Actions kunnen instellen voor de deployment op een server die wordt beheerd door Plesk.

Hier zijn de links naar de repositories met de code: backend, frontend.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster