
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: , .
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 jest plik Readme.md z dokładnym opisem struktury i instrukcjami uruchomienia projektu.
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.
jeszcze prostsza, tam jest tylko jedno zadanie send_mail_task.
W folderze są dwa podfoldery:
dockerz dwoma plikami Docker (base.dockerfiledo budowy rzadko zmieniającego się podstawowego obrazu orazDockerfiledo 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.ymldo uruchomienia lokalnej bazy danych do rozwoju;docker-compose.local.workers.ymldo lokalnego uruchomienia workera, Bazy Danych, Redis i RabbitMQ;docker-compose.test.ymldo uruchamiania testów przy wdrożeniu;docker-compose.ymldo wdrożeń.
A ostatnia interesująca nas folder — . 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
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:

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ń:
Dockerdo zarządzania i wizualizacji stanu kontenerów w panelu Plesk;Gitemdo konfiguracji kroku deploymentu na serwerze;Let's Encryptdo generowania (i automatycznego przedłużania) darmowych certyfikatów TLS;Firewalldo konfiguracji filtracji ruchu przychodzącego.
Można je zainstalować przez panel administracyjny Plesk w sekcji Rozszerzenia:

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.
- Tworzymy subskrypcję dla domeny helloworld.ru i podajemy login-hasło dla użytkownika systemowego:

Na dole strony zaznaczamy Zabezpiecz domenę za pomocą Let’s Encrypt, jeśli chcemy skonfigurować HTTPS dla strony:
- Następnie w tej subskrypcji tworzymy subdomenę dev.helloworld.ru (dla której również można wydać darmowy certyfikat TLS):

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 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 (), 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 : 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.
- Wchodzimy do Plesk, przechodzimy do sekcji Rozszerzenia, szukamy rozszerzenia Docker i instalujemy je (potrzebujemy wersji darmowej):

- Przechodzimy do zainstalowanego rozszerzenia, znajdujemy przez wyszukiwarkę obraz
redis bitnamii instalujemy ostatnią wersję:
- Wchodzimy w ściągnięty kontener i poprawiamy konfigurację: wskazujemy port, maksymalny przydzielony rozmiar RAM, hasło w zmiennych środowiskowych oraz montujemy wolumen:

- 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:

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:
- chronione hasłem repozytorium Docker, dostępne przez subdomenę ;
- Interfejs UI do przeglądania obrazów w repozytorium, dostępny pod adresem .
W tym celu:
- Stworzymy w Plesk dwie subdomeny w naszej subskrypcji: docker.helloworld.ru i docker-ui.helloworld.ru oraz skonfigurujemy dla nich certyfikaty Let’s Encrypt.
- Do folderu subdomeny docker.helloworld.ru dodamy plik
docker-compose.ymlz 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' - Pod SSH wygenerujemy plik .htpasswd dla podstawowej autoryzacji w repozytorium Docker:
htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password - Zbudujemy i uruchomimy kontenery:
docker-compose up -d - 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:

I dodajemy regułę do proxy'owania przychodzącego ruchu do naszego kontenera:

- 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 - Sprawdźmy również działanie subdomeny docker-ui.helloworld.ru:

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):
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.
- Przechodzimy do Narzędzia & Ustawienia > Ustawienia > Firewall:

- 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
- Dodamy również regułę, która otworzy porty PostgreSQL oraz panelu zarządzania RabbitMQ dla zewnętrznego świata:

- Zastosuj zasady za pomocą przycisku Zastosuj zmiany:

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.
- Wchodzimy w subskrypcję naszej strony Helloworld i przechodzimy do sekcji Git:

- W polu „Zdalne repozytorium Git” wklejamy link do naszego repozytorium Github i zmieniamy domyślny folder
httpdocsna inny (na przykład,/httpdocs/hw_back):
- Kopiujemy klucz publiczny SSH z wcześniejszego kroku i go w ustawieniach Github.
- 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):
- 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 przypadkuprod;
{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 - 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 .
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: :8443 lub :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
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

Frontend

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: , .
Źródło: habr.com
















