CI/CD i Github Actions för ett Flask+Angular-projekt

CI/CD i Github Actions för ett Flask+Angular-projekt
I den här artikeln kommer jag att dela med mig av min erfarenhet av att ställa in CI/CD med Plesk Kontrollpanel och Github Actions. Idag kommer vi att lära oss hur man distribuerar ett enkelt projekt med det okomplicerade namnet "Helloworld". Det är skrivet i Flask Python-ramverket, med Celery-arbetare och en Angular 8-frontend.

Länkar till arkiv: backend, frontend.

I den första delen av artikeln kommer vi att titta på vårt projekt och dess delar. I den andra kommer vi att ta reda på hur man ställer in Plesk och installerar nödvändiga tillägg och komponenter (DB, RabbitMQ, Redis, Docker, etc.).

I den tredje delen kommer vi äntligen att ta reda på hur man sätter upp en pipeline för att distribuera vårt projekt till en server i en dev- och prod-miljö. Och sedan kommer vi att starta sajten på servern.

Och ja, jag glömde att presentera mig. Jag heter Oleg Borzov, jag är en fullstack-utvecklare i CRM-teamet för bolåneförvaltare på Domclick.

Projektöversikt

Låt oss först titta på två projektförråd – backend och front – och gå igenom koden.

Backend: Kolv+selleri

För den bakre delen tog jag ett gäng som är ganska populärt bland Python-utvecklare: Flask-ramverket (för API) och Selleri (för uppgiftskön). SQLAchemy används som ORM. Alembic används för migrationer. För JSON-validering i handtag - Marshmallow.

В förråd det finns en Readme.md-fil med en detaljerad beskrivning av strukturen och instruktioner för att köra projektet.

Web Part API ganska okomplicerad, består av 6 pennor:

  • /ping - för att kontrollera tillgänglighet;
  • hanterar för registrering, auktorisering, avauktorisering och att få en auktoriserad användare;
  • ett e-posthandtag som placerar en uppgift i Selleri-kön.

Selleri del ännu lättare, det finns bara ett problem send_mail_task.

I mappen /konf det finns två undermappar:

  • docker med två dockerfiler (base.dockerfile att bygga en sällan föränderlig basbild och Dockerfile för huvudenheter);
  • .env_files - med filer med miljövariabler för olika miljöer.

Det finns fyra docker-compose-filer i roten av projektet:

  • docker-compose.local.db.yml att skapa en lokal databas för utveckling;
  • docker-compose.local.workers.yml för lokal höjning av arbetaren, databasen, Redis och RabbitMQ;
  • docker-compose.test.yml att köra tester under driftsättning;
  • docker-compose.yml för utplacering.

Och den sista foldern vi är intresserade av - .ci-cd. Den innehåller skalskript för distribution:

  • deploy.sh — Lansering av migrering och utbyggnad. Körs på servern efter att ha byggt och kört tester i Github Actions;
  • rollback.sh - tillbakarullning av containrar till den tidigare versionen av monteringen;
  • curl_tg.sh - skicka distributionsmeddelanden till Telegram.

Frontend på Angular

Förvar med front mycket enklare än Becks. Framsidan består av tre sidor:

  • Huvudsida med ett formulär för att skicka e-post och en utgångsknapp.
  • Login sida.
  • Registreringssida.

Huvudsidan ser asketisk ut:

CI/CD i Github Actions för ett Flask+Angular-projekt
Det finns två filer i roten Dockerfile и docker-compose.yml, såväl som den välbekanta mappen .ci-cd med något färre skript än i det bakre arkivet (borttagna skript för att köra tester).

Starta ett projekt i Plesk

Låt oss börja med att konfigurera Plesk och skapa en prenumeration på vår webbplats.

Installerar tillägg

I Plesk behöver vi fyra tillägg:

  • Docker att hantera och visuellt visa status för behållare i Plesks adminpanel;
  • Git att konfigurera distributionssteget på servern;
  • Let's Encrypt att generera (och automatiskt förnya) gratis TLS-certifikat;
  • Firewall för att konfigurera filtrering av inkommande trafik.

Du kan installera dem via Plesks adminpanel i avsnittet Tillägg:

