CI/CD у Github Actions для праекта на Flask+Angular

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.

У тэчцы /conf ляжаць дзве падтэчкі:

  • 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 і кнопкай вынахаду.
  • Старонка ўваходу.
  • Старонка рэгістрацыі.

Галоўная старонка выглядае аскетычна:

CI/CD у Github Actions для праекта на Flask+Angular
У корані ляжаць два файлы Dockerfile и docker-compose.yml, а таксама знаёмая нам тэчка .ci-cd з крыху меншай колькасцю скрыптоў, чым у бэкаўскім рэпазітары (прыбраны скрыпты для запуску тэстаў).

Заводзім праект у Plesk

Пачнём з налады Plesk і стварэння падпіскі для нашага сайта.

Ўстаноўка пашырэнняў

У Plesk нам спатрэбяцца чатыры пашырэнні:

  • Docker для кіравання і візуальнага адлюстравання стану кантэйнераў у адмінцы Plesk;
  • Git для настройкі кроку дэплою на серверы;
  • Let's Encrypt для генерацыі (і аўтападаўжэння) бясплатных TLS-сертыфікатаў;
  • Firewall для налады фільтрацыі ўваходнага трафіку.

Усталяваць іх можна праз адмінку Plesk у падзеле Extensions:

CI/CD у Github Actions для праекта на Flask+Angular
Дэталёвую наладу пашырэнняў мы разглядаць не будзем, для нашых дэма-мэт падыдуць налады па змаўчанні.

Стварэнне падпіскі і сайта

Далей нам трэба стварыць падпіску для нашага сайта helloworld.ru і дадаць туды паддамен dev.helloworld.ru.

  1. Ствараем падпіску для дамена helloworld.ru і паказваем лагін-пароль для сістэмнага карыстальніка:

    CI/CD у Github Actions для праекта на Flask+Angular
    Унізе старонкі ставім галачку Secure the domain with Let's Encrypt, калі жадаем наладзіць HTTPS для сайта:

    CI/CD у Github Actions для праекта на Flask+Angular

  2. Далей у гэтай падпісцы ствараем паддамен dev.helloworld.ru (для якога таксама можна выпусціць бясплатны TLS-сертыфікат):

    CI/CD у Github Actions для праекта на Flask+Angular

Ўстаноўка серверных кампанентаў

У нас у наяўнасці сервер з 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.

  1. Заходзім у Plesk, пераходзім у падзел Пашырэння, шукаем пашырэнне Docker і ўсталёўваны яго (нам патрэбна бясплатная версія):

    CI/CD у Github Actions для праекта на Flask+Angular

  2. Пераходзім ва ўсталяванае пашырэнне, знаходзім праз пошук выява redis bitnami і ставім апошнюю версію:

    CI/CD у Github Actions для праекта на Flask+Angular

  3. Заходзім у запампаваны кантэйнер і карэктуем канфігурацыю: паказваем порт, максімальны які выдзяляецца памер АЗП, пароль у зменных асяроддзі, і які мантуецца тым:

    CI/CD у Github Actions для праекта на Flask+Angular

  4. Выконваем крокі 2-3 для prod-кантэйнера, у наладах толькі мяняем параметры: порт, пароль, памер АЗП і шлях да тэчкі volume на серверы:

    CI/CD у Github Actions для праекта на Flask+Angular

Рэестр докераў

Апроч базавых сэрвісаў было б нядрэнна паставіць на сервер уласны рэпазітар Docker-вобразаў. Балазе месца на серверах цяпер досыць таннае (ужо сапраўды танней падпіскі на DockerHub), ды і працэс усталёўкі прыватнага рэпазітара вельмі просты.

Мы хочам, каб у нас былі ўсталяваныя:

Для гэтага:

  1. Створым у Plesk два паддамены ў нашай падпісцы: docker.helloworld.ru і docker-ui.helloworld.ru, і наладзім для іх сертыфікаты Let's Encrypt.
  2. У тэчку паддамена 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'
    

  3. Пад SSH згенераваны файл .htpasswd для Basic-аўтарызацыі ў Docker-рэпазітары:
    htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
  4. Збяром і паднімем кантэйнеры:
    docker-compose up -d
  5. І трэба перанакіраваць Nginx на нашы кантэйнеры. Гэта можна зрабіць праз Plesk.

Наступныя дзеянні трэба прарабіць для паддаменаў docker.helloworld.ru і docker-ui.helloworld.ru:

У раздзеле Інструменты распрацоўшчыкаў нашага сайта заходзім у Docker Proxy Rules:

CI/CD у Github Actions для праекта на Flask+Angular
І дадаем правіла для праксіравання ўваходнага трафіку ў наш кантэйнер:

