CI/CD w GitHub Actions dla projektu na Flask+Angular

CI/CD w GitHub Actions dla projektu na Flask+Angular
W tym artykule podzielę się swoim doświadczeniem w ustawianiu CI/CD z wykorzystaniem panelu sterowania Plesk i Github Actions. Dziś nauczymy się wdrażać prosty projekt o niezbyt skomplikowanej nazwie „Helloworld”. Został napisany w frameworku Python Flask, z workerami na Celery i frontendem na Angular 8.

Linki do repozytoriów: backend, frontend.

W pierwszej części artykułu przyjrzymy się naszemu projektowi i jego elementom. W drugiej — rozwiążemy, jak skonfigurować Plesk oraz zainstalować niezbędne rozszerzenia i komponenty (Baza Danych, RabbitMQ, Redis, Docker itp.).

W trzeciej części w końcu zrozumiemy, jak skonfigurować pipeline do wdrożenia naszego projektu na serwerze w środowisku dev i prod. A potem uruchomimy stronę na serwerze.

A tak, zapomniałem się przedstawić. Nazywam się Oleg Borzow, jestem programistą fullstack w zespole CRM dla menedżerów kredytów hipotecznych w Domklik.

Przegląd projektu

Na początek rozważymy dwa repozytoria projektu — backendu i frontu — i przejdziemy przez kod.

Część backendowa: Flask+Celery

Do części backendowej wybrałem dość popularne wśród programistów Pythona połączenie: framework Flask (do API) oraz Celery (do kolejek zadań). Jako ORM używana jest SQLAlchemy. Do migracji stosuje się Alembic. Do walidacji JSON w endpointach używamy Marshmallow.

W repozytorium jest plik Readme.md z dokładnym opisem struktury i instrukcjami uruchomienia projektu.

API części webowej dość proste, składa się z 6 endpointów:

  • /ping — do sprawdzania dostępności;
  • endpointy do rejestracji, autoryzacji, deautoryzacji i uzyskiwania zautoryzowanego użytkownika;
  • endpoint do wysyłania e-maili, który umieszcza zadanie w kolejce Celery.

Część Celery jeszcze prostsza, tam jest tylko jedno zadanie send_mail_task.

W folderze /conf są dwa podfoldery:

  • docker z dwoma plikami Docker (base.dockerfile do budowy rzadko zmieniającego się podstawowego obrazu oraz Dockerfile do głównych budów);
  • .env_files — z plikami z zmiennymi środowiskowymi dla różnych środowisk.

W głównym katalogu projektu znajdują się cztery pliki docker-compose:

  • docker-compose.local.db.yml do uruchomienia lokalnej bazy danych do rozwoju;
  • docker-compose.local.workers.yml do lokalnego uruchomienia workera, Bazy Danych, Redis i RabbitMQ;
  • docker-compose.test.yml do uruchamiania testów przy wdrożeniu;
  • docker-compose.yml do wdrożeń.

A ostatnia interesująca nas folder — .ci-cd. Znajdują się w niej skrypty shellowe do wdrażania:

  • deploy.sh — uruchomienie migracji i wdrożenia. Uruchamia się na serwerze po zbudowaniu i uruchomieniu testów w Github Actions;
  • rollback.sh — przywrócenie kontenerów do poprzedniej wersji budowy;
  • curl_tg.sh — wysyłanie powiadomień o wdrożeniu do Telegramu.

Frontend na Angular

Repozytorium z frontendem znacznie prostszy niż backend. Frontend składa się z trzech stron:

  • Strona główna z formularzem do wysyłania e-maili i przyciskiem wyjścia.
  • Strona logowania.
  • Strona rejestracji.

Strona główna wygląda ascetycznie:

CI/CD w GitHub Actions dla projektu na Flask+Angular
W katalogu głównym znajdują się dwa pliki Dockerfile i docker-compose.yml, a także znana nam folder .ci-cd z nieco mniejszą ilością skryptów niż w repozytorium backendowym (usunięto skrypty do uruchamiania testów).

Zakładamy projekt w Plesk

Zacznijmy od konfiguracji Plesk i utworzenia subskrypcji dla naszej strony.

Instalacja rozszerzeń

W Plesk będziemy potrzebować czterech rozszerzeń:

  • Docker do zarządzania i wizualizacji stanu kontenerów w panelu Plesk;
  • Gitem do konfiguracji kroku deploymentu na serwerze;
  • Let's Encrypt do generowania (i automatycznego przedłużania) darmowych certyfikatów TLS;
  • Firewall do konfiguracji filtracji ruchu przychodzącego.