CI/CD i Github Actions för ett Flask+Angular-projekt
Vi kommer inte att överväga de detaljerade inställningarna för tillägg, standardinställningarna kommer att göra för våra demoändamål.

Skapa en prenumeration och webbplats

Därefter måste vi skapa en prenumeration på vår helloworld.ru-webbplats och lägga till underdomänen dev.helloworld.ru där.

  1. Skapa en prenumeration för domänen helloworld.ru och ange inloggningslösenordet för systemanvändaren:

    CI/CD i Github Actions för ett Flask+Angular-projekt
    Markera rutan längst ner på sidan Säkra domänen med Let's Encryptom vi vill ställa in HTTPS för webbplatsen:

    CI/CD i Github Actions för ett Flask+Angular-projekt

  2. Därefter, i den här prenumerationen, skapa en underdomän dev.helloworld.ru (för vilken du också kan utfärda ett gratis TLS-certifikat):

    CI/CD i Github Actions för ett Flask+Angular-projekt

Installera serverkomponenter

Vi har en server med OS Debian Stretch 9.12 och installerad kontrollpanel Plesk Obsidian 18.0.27.

Vi behöver installera och konfigurera för vårt projekt:

  • PostgreSQL (i vårt fall kommer det att finnas en server med två databaser för dev- och prod-miljöer).
  • RabbitMQ (samma, samma instans med olika vhosts för miljöer).
  • Två Redis-instanser (för dev- och prod-miljöer).
  • Docker Registry (för lokal lagring av byggda Docker-bilder).
  • UI för Docker-registret.

PostgreSQL

Plesk kommer redan med PostgreSQL DBMS, men inte den senaste versionen (i skrivande stund Plesk Obsidian stöds Postgres version 8.4–10.8). Vi vill ha den senaste versionen för vår applikation (12.3 när detta skrivs), så vi kommer att installera det manuellt.

Det finns många detaljerade instruktioner för att installera Postgres på Debian på nätet (exempel), så jag kommer inte att beskriva dem i detalj, jag ger bara kommandona:

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

Med tanke på att PostgreSQL har ganska mediokra standardinställningar är det nödvändigt att korrigera konfigurationen. Detta kommer att hjälpa oss kalkylator: du måste köra in parametrarna för din server och ersätta inställningarna i filen /etc/postgresql/12/main/postgresql.conftill de som erbjuds. Det bör noteras här att sådana räknare inte är en magisk kula, och basen bör ställas in mer exakt, baserat på din hårdvara, applikation och frågekomplexitet. Men det här räcker för att komma igång.

Förutom de inställningar som räknaren föreslår, ändrar vi även in postgresql.confstandardporten 5432 till en annan (i vårt exempel - 53983).

Efter att ha ändrat konfigurationsfilen, starta om postgresql-server med kommandot:

service postgresql restart

Vi har installerat och konfigurerat PostgreSQL. Låt oss nu skapa en databas, användare för dev- och prod-miljöer, och ge användarna rättigheter att hantera databasen:

$ 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

Låt oss gå vidare till att installera RabbitMQ, en meddelandeförmedlare för selleri. Att installera det på Debian är ganska enkelt:

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

Efter installationen måste vi skapa vhosts, användare och ge nödvändiga rättigheter:

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

Låt oss nu installera och konfigurera den sista komponenten för vår applikation - Redis. Den kommer att användas som en backend för att lagra resultaten av Selleri-uppgifter.

Vi kommer att ta upp två Docker-containrar med Redis för dev- och prod-miljöer med hjälp av tillägget Docker för Plesk.

  1. Vi går till Plesk, går till avsnittet Extensions, letar efter Docker-tillägget och installerar det (vi behöver en gratisversion):

    CI/CD i Github Actions för ett Flask+Angular-projekt

  2. Gå till det installerade tillägget, hitta bilden genom sökningen redis bitnami och installera den senaste versionen:

    CI/CD i Github Actions för ett Flask+Angular-projekt

  3. Vi går in i den nedladdade behållaren och justerar konfigurationen: ange porten, den maximala tilldelade RAM-storleken, lösenordet i miljövariablerna och montera volymen:

    CI/CD i Github Actions för ett Flask+Angular-projekt

  4. Vi utför steg 2-3 för prod-behållaren, i inställningarna ändrar vi bara parametrarna: port, lösenord, RAM-storlek och sökväg till volymmappen på servern:

    CI/CD i Github Actions för ett Flask+Angular-projekt

