W tym artykule podzielę się moimi doświadczeniami z konfigurowania CI/CD za pomocą Plesk Control Panel i Github Actions. Dzisiaj nauczymy się, jak wdrożyć prosty projekt o nieskomplikowanej nazwie „Helloworld”. Jest napisany w frameworku Flask Python, z pracownikami Celery i nakładką Angular 8.
W pierwszej części artykułu przyjrzymy się naszemu projektowi i jego częściom. W drugim dowiemy się, jak skonfigurować Plesk i zainstalować niezbędne rozszerzenia i komponenty (DB, RabbitMQ, Redis, Docker itp.).
W trzeciej części w końcu dowiemy się, jak skonfigurować potok wdrażania naszego projektu na serwerze w środowisku dev i prod. Następnie uruchomimy stronę na serwerze.
I tak, zapomniałem się przedstawić. Nazywam się Oleg Borzov, jestem fullstack developerem w zespole CRM dla managerów kredytów hipotecznych w Domclick.
Przegląd projektu
Najpierw spójrzmy na dwa repozytoria projektu — backend i front — i przejrzyjmy kod.
Backend: Kolba + Seler
W tylnej części wziąłem kilka dość popularnych wśród programistów Pythona: framework Flask (dla API) i Seler (dla kolejki zadań). SQLAchemy jest używany jako ORM. Alembik służy do migracji. Do sprawdzania poprawności JSON w uchwytach - Marshmallow.
В repozytoria znajduje się plik Readme.md ze szczegółowym opisem struktury i instrukcją uruchomienia projektu.
Strona główna z formularzem do wysyłania wiadomości e-mail i przyciskiem wyjścia.
Strona logowania.
Strona rejestracji.
Strona główna wygląda ascetycznie:
W katalogu głównym znajdują się dwa pliki Dockerfile и docker-compose.yml, a także znajomy folder .ci-cd z nieco mniejszą liczbą skryptów niż w repozytorium wstecznym (usunięto skrypty do uruchamiania testów).
Rozpoczęcie projektu w Plesku
Zacznijmy od skonfigurowania Plesk i utworzenia subskrypcji dla naszej witryny.
Instalowanie rozszerzeń
W Plesku potrzebujemy czterech rozszerzeń:
Docker zarządzać i wizualnie wyświetlać stan kontenerów w panelu administracyjnym Plesk;
Git aby skonfigurować etap wdrażania na serwerze;
Let's Encrypt do generowania (i automatycznego odnawiania) bezpłatnych certyfikatów TLS;
Firewall skonfigurować filtrowanie ruchu przychodzącego.
Możesz je zainstalować za pośrednictwem panelu administracyjnego Plesk w sekcji Rozszerzenia:
Nie będziemy brać pod uwagę szczegółowych ustawień rozszerzeń, ustawienia domyślne wystarczą do naszych celów demonstracyjnych.
Utwórz subskrypcję i witrynę
Następnie musimy utworzyć subskrypcję dla naszej witryny helloworld.ru i dodać tam subdomenę dev.helloworld.ru.
Utwórz subskrypcję domeny helloworld.ru i podaj hasło logowania dla użytkownika systemu:
Zaznacz pole u dołu strony Zabezpiecz domenę za pomocą Let's Encryptjeśli chcemy skonfigurować HTTPS dla witryny:
Następnie w tej subskrypcji utwórz subdomenę dev.helloworld.ru (dla której możesz również wystawić bezpłatny certyfikat TLS):
Instalowanie składników serwera
Mamy serwer z System operacyjny Debian Stretch 9.12 i zainstalowany panel sterowania Plesk Obsydian 18.0.27.
Musimy zainstalować i skonfigurować dla naszego projektu:
PostgreSQL (w naszym przypadku będzie to jeden serwer z dwiema bazami danych dla środowisk dev i prod).
RabbitMQ (ta sama, ta sama instancja z różnymi vhostami dla środowisk).
Dwie instancje Redis (dla środowisk deweloperskich i produkcyjnych).
Docker Registry (do lokalnego przechowywania zbudowanych obrazów Docker).
Interfejs użytkownika dla rejestru Docker.
PostgreSQL
Plesk jest już dostarczany z PostgreSQL DBMS, ale nie najnowszą wersją (w momencie pisania Plesk Obsidian utrzymany wersje Postgresa 8.4–10.8). Chcemy najnowszej wersji dla naszej aplikacji (12.3 w momencie pisania tego tekstu), więc zainstalujemy ją ręcznie.
Istnieje wiele szczegółowych instrukcji instalacji Postgres na Debianie w sieci (przykład), więc nie będę ich szczegółowo opisywał, podam tylko komendy:
Biorąc pod uwagę, że PostgreSQL ma raczej przeciętne ustawienia domyślne, konieczne jest poprawienie konfiguracji. To nam pomoże Stosując: musisz wprowadzić parametry swojego serwera i zastąpić ustawienia w pliku /etc/postgresql/12/main/postgresql.confdo oferowanych. Należy tutaj zaznaczyć, że takie kalkulatory nie są magiczną kulą, a bazę należy dostroić bardziej precyzyjnie, w oparciu o sprzęt, aplikację i złożoność zapytań. Ale to wystarczy, aby zacząć.
Oprócz ustawień proponowanych przez kalkulator dokonujemy również przesiadek postgresql.confdomyślny port 5432 na inny (w naszym przykładzie - 53983).
Po zmianie pliku konfiguracyjnego zrestartuj serwer postgresql za pomocą polecenia:
service postgresql restart
Zainstalowaliśmy i skonfigurowaliśmy PostgreSQL. Teraz utwórzmy bazę danych użytkowników dla środowisk dev i prod oraz nadajmy użytkownikom uprawnienia 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. Instalacja na Debianie jest dość prosta:
Teraz zainstalujmy i skonfigurujmy ostatni komponent dla naszej aplikacji - Redis. Będzie używany jako backend do przechowywania wyników zadań Celery.
Zbudujemy dwa kontenery Docker z Redis dla środowisk dev i prod korzystających z rozszerzenia Docker dla Pleska.
Wchodzimy na Plesk, przechodzimy do sekcji Extensions, szukamy rozszerzenia Docker i instalujemy je (potrzebujemy darmowej wersji):
Przejdź do zainstalowanego rozszerzenia, znajdź obraz za pomocą wyszukiwania redis bitnami i zainstaluj najnowszą wersję:
Wchodzimy do pobranego kontenera i dostosowujemy konfigurację: określamy port, maksymalny przydzielony rozmiar pamięci RAM, hasło w zmiennych środowiskowych i montujemy wolumin:
Kroki 2-3 wykonujemy dla kontenera prod, w ustawieniach zmieniamy tylko parametry: port, hasło, rozmiar RAM i ścieżkę do folderu wolumenu na serwerze:
Rejestr Dockera
Oprócz podstawowych usług fajnie byłoby umieścić na serwerze własne repozytorium obrazów Dockera. Na szczęście miejsce na serwerze jest teraz dość tanie (z pewnością tańsze niż subskrypcja DockerHub), a proces zakładania prywatnego repozytorium jest bardzo prosty.
Stwórzmy dwie subdomeny w Plesk w naszej subskrypcji: docker.helloworld.ru i docker-ui.helloworld.ru i skonfigurujmy dla nich certyfikaty Let's Encrypt.
Dodaj plik do folderu poddomeny docker.helloworld.ru docker-compose.yml z taką zawartością:
I musimy przekierować Nginx do naszych kontenerów. Można to zrobić przez Plesk.
Następujące kroki należy wykonać dla subdomen docker.helloworld.ru i docker-ui.helloworld.ru:
W sekcji Narzędzia deweloperskie przejdź do naszej witryny Reguły serwera proxy Dockera:
I dodaj regułę do proxy ruchu przychodzącego do naszego kontenera:
Sprawdzamy czy możemy zalogować się 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 też działanie subdomeny docker-ui.helloworld.ru:
Po kliknięciu Przeglądaj repozytoria przeglądarka wyświetli okno autoryzacji, 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 dla Ciebie pusta):
Otwieranie portów w Plesk Firewall
Po zainstalowaniu i skonfigurowaniu komponentów musimy otworzyć porty, aby komponenty były dostępne z kontenerów Dockera i sieci zewnętrznej.
Zobaczmy, jak to zrobić za pomocą rozszerzenia Firewall dla Pleska, które zainstalowaliśmy wcześniej.
Iść do Narzędzia i ustawienia > Ustawienia > Zapora sieciowa:
Iść do Zmodyfikuj reguły zapory Plesk > Dodaj regułę niestandardową i otwórz następujące porty TCP dla podsieci Docker (172.0.0.0 / 8):
KrólikMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
Redis: 32785, 32786
Dodamy również regułę, która otworzy porty PostgreSQL i panele zarządzające RabbitMQ na świat zewnętrzny:
Zastosuj reguły za pomocą przycisku Zastosuj zmiany:
Konfigurowanie CI/CD w akcjach Github
Przejdźmy do najciekawszej części - ustawienia potoku ciągłej integracji i dostarczenia naszego projektu na serwer.
Rurociąg ten będzie składał się z dwóch części:
zbudowanie obrazu i uruchomienie testów (dla backendu) - po stronie Github;
uruchamianie migracji (dla backendu) i wdrażanie kontenerów - na serwerze.
Wysłać do Pleska
Zajmijmy się najpierw drugim punktem (bo od tego zależy pierwszy).
Skonfigurujemy proces wdrażania za pomocą rozszerzenia Git dla Plesk.
Rozważmy przykład ze środowiskiem Prod dla repozytorium zaplecza.
Przechodzimy do subskrypcji naszej witryny Helloworld i przechodzimy do podsekcji Git:
Wstaw link do naszego repozytorium Github w pole „Remote Git reposository” i zmień domyślny folder httpdocs do innego (np. /httpdocs/hw_back):
Skopiuj klucz publiczny SSH z poprzedniego kroku i dodać jest w ustawieniach Github.
Kliknij OK na ekranie w kroku 2, po czym zostaniemy przekierowani na stronę repozytorium w Plesk. Teraz musimy skonfigurować repozytorium, aby było aktualizowane o zatwierdzenia do gałęzi master. Aby to zrobić, przejdź do Ustawienia repozytorium i zapisz wartość Webhook URL (będziemy go potrzebować później podczas konfigurowania Github Actions):
W polu Działania na ekranie z poprzedniego akapitu wprowadź skrypt uruchamiający wdrożenie:
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 zaplecza na serwerze; {ENV} - środowisko (dev/prod), w naszym przypadku prod; {DOCKER_REGISTRY_HOST} - host naszego repozytorium dokerów {TG_BOT_TOKEN} — Token bota telegramu; {TG_CHAT_ID} — Identyfikator czatu/kanału 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
Dodaj użytkownika z naszej subskrypcji do grupy Docker (aby mógł zarządzać kontenerami):
sudo usermod -aG docker helloworld_admin
Środowisko dev dla repozytorium zaplecza i frontendu jest konfigurowane w ten sam sposób.
Potok wdrażania w akcjach Github
Przejdźmy do konfigurowania pierwszej części naszego potoku CI/CD w Github Actions.
DOCKER_LOGIN - zaloguj się do repozytorium Dockera;
DOCKER_PASSWORD - hasło do niego;
DEPLOY_HOST — host, na którym dostępny jest panel administracyjny Plesk (przykład: helloworld.com:8443 lub 123.4.56.78:8443);
DEPLOY_BACK_PROD_TOKEN - token do wdrożenia do prod-repository na serwerze (dostaliśmy go w Deployment in Plesk p. 4);
DEPLOY_BACK_DEV_TOKEN - token do wdrożenia do repozytorium dev na serwerze.
Proces wdrażania jest prosty i składa się z trzech głównych kroków:
zbudowanie i opublikowanie obrazu w naszym repozytorium;
uruchamianie testów w kontenerze na podstawie świeżo zbudowanego obrazu;
wdrożenie do żądanego środowiska w zależności od branży (dev/master).
frontend
Plik Deploy.yml dla przedniego repozytorium niewiele różni się od Becka. Brakuje kroku z uruchomieniem testów i zmianą nazw tokenów do wdrożenia. Nawiasem mówiąc, tajemnice dla przedniego repozytorium należy wypełnić osobno.
Konfiguracja witryny
Ruch proxy przez Nginx
Cóż, doszliśmy do końca. Pozostaje tylko skonfigurować proxy ruchu przychodzącego i wychodzącego do naszego kontenera przez Nginx. Omówiliśmy już ten proces w kroku 5 konfiguracji Docker Registry. To samo należy powtórzyć dla części tylnej i przedniej w środowiskach deweloperskich i produkcyjnych.
Dam screeny z ustawień.
Backend
frontend
Ważne wyjaśnienie. Wszystkie adresy URL zostaną przekazane do kontenera frontendu, z wyjątkiem adresów zaczynających się od /api/ - zostaną przesłane do tylnego kontenera (tzw w tylnym kontenerze, od którego muszą zaczynać wszyscy opiekunowie /api/).
Wyniki
Teraz nasza strona powinna być dostępna pod adresami helloworld.ru i dev.helloworld.ru (odpowiednio prod- i dev-environments).
W sumie nauczyliśmy się, jak przygotować prostą aplikację we Flask i Angular oraz skonfigurować potok w Github Actions, aby ją wdrożyć na serwerze z Plesk.