Można je zainstalować przez panel administracyjny Plesk w sekcji Rozszerzenia:

CI/CD w GitHub Actions dla projektu na Flask+Angular
Szczegółowej konfiguracji rozszerzeń nie będziemy omawiać, do naszych celów demo wystarczą ustawienia domyślne.

Tworzenie subskrypcji i strony

Następnie musimy utworzyć subskrypcję dla naszej strony helloworld.ru i dodać subdomenę dev.helloworld.ru.

  1. Tworzymy subskrypcję dla domeny helloworld.ru i podajemy login-hasło dla użytkownika systemowego:

    CI/CD w GitHub Actions dla projektu na Flask+Angular
    Na dole strony zaznaczamy Zabezpiecz domenę za pomocą Let’s Encrypt, jeśli chcemy skonfigurować HTTPS dla strony:

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  2. Następnie w tej subskrypcji tworzymy subdomenę dev.helloworld.ru (dla której również można wydać darmowy certyfikat TLS):

    CI/CD w GitHub Actions dla projektu na Flask+Angular

Instalacja komponentów serwerowych

Mamy serwer z OS Debian Stretch 9.12 i zainstalowanym panelem zarządzania Plesk Obsidian 18.0.27.

Musimy zainstalować i skonfigurować dla naszego projektu:

  • PostgreSQL (w naszym przypadku będzie jeden serwer z dwiema bazami danych dla środowiska dev i prod).
  • RabbitMQ (to samo, jedna instancja z różnymi vhostami dla środowisk).
  • Dwie instancje Redis (dla środowisk dev i prod).
  • Docker Registry (do lokalnego przechowywania zbudowanych obrazów Docker).
  • Interfejs UI dla Docker registry.

PostgreSQL

Wraz z Plesk już zawiera bazę danych PostgreSQL, ale nie najnowszej wersji (w momencie pisania artykułu Plesk Obsidian wspierał Postgresa w wersjach 8.4–10.8). Chcemy jednak dla naszej aplikacji najnowszą wersję (12.3 w momencie pisania artykułu), więc zainstalujemy ją ręcznie.

Szczegółowych instrukcji dotyczących instalacji Postgresa na Debianie w sieci jest wiele (przykład), więc szczegółowo ich nie opiszę, po prostu podam komendy:

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

Biorąc pod uwagę, że PostgreSQL ma dość przeciętne ustawienia domyślne, konieczne jest dostosowanie konfiguracji. W tym pomoże nam , który wizualnie pokazuje, ile osoba zaoszczędzi lub straci, przeprowadzając się z Lozanny, powiedzmy, do Écublens (przedmieściem, gdzie mieści się EPFL).: należy wprowadzić parametry swojego serwera i zastąpić ustawienia w pliku /etc/postgresql/12/main/postgresql.confsugerowanymi. Należy dodać, że tego typu kalkulatory nie są złotym środkiem, a bazę powinno się tuningować bardziej precyzyjnie, w oparciu o sprzęt, aplikację i złożoność zapytań. Ale na początek to wystarczy.

Oprócz sugerowanych przez kalkulator ustawień zmieniamy również w postgresql.confdomyślnie przypisany port 5432 na inny (w naszym przykładzie — 53983).

Po zmianie pliku konfiguracyjnego restartujemy postgresql-server poleceniem:

service postgresql restart

Zainstalowaliśmy i skonfigurowaliśmy PostgreSQL. Teraz stworzymy bazę danych, użytkowników dla środowisk dev i prod oraz nadamy im prawa do zarządzania bazą danych:

$ 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

Przejdźmy do instalacji RabbitMQ — brokera wiadomości dla Celery. Instaluje się go na Debianie dość prosto:

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

Po instalacji musimy stworzyć vhosts, użytkowników i przyznać odpowiednie prawa:

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

Teraz zainstalujemy i skonfigurujemy ostatni komponent dla naszej aplikacji — Redis. Będzie on używany jako backend do przechowywania wyników zadań Celery.

Uruchomimy dwa kontenery Docker z Redis dla środowisk dev i prod przy użyciu rozszerzenia Docker dla Plesk.

  1. Wchodzimy do Plesk, przechodzimy do sekcji Rozszerzenia, szukamy rozszerzenia Docker i instalujemy je (potrzebujemy wersji darmowej):

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  2. Przechodzimy do zainstalowanego rozszerzenia, znajdujemy przez wyszukiwarkę obraz redis bitnami i instalujemy ostatnią wersję:

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  3. Wchodzimy w ściągnięty kontener i poprawiamy konfigurację: wskazujemy port, maksymalny przydzielony rozmiar RAM, hasło w zmiennych środowiskowych oraz montujemy wolumen:

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  4. Wykonujemy kroki 2-3 dla kontenera prod, w ustawieniach zmieniamy tylko parametry: port, hasło, rozmiar RAM i ścieżkę do folderu wolumenu na serwerze:

    CI/CD w GitHub Actions dla projektu na Flask+Angular