Docker-registret

Förutom grundläggande tjänster skulle det vara trevligt att lägga ditt eget Docker-bildarkiv på servern. Lyckligtvis är serverutrymme nu ganska billigt (säkert billigare än en DockerHub-prenumeration), och processen att sätta upp ett privat arkiv är mycket enkel.

Vi vill ha:

För att göra detta:

  1. Låt oss skapa två underdomäner i Plesk i vår prenumeration: docker.helloworld.ru och docker-ui.helloworld.ru, och konfigurera Let's Encrypt-certifikat för dem.
  2. Lägg till filen i underdomänmappen docker.helloworld.ru docker-compose.yml med innehåll som detta:
    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. Under SSH kommer vi att generera .htpasswd-filen för grundläggande auktorisering i Docker-förvaret:
    htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
  4. Samla och lyft behållare:
    docker-compose up -d
  5. Och vi måste omdirigera Nginx till våra containrar. Detta kan göras genom Plesk.

Följande steg måste utföras för underdomänerna docker.helloworld.ru och docker-ui.helloworld.ru:

I avsnitt Dev-verktyg vår sida gå till Docker proxy regler:

CI/CD i Github Actions för ett Flask+Angular-projekt
Och lägg till en regel för proxy för inkommande trafik till vår behållare:

CI/CD i Github Actions för ett Flask+Angular-projekt

  1. Vi kontrollerar att vi kan logga in på vår container från den lokala maskinen:
    $ 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. Låt oss också kontrollera funktionen för underdomänen docker-ui.helloworld.ru:

    CI/CD i Github Actions för ett Flask+Angular-projekt
    När du klickar på Bläddra i arkiv kommer webbläsaren att visa ett auktoriseringsfönster där du måste ange användarnamn och lösenord för arkivet. Efter det kommer vi att överföras till en sida med en lista över arkiv (för nu kommer den att vara tom för dig):

    CI/CD i Github Actions för ett Flask+Angular-projekt

Öppnar portar i Plesk Firewall

Efter att ha installerat och konfigurerat komponenterna måste vi öppna portar så att komponenterna är åtkomliga från Docker-containrar och det externa nätverket.

Låt oss se hur du gör detta med brandväggstillägget för Plesk som vi installerade tidigare.

  1. Gå till Verktyg och inställningar > Inställningar > Brandvägg:
    CI/CD i Github Actions för ett Flask+Angular-projekt
  2. Gå till Ändra Plesk-brandväggsregler > Lägg till anpassad regel och öppna följande TCP-portar för Docker-undernätet (172.0.0.0 / 8):
    RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
    Redis: 32785, 32786

    CI/CD i Github Actions för ett Flask+Angular-projekt

  3. Vi kommer också att lägga till en regel som öppnar PostgreSQL-portar och RabbitMQ-hanteringspaneler för omvärlden:

    CI/CD i Github Actions för ett Flask+Angular-projekt

  4. Tillämpa reglerna med knappen Tillämpa ändringar:

    CI/CD i Github Actions för ett Flask+Angular-projekt

Konfigurera CI/CD i Github Actions

Låt oss komma ner till den mest intressanta delen - att sätta upp en kontinuerlig integrationspipeline och leverera vårt projekt till servern.

Denna pipeline kommer att bestå av två delar:

  • bygga en bild och köra tester (för backend) - på Github-sidan;
  • köra migreringar (för backend) och distribuera behållare - på servern.

Distribuera till Plesk

Låt oss ta itu med den andra punkten först (eftersom den första beror på den).

Vi kommer att konfigurera distributionsprocessen med Git-tillägget för Plesk.

