
В тази статия ще споделя опита си в настройването на 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 се използва SQLAlchemy. За миграции се прилага Alembic. За валидиране на JSON в ръцете — Marshmallow.
В има файл Readme.md с подробни описания на структурата и инструкции за стартиране на проекта.
достатъчно прост, състои се от 6 ръце:
/ping— за проверка на наличността;- ръце за регистрация, авторизация, деавторизация и получаване на авторизиран потребител;
- ръка за изпращане на имейл, която поставя задача в опашката на 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за деплой.
И последната интересна папка за нас — . В нея се намират 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 (), затова няма да ги описвам подробно, просто ще дам командите:
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
Като се има предвид, че 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:
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
След инсталирането трябва да създадем vhosts, потребители и да предоставим нужните права:
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
Сега ще инсталираме и настроим последния компонент за нашето приложение — Redis. Той ще се използва като бекенд за съхранение на резултатите от задачите на Celery.
Ние ще стартираме два Docker контейнери с Redis за dev и prod среди с помощта на разширение Docker за Plesk.
- Влизаме в Plesk, преминаваме в секция Разширения, търсим разширението Docker и го инсталираме (нуждаем се от безплатната версия):

- Преминаваме в инсталираното разширение, намираме образа чрез търсене
redis bitnamiи поставяме последната версия:
- Влизаме в изтегления контейнер и коригираме конфигурацията: посочваме порт, максимален размер на RAM, парола в променливите на средата и монтираме обем:

- изпълняваме стъпки 2-3 за prod контейнера, само в настройките променяме параметрите: порт, парола, размер на RAM и пътя до папката volume на сървера:

Docker Registry
Освен основните услуги, би било добре да инсталираме на сървера собствен хранилище на Docker образи. Ще кажем, че пространството на сървърите в момента е доста евтино (определено поевтино от абонамента за DockerHub), а процесът на инсталиране на частен хранилище е много прост.
Искаме да имаме инсталирано:
- защитено с парола Docker хранилище, достъпно през поддомен ;
- UI интерфейс за преглед на образите в хранилището, достъпен на адрес .
За целта:
- Ще създадем в Plesk два поддомена в нашия абонамент: docker.helloworld.ru и docker-ui.helloworld.ru и ще настроим сертификати Let’s Encrypt за тях.
- В папката на поддомена docker.helloworld.ru добавяме файл
docker-compose.ymlс такова съдържание: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' - Под SSH генерираме файл .htpasswd за Basic авторизация в Docker хранилището:
htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password - Събираме и стартираме контейнерите:
docker-compose up -d - И трябва да пренасочим Nginx към нашите контейнери. Това може да се направи през Plesk.
Следните действия трябва да се извършат за поддомените docker.helloworld.ru и docker-ui.helloworld.ru:
В секцията Dev Tools на нашия сайт влизаме в 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.
- Преминаваме към Инструменти & Настройки > Настройки > Защитна стена:

- Преминаваме към Промяна на правилата на Plesk Firewall > Добавяне на персонализирано правило и отваряме следните TCP портове за подмрежата на Docker (172.0.0.0/8):
RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
Redis: 32785, 32786
- Също така, ще добавим правило, което ще отвори портовете на PostgreSQL и управленския панел на RabbitMQ за външния свят:

- Прилагаме правилата с бутона Apply Changes:

Настройка на CI/CD в Github Actions
Нека преминем към най-интригуващата част — настройка на pipeline за непрекъсната интеграция и доставка на нашия проект до сървъра.
Този pipeline ще се състои от две части:
- сборка на образа и изпълнение на тестовете (за backend) — от страната на Github;
- стартиране на миграции (за backend) и деплой на контейнерите — на сървъра.
Деплой в Plesk
Нека първо се занимаем с втория пункт (тъй като от него зависи първият).
Процесът на деплой ще настроим с помощта на разширението Git за Plesk.
Нека разгледаме пример с Prod среда за Backend репозитория.
- Влизаме в абонамента на нашия сайт Helloworld и преминаваме в подраздела Git:

- Въвеждаме в полето «Remote Git repository» връзка към нашия Github репозиторий и променяме папката по подразбиране
httpdocsна друга (например,/httpdocs/hw_back):
- Копираме SSH Public key от предишния етап и го в настройките на Github.
- Натискаме ОК на екрана в пункт 2, след което ще бъдем пренасочени към страницата на репозитория в Plesk. Сега трябва да настроим актуализирането на репозитория при комити в ветка master. За целта преминаваме в Настройки на репозитория и запазваме стойността
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}— ИД на чата/канала за изпращане на известия.Примерен скрипт:
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.
Backend
Пайплайнът е описан в .
Но преди да преминем към него, нека да попълним нужните Secret-переменные в Github. За целта, преминаваме в Settings -> Secrets:
DOCKER_REGISTRY— хост на нашия Docker-репозитория (docker.helloworld.ru);DOCKER_LOGIN— логин за Docker-репозитория;DOCKER_PASSWORD— парола за него;DEPLOY_HOST— хост, на който е налична админката Plesk (пример: :8443 или :8443);DEPLOY_BACK_PROD_TOKEN— токен за деплой в prod-репозитория на сървера (получихме го в Развъртыване в Plesk п. 4);DEPLOY_BACK_DEV_TOKEN— токен за деплой в dev-репозитория на сървера.
Процесът на деплой е прост и се състои от три основни стъпки:
- сборка и публикуване на образа в нашия репозиторий;
- стартиране на тестове в контейнер на базата на новосъздадения образ;
- развъртане в необходимата среда в зависимост от клона (dev/master).
Frontend
не се различава много от бековия. В него липсва стъпката с пускането на тестове и се променят имената на токените за деплой. Секретите за фронт-репозитория, между другото, трябва да се попълват отделно.
Настройка на сайта
Проксиране на трафика през Nginx
Е, стигнахме до края. Остава само да настроим проксирането на входящия и изходящия трафик в нашия контейнер през Nginx. Този процес вече разгледахме в точка 5 от настройването на Docker Registry. Същото трябва да повторим и за бек- и фронт-частта в dev- и prod-окруженията.
Ще покажа екрани на настройките.
Backend

Frontend

Важно уточнение. В фронтенд-контейнера ще се проксирият всички URL, освен тези, започващи с /api/ — те ще се проксирият в бек-контейнера (поради което в бек-контейнера всички обработвачи трябва да започват с /api/).
Итог
Сега нашият сайт трябва да бъде достъпен на адресите helloworld.ru и dev.helloworld.ru (prod- и dev-окружение съответно).
В крайна сметка, научихме как да подготвим простото приложение на Flask и Angular и да настроим пайплайн в Github Actions за неговото разполагане на сървера, управляван от Plesk.
Повтарям връзките към репозиториите с кода: , .
Източник: habr.com
