Docker Registry

Oprócz podstawowych usług warto zainstalować na serwerze własne repozytorium obrazów Docker. Na szczęście miejsce na serwerach jest obecnie wystarczająco tanie (na pewno tańsze niż subskrypcja na DockerHub), a proces instalacji prywatnego repozytorium jest bardzo prosty.

Chcemy, aby były zainstalowane:

W tym celu:

  1. Stworzymy w Plesk dwie subdomeny w naszej subskrypcji: docker.helloworld.ru i docker-ui.helloworld.ru oraz skonfigurujemy dla nich certyfikaty Let’s Encrypt.
  2. Do folderu subdomeny docker.helloworld.ru dodamy plik docker-compose.yml z taką zawartością:
    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. Pod SSH wygenerujemy plik .htpasswd dla podstawowej autoryzacji w repozytorium Docker:
    htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
  4. Zbudujemy i uruchomimy kontenery:
    docker-compose up -d
  5. I musimy przekierować Nginx na nasze kontenery. Można to zrobić przez Plesk.

Następujące działania należy wykonać dla subdomen docker.helloworld.ru i docker-ui.helloworld.ru:

W sekcji Dev Tools naszej strony wchodzimy w Reguły Proxy Docker:

CI/CD w GitHub Actions dla projektu na Flask+Angular
I dodajemy regułę do proxy'owania przychodzącego ruchu do naszego kontenera:

CI/CD w GitHub Actions dla projektu na Flask+Angular

  1. Sprawdzamy, czy możemy się zalogować do naszego kontenera z lokalnej maszyny:
    $ 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. Sprawdźmy również działanie subdomeny docker-ui.helloworld.ru:

    CI/CD w GitHub Actions dla projektu na Flask+Angular
    Po kliknięciu przycisku Przeglądaj repozytoria, przeglądarka wyświetli okno logowania, w którym należy wprowadzić nazwę użytkownika i hasło do repozytorium. Następnie zostaniemy przeniesieni na stronę z listą repozytoriów (na razie będzie ona pusta):

    CI/CD w GitHub Actions dla projektu na Flask+Angular

Otwieramy porty w Plesk Firewall

Po zainstalowaniu i skonfigurowaniu komponentów musimy otworzyć porty, aby komponenty były dostępne z kontenerów Docker i z sieci zewnętrznej.

Zobaczmy, jak to zrobić na przykładzie wcześniej zainstalowanego rozszerzenia Firewall dla Plesk.

  1. Przechodzimy do Narzędzia & Ustawienia > Ustawienia > Firewall:
    CI/CD w GitHub Actions dla projektu na Flask+Angular
  2. Przechodzimy do Modyfikuj zasady Plesk Firewall > Dodaj regułę niestandardową i otwieramy następujące porty TCP dla podsieci Docker (172.0.0.0/8):
    RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
    Redis: 32785, 32786

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  3. Dodamy również regułę, która otworzy porty PostgreSQL oraz panelu zarządzania RabbitMQ dla zewnętrznego świata:

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  4. Zastosuj zasady za pomocą przycisku Zastosuj zmiany:

    CI/CD w GitHub Actions dla projektu na Flask+Angular

Konfiguracja CI/CD w Github Actions

Przejdźmy do najbardziej interesującej części — konfiguracji pipeline’u ciągłej integracji i dostarczania naszego projektu na serwer.

Ten pipeline będzie składał się z dwóch części:

  • budowy obrazu i uruchamiania testów (dla backendu) — po stronie Github;
  • uruchomienia migracji (dla backendu) i wdrożenia kontenerów — na serwerze.

Wdrożenie w Plesk

Najpierw zajmiemy się drugim punktem (ponieważ od niego zależy pierwszy).

Proces wdrożenia skonfigurujemy za pomocą rozszerzenia Git dla Plesk.