Tänk på ett exempel med en Prod-miljö för ett Backend-förråd.

  1. Vi går till prenumerationen på vår Helloworld-webbplats och går till undersektionen Git:

    CI/CD i Github Actions för ett Flask+Angular-projekt

  2. Infoga en länk till vårt Github-förråd i fältet "Remote Git-repository" och ändra standardmappen httpdocs till en annan (t. /httpdocs/hw_back):

    CI/CD i Github Actions för ett Flask+Angular-projekt

  3. Kopiera SSH Public-nyckeln från föregående steg och Lägg till det finns i Github-inställningarna.
  4. Klicka på OK på skärmen i steg 2, varefter vi omdirigeras till förvarssidan i Plesk. Nu måste vi konfigurera arkivet så att det uppdateras på commits till huvudgrenen. För att göra detta, gå till Lagringsinställningar och spara värdet Webhook URL (vi kommer att behöva det senare när vi ställer in Github Actions):

    CI/CD i Github Actions för ett Flask+Angular-projekt

  5. I fältet Åtgärder på skärmen från föregående stycke anger du skriptet för att starta distributionen:
    cd {REPOSITORY_ABSOLUTE_PATH}
    .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID} 

    där:

    {REPOSITORY_ABSOLUTE_PATH} - sökväg till prod-mappen för backend-förvaret på servern;
    {ENV} - miljö (dev/prod), i vårt fall prod;
    {DOCKER_REGISTRY_HOST} - värden för vårt docker-förråd
    {TG_BOT_TOKEN} — Telegram bot-token;
    {TG_CHAT_ID} — ID för chatten/kanalen för att skicka aviseringar.

    Skriptexempel:

    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. Lägg till en användare från vår prenumeration till Docker-gruppen (så att de kan hantera behållare):
    sudo usermod -aG docker helloworld_admin

Utvecklingsmiljön för backend-förvaret och frontend är inställda på samma sätt.

Implementeringspipeline i Github Actions

Låt oss gå vidare till att installera den första delen av vår CI/CD-pipeline i Github Actions.

backend

Rörledningen beskrivs i deploy.yml filen.

Men innan vi analyserar det, låt oss fylla i de Secret-variabler vi behöver i Github. För att göra detta, gå till Inställningar -> Hemligheter:

  • DOCKER_REGISTRY - värden för vårt Docker-förråd (docker.helloworld.ru);
  • DOCKER_LOGIN - logga in på Docker-förrådet;
  • DOCKER_PASSWORD - lösenord till det;
  • DEPLOY_HOST — värd där Plesks adminpanel är tillgänglig (exempel: helloworld.com:8443 eller 123.4.56.78:8443);
  • DEPLOY_BACK_PROD_TOKEN - en token för distribution till prod-repository på servern (vi fick den i Deployment in Plesk s. 4);
  • DEPLOY_BACK_DEV_TOKEN - token för distribution till dev-förvaret på servern.

Implementeringsprocessen är enkel och består av tre huvudsteg:

  • bygga och publicera bilden i vårt arkiv;
  • köra tester i en container baserad på en nybyggd bild;
  • distribution till önskad miljö beroende på gren (dev/master).

Frontend

Filen deploy.yml för det främre arkivet lite annorlunda än Becks. Det saknar ett steg med att köra tester och ändrar namnen på tokens för distribution. Hemligheter för det främre arkivet måste förresten fyllas i separat.

Sajtinställningar

Proxytrafik genom Nginx

Nåväl, vi har kommit till slutet. Det återstår bara att konfigurera proxy för inkommande och utgående trafik till vår container via Nginx. Vi har redan täckt denna process i steg 5 i Docker Registry-installationen. Samma sak bör upprepas för de bakre och främre delarna i dev- och prodmiljöer.

Jag kommer att tillhandahålla skärmdumpar av inställningarna.

backend

CI/CD i Github Actions för ett Flask+Angular-projekt

Frontend

CI/CD i Github Actions för ett Flask+Angular-projekt
Viktigt förtydligande. Alla webbadresser kommer att skickas som proxy till frontend-behållaren, förutom de som börjar med /api/ - de kommer att skickas till den bakre behållaren (så i den bakre behållaren ska alla hanterare börja med /api/).

Resultat av

Nu bör vår sida vara tillgänglig på helloworld.ru och dev.helloworld.ru (prod- och dev-miljöer, respektive).

Totalt lärde vi oss hur man förbereder en enkel applikation i Flask och Angular och satte upp en pipeline i Github Actions för att rulla ut den till en server som kör Plesk.

Jag kommer att duplicera länkarna till arkiven med koden: backend, frontend.

Källa: will.com

Lägg en kommentar