CI/CD у Github Actions для праекта на Flask+Angular

  1. Правяраем, што можам аўтарызавацца ў нашым кантэйнеры з лакальнай машыны:
    $ 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. Таксама праверым працу паддамена docker-ui.helloworld.ru:

    CI/CD у Github Actions для праекта на Flask+Angular
    Пры націску на Browse repositories браўзэр выдасць акенца для аўтарызацыі, куды трэба будзе ўвесці лагін і пароль для рэпазітара. Пасля чаго нас перакіне на старонку са спісам рэпазітараў (у вас пакуль яна будзе пустой):

    CI/CD у Github Actions для праекта на Flask+Angular

Адкрываем парты ў Plesk Firewall

Пасля ўстаноўкі і настройкі кампанентаў нам трэба адкрыць парты, каб кампаненты былі даступныя з Docker-кантэйнераў і знешняй сеткі.

Паглядзім, як гэта рабіць, на прыкладзе ўсталяванага намі раней пашырэнні Firewall для Plesk.

  1. пераходзім у Tools & Settings > Settings > Firewall:
    CI/CD у Github Actions для праекта на Flask+Angular
  2. пераходзім у 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

    CI/CD у Github Actions для праекта на Flask+Angular

  3. Таксама дадамо правіла, якое адкрые знешняму свету парты PostgreSQL і management-панэлі RabbitMQ:

    CI/CD у Github Actions для праекта на Flask+Angular

  4. Ужывальны правілы з дапамогай кнопкі Apply Changes:

    CI/CD у Github Actions для праекта на Flask+Angular

Настройка CI/CD у Github Actions

Прыступім да самай цікавай часткі - наладзе пайплайн бесперапыннай інтэграцыі і дастаўкі нашага праекта да сервера.

Гэты пайплайн будзе складацца з дзвюх частак:

  • зборка выявы і прагон тэстаў (для бэкенда) - на боку Github;
  • запуск міграцый (для бэкенда) і дэплой кантэйнераў - на серверы.

Дэплой у Plesk

Разбярэмся спачатку з другім пунктам (бо ад яго залежыць першы).

Працэс дэплою мы будзем наладжваць з дапамогай пашырэння Git для Plesk.

Разгледзім прыклад з Prod асяроддзем для Backend рэпазітара.

  1. Заходзім у падпіску нашага сайта Helloworld і пераходзім у падраздзел Git:

    CI/CD у Github Actions для праекта на Flask+Angular

  2. Устаўляемы ў поле «Remote Git repository» спасылку на наш Github-рэпазітар і змяняем тэчку па змаўчанні httpdocs на іншую (напрыклад, /httpdocs/hw_back):

    CI/CD у Github Actions для праекта на Flask+Angular

  3. Капіяваны SSH Public key з папярэдняга этапу і дадаем яго ў наладах Github.
  4. Націскаем ОК на экране ў пункце 2, пасля чаго нас перакідае на старонку рэпазітара ў Plesk. Цяпер нам трэба наладзіць абнаўленне рэпазітара пры комітах у галінку master. Для гэтага пераходзім у Repository Settings і захоўваем значэнне Webhook URL (яно нам спатрэбіцца пазней пры наладзе Github Actions):

    CI/CD у Github Actions для праекта на Flask+Angular

  5. У поле 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
  6. Дадаем карыстальніка з нашай падпіскі ў групу Docker (каб ён мог кіраваць кантэйнерамі):
    sudo usermod -aG docker helloworld_admin

Dev-асяроддзе для backend-рэпазітара і frontend наладжваюцца аналагічна.

Pipeline дэплою ў Github Actions

Пераходзім да налады першай часткі нашага CI/CD-пайплана ў Github Actions.

Backend

Пайплайн апісваецца ў файле deploy.yml.

Але перад яго разборам запоўнім у 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

CI/CD у Github Actions для праекта на Flask+Angular

Frontend

CI/CD у Github Actions для праекта на Flask+Angular
Важнае ўдакладненне. У фронтэнд-кантэйнер будуць праксіравацца ўсе URL, акрамя якія пачынаюцца на /api/ - Яны будуць праксіраваны ў бэк-кантэйнер (таму у бэк-кантэйнеры ўсе апрацоўшчыкі павінны пачынацца з /api/).

Вынікі

Цяпер наш сайт павінен быць даступны па адрасах helloworld.ru і dev.helloworld.ru (prod- і dev-асяроддзе адпаведна).

Разам, мы даведаліся, як падрыхтаваць простае дадатак на Flask і Angular і наладзіць у Github Actions пайплайн для яго выкаткі на сервер пад кіраваннем Plesk.

Прадублірую спасылкі на рэпазітары з кодам: бэкенд, франтэнд.

Крыніца: habr.com

Дадаць каментар