Rozważymy przykład z środowiskiem Prod dla repozytorium Backend.

  1. Wchodzimy w subskrypcję naszej strony Helloworld i przechodzimy do sekcji Git:

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  2. W polu „Zdalne repozytorium Git” wklejamy link do naszego repozytorium Github i zmieniamy domyślny folder httpdocs na inny (na przykład, /httpdocs/hw_back):

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  3. Kopiujemy klucz publiczny SSH z wcześniejszego kroku i dodajemy go w ustawieniach Github.
  4. Klikamy OK na ekranie w punkcie 2, po czym zostaniemy przeniesieni na stronę repozytorium w Plesk. Teraz musimy skonfigurować aktualizację repozytorium przy commitach do gałęzi master. W tym celu przechodzimy do Ustawienia repozytorium i zapisujemy wartość Webhook URL (będzie nam potrzebne później przy konfiguracji Github Actions):

    CI/CD w GitHub Actions dla projektu na Flask+Angular

  5. W polu Akcje na ekranie z poprzedniego kroku wprowadzamy skrypt do uruchomienia wdrożenia:
    cd {REPOSITORY_ABSOLUTE_PATH}
    .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID} 

    gdzie:

    {REPOSITORY_ABSOLUTE_PATH} — ścieżka do folderu prod repozytorium backend na serwerze;
    {ENV} — środowisko (dev/prod), w naszym przypadku prod;
    {DOCKER_REGISTRY_HOST} — host naszego repozytorium dockerowego
    {TG_BOT_TOKEN} — token bota Telegram;
    {TG_CHAT_ID} — ID czatu/kanalu do wysyłania powiadomień.

    Przykład skryptu:

    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. Dodajemy użytkownika z naszej subskrypcji do grupy Docker (aby mógł zarządzać kontenerami):
    sudo usermod -aG docker helloworld_admin

Środowisko deweloperskie dla repozytorium backend i frontend konfiguruje się analogicznie.

Pipeline wdrożenia w Github Actions

Przechodzimy do konfiguracji pierwszej części naszego CI/CD pipeline'a w Github Actions.

Backend

Pipeline jest opisany w pliku deploy.yml.

Ale przed jego analizą wypełnijmy w Github potrzebne nam zmienne Secret. W tym celu przechodzimy do Ustawienia -> Sekrety:

  • DOCKER_REGISTRY — host naszego repozytorium Docker (docker.helloworld.ru);
  • DOCKER_LOGIN — login do repozytorium Docker;
  • DOCKER_PASSWORD — hasło do niego;
  • DEPLOY_HOST — host, na którym dostępna jest administracja Plesk (przykład: helloworld.ru:8443 lub 123.4.56.78:8443);
  • DEPLOY_BACK_PROD_TOKEN — token do wdrożenia w repozytorium prod na serwerze (otrzymaliśmy go w Rozwój w Plesk p. 4);
  • DEPLOY_BACK_DEV_TOKEN — token do wdrożenia w repozytorium dev na serwerze.

Proces wdrożenia jest prosty i składa się z trzech głównych kroków:

  • budowanie i publikacja obrazu w naszym repozytorium;
  • uruchamianie testów w kontenerze na podstawie świeżo zbudowanego obrazu;
  • wdrożenie w odpowiednim środowisku w zależności od gałęzi (dev/master).

Frontend

Plik deploy.yml dla repozytorium frontend nie różni się zbytnio od backendowego. Brakuje w nim kroku z uruchamianiem testów i zmieniane są nazwy tokenów do wdrożenia. Zmienne sekrety dla repozytorium frontend, nawiasem mówiąc, trzeba wypełniać oddzielnie.

Konfiguracja strony

Proxy ruchu przez Nginx

No cóż, zbliżamy się do końca. Pozostaje nam tylko skonfigurować proxy dla przychodzącego i wychodzącego ruchu do naszego kontenera przez Nginx. Proces ten już omówiliśmy w punkcie 5 konfiguracji Docker Registry. To samo trzeba powtórzyć dla części backend i frontend w środowiskach dev i prod.

Podam zrzuty ekranu ustawień.

Backend

CI/CD w GitHub Actions dla projektu na Flask+Angular

Frontend

CI/CD w GitHub Actions dla projektu na Flask+Angular
Ważne uzupełnienie. Do kontenera frontend będą proxy'owane wszystkie URL-e, z wyjątkiem zaczynających się na /api/ — będą one proxy'owane do kontenera backend (dlatego w kontenerze backend wszystkie przetwarzacze muszą zaczynać się od /api/).

Podsumowanie

Teraz nasza strona powinna być dostępna pod adresami helloworld.ru i dev.helloworld.ru (środowisko prod i dev odpowiednio).

Podsumowując, dowiedzieliśmy się, jak przygotować prostą aplikację na Flask i Angular oraz skonfigurować w Github Actions pipeline do jej wdrożenia na serwerze zarządzanym przez Plesk.

Powtórzę linki do repozytoriów z kodem: backend, frontend.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster