CI/CD у Github Actions для праекта на Flask+Angular
У гэтым артыкуле я падзялюся сваім досведам налады CI/CD з выкарыстаннем панэлі кіравання Plesk і Github Actions. Сёння будзем вучыцца дэплоіць прасценькі праект з немудрагелістай назвай «Helloworld». Ён напісаны на Python-фрэймворку Flask, з воркерамі на Celery і франтэндам на Angular 8.
У першай частцы артыкула мы паглядзім на наш праект і яго часткі. У другой – разбярэмся, як наладзіць Plesk і ўсталяваць неабходныя пашырэнні і кампаненты (БД, RabbitMQ, Redis, Docker і г.д.).
У трэцяй частцы мы, нарэшце, разбярэмся, як наладзіць пайплайн для дэплою нашага праекта на сервер у dev-і prod-асяроддзе. А потым запусцім сайт на серверы.
І так, забыўся прадставіцца. Мяне клічуць Алег Барзоў, я fullstack-распрацоўшчык у камандзе CRM для мэнэджэраў іпатэчнага крэдытавання ў Домклік.
Агляд праекту
Для пачатку разгледзім два рэпазітары праекта - бэкенда і фронту - і прабяжымся па кодзе.
Бэкенд-частка: Flask+Celery
Для бэк-часткі я ўзяў досыць папулярную сярод Python-распрацоўнікаў звязку: фрэймворк Flask (для API) і Celery (для чаргі задач). У якасці ORM выкарыстоўваецца SQLAchemy. Для міграцый прымяняецца Alembic. Для валідацыі JSON у ручках - Marshmallow.
В рэпазітары есць файл Readme.md з падрабязным апісаннем структуры і інструкцыямі для запуску праекта.
API вэб-часткі досыць немудрагелісты, складаецца з 6 ручак:
/ping - Для праверкі даступнасці;
ручкі для рэгістрацыі, аўтарызацыі, дэаўтарызацыі і атрымання аўтарызаванага карыстальніка;
ручка для адпраўкі email, якая кладзе задачку ў чаргу Celery.
Celery-частка яшчэ прасцей, там усяго адна задачка send_mail_task.
docker з двума Docker-файламі (base.dockerfile для зборкі рэдка змяняецца базавай выявы і Dockerfile для асноўных зборак);
.env_files - З файламі з зменнымі асяроддзі для розных асяроддзяў.
У корані праекта знаходзяцца чатыры файлы docker-compose:
docker-compose.local.db.yml для ўзняцця лакальнай БД для распрацоўкі;
docker-compose.local.workers.yml для лакальнага ўзняцця воркера, БД, Redis і RabbitMQ;
docker-compose.test.yml для прагону тэстаў пры разгортванні;
docker-compose.yml для дэплою.
І апошняя цікавая нам тэчка - .ci-cd. У ёй ляжаць shell-скрыпты для разгортвання:
deploy.sh - запуск міграцыі і дэплою. Запускаецца на серверы пасля зборкі і прагону тэстаў у Github Actions;
rollback.sh - Адкат кантэйнераў на папярэднюю версію зборкі;
curl_tg.sh — адпраўка апавяшчэнняў аб разгортванні ў Telegram.
Франтэнд на Angular
Рэпазітар з фронтам моцна прасцей бэкаўскай. Фронт складаецца з трох старонак:
Галоўная старонка з формай для адпраўкі email і кнопкай вынахаду.
Старонка ўваходу.
Старонка рэгістрацыі.
Галоўная старонка выглядае аскетычна:
У корані ляжаць два файлы Dockerfile и docker-compose.yml, а таксама знаёмая нам тэчка .ci-cd з крыху меншай колькасцю скрыптоў, чым у бэкаўскім рэпазітары (прыбраны скрыпты для запуску тэстаў).
Заводзім праект у Plesk
Пачнём з налады Plesk і стварэння падпіскі для нашага сайта.
Ўстаноўка пашырэнняў
У Plesk нам спатрэбяцца чатыры пашырэнні:
Docker для кіравання і візуальнага адлюстравання стану кантэйнераў у адмінцы Plesk;
Git для настройкі кроку дэплою на серверы;
Let's Encrypt для генерацыі (і аўтападаўжэння) бясплатных TLS-сертыфікатаў;
Firewall для налады фільтрацыі ўваходнага трафіку.
Усталяваць іх можна праз адмінку Plesk у падзеле Extensions:
Дэталёвую наладу пашырэнняў мы разглядаць не будзем, для нашых дэма-мэт падыдуць налады па змаўчанні.
Стварэнне падпіскі і сайта
Далей нам трэба стварыць падпіску для нашага сайта helloworld.ru і дадаць туды паддамен dev.helloworld.ru.
Ствараем падпіску для дамена helloworld.ru і паказваем лагін-пароль для сістэмнага карыстальніка:
Унізе старонкі ставім галачку Secure the domain with Let's Encrypt, калі жадаем наладзіць HTTPS для сайта:
Далей у гэтай падпісцы ствараем паддамен dev.helloworld.ru (для якога таксама можна выпусціць бясплатны TLS-сертыфікат):
Ўстаноўка серверных кампанентаў
У нас у наяўнасці сервер з OS Debian Stretch 9.12 і ўсталяванай панэллю кіравання Plesk Obsidian 18.0.27.
Нам трэба ўсталяваць і наладзіць для нашага праекту:
PostgreSQL (у нашым выпадку будзе адзін сервер з двума БД для dev-і prod-асяроддзя).
RabbitMQ (тое ж самае, адзін інстанс з рознымі vhosts для асяроддзяў).
Два інстансу Redis (для dev- і prod-асяроддзя).
Docker Registry (для лакальнага захоўвання сабраных Docker-вобразаў).
UI-інтэрфейс для Docker registry.
PostgreSQL
У камплекце з Plesk ужо ідзе СКБД PostgreSQL, аднак не самай свежай версіі (на момант напісання артыкула Plesk Obsidian падтрымліваў Postgres (версій 8.4–10.8). Мы ж хочам для свайго дадатку самую апошнюю версію (12.3 на момант напісання артыкула), таму будзем ставіць яе ўручную.
Падрабязных інструкцый па ўсталяванні Postgres на Debian у сетцы досыць (прыклад), таму падрабязна апісваць іх не буду, проста прывяду каманды:
Улічваючы, што ў PostgreSQL дастаткова пасрэдныя налады па змаўчанні, трэба абавязкова скарэктаваць канфігурацыю. У гэтым нам дапаможа калькулятар: трэба убіць параметры свайго сервера і замяніць наладкі ў файле /etc/postgresql/12/main/postgresql.confна прапанаваныя. Тут варта абмовіцца, што падобныя калькулятары - не чароўная куля, і базу варта цюніць больш кропкава, зыходзячы з вашага жалеза, прыкладанні і складанасці запытаў. Але для старту гэтага дастаткова.
Акрамя прапанаваных калькулятарам налад таксама мяняем у postgresql.confпрапісаны па змаўчанні порт 5432 на іншы (у нашым прыкладзе — 53983).
Пасля змены канфігурацыйнага файла перазагружаем postgresql-server камандай:
service postgresql restart
Мы паставілі і настроілі PostgreSQL. Цяпер створым БД, карыстальнікаў для dev- і prod-асяроддзяў, і выдадзім карыстальнікам права на кіраванне БД:
$ 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
Пяройдзем да ўстаноўкі RabbitMQ – брокера паведамленняў для Celery. Ставіцца ён на Debian дастаткова проста:
Цяпер усталюем і наладзім апошні кампанент для нашага прыкладання - Redis. Ён будзе выкарыстоўвацца як бэкенд для захоўвання вынікаў задач Celery.
Мы паднімем два Docker-кантэйнера з Redis пад dev- і prod-асяроддзя з дапамогай пашырэння Docker для Plesk.
Заходзім у Plesk, пераходзім у падзел Пашырэння, шукаем пашырэнне Docker і ўсталёўваны яго (нам патрэбна бясплатная версія):
Пераходзім ва ўсталяванае пашырэнне, знаходзім праз пошук выява redis bitnami і ставім апошнюю версію:
Заходзім у запампаваны кантэйнер і карэктуем канфігурацыю: паказваем порт, максімальны які выдзяляецца памер АЗП, пароль у зменных асяроддзі, і які мантуецца тым:
Выконваем крокі 2-3 для prod-кантэйнера, у наладах толькі мяняем параметры: порт, пароль, памер АЗП і шлях да тэчкі volume на серверы:
Рэестр докераў
Апроч базавых сэрвісаў было б нядрэнна паставіць на сервер уласны рэпазітар Docker-вобразаў. Балазе месца на серверах цяпер досыць таннае (ужо сапраўды танней падпіскі на DockerHub), ды і працэс усталёўкі прыватнага рэпазітара вельмі просты.
І трэба перанакіраваць Nginx на нашы кантэйнеры. Гэта можна зрабіць праз Plesk.
Наступныя дзеянні трэба прарабіць для паддаменаў docker.helloworld.ru і docker-ui.helloworld.ru:
У раздзеле Інструменты распрацоўшчыкаў нашага сайта заходзім у Docker Proxy Rules:
І дадаем правіла для праксіравання ўваходнага трафіку ў наш кантэйнер:
Правяраем, што можам аўтарызавацца ў нашым кантэйнеры з лакальнай машыны:
$ 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
Таксама праверым працу паддамена docker-ui.helloworld.ru:
Пры націску на Browse repositories браўзэр выдасць акенца для аўтарызацыі, куды трэба будзе ўвесці лагін і пароль для рэпазітара. Пасля чаго нас перакіне на старонку са спісам рэпазітараў (у вас пакуль яна будзе пустой):
Адкрываем парты ў Plesk Firewall
Пасля ўстаноўкі і настройкі кампанентаў нам трэба адкрыць парты, каб кампаненты былі даступныя з Docker-кантэйнераў і знешняй сеткі.
Паглядзім, як гэта рабіць, на прыкладзе ўсталяванага намі раней пашырэнні Firewall для Plesk.
пераходзім у Tools & Settings > Settings > Firewall:
пераходзім у Modify Plesk Firewall Rules > Add Custom Rule і адчыняны наступныя TCP-парты для падсеткі Docker (172.0.0.0 / 8):
RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
Redis: 32785, 32786
Таксама дадамо правіла, якое адкрые знешняму свету парты PostgreSQL і management-панэлі RabbitMQ:
Ужывальны правілы з дапамогай кнопкі Apply Changes:
Настройка CI/CD у Github Actions
Прыступім да самай цікавай часткі - наладзе пайплайн бесперапыннай інтэграцыі і дастаўкі нашага праекта да сервера.
Гэты пайплайн будзе складацца з дзвюх частак:
зборка выявы і прагон тэстаў (для бэкенда) - на боку Github;
запуск міграцый (для бэкенда) і дэплой кантэйнераў - на серверы.
Дэплой у Plesk
Разбярэмся спачатку з другім пунктам (бо ад яго залежыць першы).
Працэс дэплою мы будзем наладжваць з дапамогай пашырэння Git для Plesk.
Разгледзім прыклад з Prod асяроддзем для Backend рэпазітара.
Заходзім у падпіску нашага сайта Helloworld і пераходзім у падраздзел Git:
Устаўляемы ў поле «Remote Git repository» спасылку на наш Github-рэпазітар і змяняем тэчку па змаўчанні httpdocs на іншую (напрыклад, /httpdocs/hw_back):
Капіяваны SSH Public key з папярэдняга этапу і дадаем яго ў наладах Github.
Націскаем ОК на экране ў пункце 2, пасля чаго нас перакідае на старонку рэпазітара ў Plesk. Цяпер нам трэба наладзіць абнаўленне рэпазітара пры комітах у галінку master. Для гэтага пераходзім у Repository Settings і захоўваем значэнне Webhook URL (яно нам спатрэбіцца пазней пры наладзе Github Actions):
У поле Actions на экране з папярэдняга пункта ўводны скрыпт для запуску дэплою:
cd {REPOSITORY_ABSOLUTE_PATH}
.ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID}
дзе:
{REPOSITORY_ABSOLUTE_PATH} - шлях да тэчкі prod backend-рэпазітара на серверы; {ENV} - серада (dev/prod), у нашым выпадку prod; {DOCKER_REGISTRY_HOST} — хост нашага docker рэпазітара {TG_BOT_TOKEN} - токен Telegram-бота; {TG_CHAT_ID} - ID чата/канала для адпраўкі апавяшчэнняў.
Прыклад скрыпту:
cd /var/www/vhosts/helloworld.ru/httpdocs/hw_back/
.ci-cd/deploy.sh dev docker.helloworld.ru docker_user docker_password 12345678:AAbcdEfghCH1vGbCasdfSAs0K5PALDsaw -1001234567890
Дадаем карыстальніка з нашай падпіскі ў групу Docker (каб ён мог кіраваць кантэйнерамі):
sudo usermod -aG docker helloworld_admin
Dev-асяроддзе для backend-рэпазітара і frontend наладжваюцца аналагічна.
Pipeline дэплою ў Github Actions
Пераходзім да налады першай часткі нашага CI/CD-пайплана ў Github Actions.
Але перад яго разборам запоўнім у Github патрэбныя нам Secret-зменныя. Для гэтага пераходзім у Settings -> Secrets:
DOCKER_REGISTRY - хост нашага Docker-рэпазітара (docker.helloworld.ru);
DOCKER_LOGIN — лагін да Docker-рэпазітара;
DOCKER_PASSWORD - пароль да яго;
DEPLOY_HOST - хост, на якім даступная адмінка Plesk (прыклад: helloworld.ru:8443 ці 123.4.56.78:8443);
DEPLOY_BACK_PROD_TOKEN - токен для дэплою ў prod-рэпазітар на серверы (мы яго атрымалі ў Разгортванне ў Plesk п. 4);
DEPLOY_BACK_DEV_TOKEN - токен для дэплою ў dev-рэпазітар на серверы.
Працэс дэплою просты і складаецца з трох асноўных крокаў:
зборка і публікацыя выявы ў нашым рэпазітары;
запуск тэстаў у кантэйнеры на базе свежазабранай выявы;
разгортванне ў патрэбнае асяроддзе ў залежнасці ад галіны (dev/master).
Frontend
Файл deploy.yml для фронт-рэпазітара мала чым адрозніваецца ад бэкаўскай. У ім адсутнічае крок з запускам тэстаў і мяняюцца назвы токенаў для дэплою. Сакрэты для фронт-рэпазітара, дарэчы, трэба запаўняць асобна.
Настройка сайта
Праксіраванне трафіку праз Nginx
Ну што ж, мы падышлі да канца. Засталося толькі наладзіць праксіраванне ўваходнага і выходнага трафіку ў наш кантэйнер праз Nginx. Гэты працэс мы ўжо разгледзелі ў пункце 5 наладкі Docker Registry. Тое ж самае трэба паўтарыць для бэк- і фронт-часткі ў dev-і prod-акружэннях.
Прывяду скрыны налад.
Backend
Frontend
Важнае ўдакладненне. У фронтэнд-кантэйнер будуць праксіравацца ўсе URL, акрамя якія пачынаюцца на /api/ - Яны будуць праксіраваны ў бэк-кантэйнер (таму у бэк-кантэйнеры ўсе апрацоўшчыкі павінны пачынацца з /api/).
Вынікі
Цяпер наш сайт павінен быць даступны па адрасах helloworld.ru і dev.helloworld.ru (prod- і dev-асяроддзе адпаведна).
Разам, мы даведаліся, як падрыхтаваць простае дадатак на Flask і Angular і наладзіць у Github Actions пайплайн для яго выкаткі на сервер пад кіраваннем Plesk.
Прадублірую спасылкі на рэпазітары з кодам: бэкенд, франтэнд.