CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

CI/CD sa Github Actions para sa isang Flask+Angular na proyekto
Sa artikulong ito, ibabahagi ko ang aking karanasan sa pag-set up ng CI/CD gamit ang Plesk Control Panel at Github Actions. Ngayon ay matututunan natin kung paano mag-deploy ng isang simpleng proyekto na may hindi kumplikadong pangalan na "Helloworld". Ito ay nakasulat sa Flask Python framework, kasama ang mga manggagawa ng Celery at isang Angular 8 frontend.

Mga link sa mga repository: backend, frontend.

Sa unang bahagi ng artikulo, titingnan natin ang aming proyekto at ang mga bahagi nito. Sa pangalawa, malalaman natin kung paano i-set up ang Plesk at i-install ang mga kinakailangang extension at bahagi (DB, RabbitMQ, Redis, Docker, atbp.).

Sa ikatlong bahagi, malalaman natin sa wakas kung paano mag-set up ng pipeline para sa pag-deploy ng aming proyekto sa isang server sa isang dev at prod environment. At pagkatapos ay ilulunsad namin ang site sa server.

And yes, nakalimutan kong magpakilala. Ang pangalan ko ay Oleg Borzov, isa akong fullstack developer sa CRM team para sa mga mortgage manager sa Domclick.

Pangkalahatang-ideya ng Proyekto

Una, tingnan natin ang dalawang repositoryo ng proyekto - backend at harap - at suriin ang code.

Backend: Flask+Celery

Para sa likod na bahagi, kumuha ako ng isang grupo na medyo sikat sa mga developer ng Python: ang Flask framework (para sa API) at Celery (para sa task queue). Ginagamit ang SQLAchemy bilang ORM. Ginagamit ang Alembic para sa mga migrasyon. Para sa pagpapatunay ng JSON sa mga hawakan - Marshmallow.

Π’ mga repositoryo mayroong Readme.md file na may detalyadong paglalarawan ng istraktura at mga tagubilin para sa pagpapatakbo ng proyekto.

Web Part API medyo simple, binubuo ng 6 na panulat:

  • /ping - upang suriin ang pagkakaroon;
  • humahawak para sa pagpaparehistro, awtorisasyon, pag-alis ng pahintulot at pagkuha ng awtorisadong gumagamit;
  • isang email handle na naglalagay ng gawain sa Celery queue.

Bahagi ng kintsay kahit na mas madali, mayroon lamang isang problema send_mail_task.

Sa folder /conf mayroong dalawang subfolder:

  • docker na may dalawang Dockerfiles (base.dockerfile upang bumuo ng isang bihirang pagbabago ng base na imahe at Dockerfile para sa mga pangunahing pagtitipon);
  • .env_files - na may mga file na may mga variable ng kapaligiran para sa iba't ibang mga kapaligiran.

Mayroong apat na docker-compose file sa ugat ng proyekto:

  • docker-compose.local.db.yml upang itaas ang isang lokal na database para sa pag-unlad;
  • docker-compose.local.workers.yml para sa lokal na pagpapalaki ng manggagawa, database, Redis at RabbitMQ;
  • docker-compose.test.yml upang magpatakbo ng mga pagsubok sa panahon ng pag-deploy;
  • docker-compose.yml para sa deployment.

At ang huling folder na interesado kami - .ci-cd. Naglalaman ito ng mga script ng shell para sa pag-deploy:

  • deploy.sh β€” paglulunsad ng migration at deployment. Tumatakbo sa server pagkatapos bumuo at magpatakbo ng mga pagsubok sa Github Actions;
  • rollback.sh - rollback ng mga lalagyan sa nakaraang bersyon ng pagpupulong;
  • curl_tg.sh - pagpapadala ng mga abiso sa pag-deploy sa Telegram.

Frontend sa Angular

Imbakan na may harap mas simple kaysa kay Beck. Ang harap ay binubuo ng tatlong pahina:

  • Pangunahing pahina na may form para sa pagpapadala ng email at isang exit button.
  • Pahina sa pag-login.
  • Pahina ng pagpaparehistro.

Ang pangunahing pahina ay mukhang asetiko:

CI/CD sa Github Actions para sa isang Flask+Angular na proyekto
Mayroong dalawang mga file sa ugat Dockerfile ΠΈ docker-compose.yml, pati na rin ang pamilyar na folder .ci-cd na may bahagyang mas kaunting mga script kaysa sa likod na repository (inalis ang mga script para sa pagpapatakbo ng mga pagsubok).

Pagsisimula ng isang proyekto sa Plesk

Magsimula tayo sa pamamagitan ng pag-set up ng Plesk at paggawa ng subscription para sa aming site.

Pag-install ng mga extension

Sa Plesk, kailangan namin ng apat na extension:

  • Docker upang pamahalaan at biswal na ipakita ang katayuan ng mga lalagyan sa panel ng admin ng Plesk;
  • Git upang i-configure ang hakbang sa pag-deploy sa server;
  • Let's Encrypt upang bumuo (at mag-auto-renew) ng mga libreng TLS certificate;
  • Firewall upang i-configure ang pag-filter ng papasok na trapiko.

Maaari mong i-install ang mga ito sa pamamagitan ng Plesk admin panel sa seksyong Mga Extension:

CI/CD sa Github Actions para sa isang Flask+Angular na proyekto
Hindi namin isasaalang-alang ang mga detalyadong setting para sa mga extension, gagawin ng mga default na setting para sa aming mga layunin ng demo.

Gumawa ng subscription at site

Susunod, kailangan naming lumikha ng isang subscription para sa aming helloworld.ru website at idagdag ang dev.helloworld.ru subdomain doon.

  1. Lumikha ng isang subscription para sa helloworld.ru domain at tukuyin ang login-password para sa user ng system:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto
    Lagyan ng check ang kahon sa ibaba ng pahina I-secure ang domain gamit ang Let's Encryptkung gusto naming mag-set up ng HTTPS para sa site:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  2. Susunod, sa subscription na ito, lumikha ng subdomain dev.helloworld.ru (kung saan maaari ka ring mag-isyu ng libreng TLS certificate):

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

Pag-install ng Mga Bahagi ng Server

Mayroon kaming isang server na may OS Debian Stretch 9.12 at naka-install na control panel Plesk Obsidian 18.0.27.

Kailangan naming i-install at i-configure para sa aming proyekto:

  • PostgreSQL (sa aming kaso, magkakaroon ng isang server na may dalawang database para sa dev at prod environment).
  • RabbitMQ (pareho, parehong halimbawa sa iba't ibang vhosts para sa mga kapaligiran).
  • Dalawang Redis instance (para sa dev at prod environment).
  • Docker Registry (para sa lokal na imbakan ng mga built Docker na imahe).
  • UI para sa pagpapatala ng Docker.

PostgreSQL

Ang Plesk ay mayroon nang PostgreSQL DBMS, ngunit hindi ang pinakabagong bersyon (sa panahon ng pagsulat ng Plesk Obsidian suportado Mga bersyon ng Postgres 8.4–10.8). Gusto namin ang pinakabagong bersyon para sa aming application (12.3 sa oras ng pagsulat na ito), kaya manu-mano namin itong i-install.

Mayroong maraming mga detalyadong tagubilin para sa pag-install ng Postgres sa Debian sa net (halimbawa), kaya hindi ko ilalarawan ang mga ito nang detalyado, ibibigay ko lang ang mga utos:

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

Dahil ang PostgreSQL ay may medyo katamtamang default na mga setting, kinakailangan na ayusin ang pagsasaayos. Makakatulong ito sa atin calculator: kailangan mong magmaneho sa mga parameter ng iyong server at palitan ang mga setting sa file /etc/postgresql/12/main/postgresql.confsa mga inaalok. Dapat pansinin dito na ang mga naturang calculator ay hindi isang magic bullet, at ang base ay dapat na nakatutok nang mas tumpak, batay sa iyong hardware, application, at pagiging kumplikado ng query. Ngunit ito ay sapat na upang makapagsimula.

Bilang karagdagan sa mga setting na iminungkahi ng calculator, nagbabago din kami postgresql.confang default na port 5432 sa isa pa (sa aming halimbawa - 53983).

Pagkatapos baguhin ang configuration file, i-restart ang postgresql-server gamit ang command:

service postgresql restart

Na-install at na-configure namin ang PostgreSQL. Ngayon, gumawa tayo ng database, mga user para sa dev at prod environment, at bigyan ang mga user ng mga karapatan na pamahalaan ang database:

$ 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

Kuneho MQ

Lumipat tayo sa pag-install ng RabbitMQ, isang message broker para sa Celery. Ang pag-install nito sa Debian ay medyo simple:

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

Pagkatapos ng pag-install, kailangan naming lumikha vhosts, mga user at ibigay ang mga kinakailangang karapatan:

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

Ngayon ay i-install at i-configure natin ang huling bahagi para sa ating application - Redis. Gagamitin ito bilang backend para sa pag-iimbak ng mga resulta ng mga gawain sa Celery.

Magtataas kami ng dalawang Docker container na may Redis para sa dev at prod environment gamit ang extension Docker para sa Plesk.

  1. Pumunta kami sa Plesk, pumunta sa seksyong Mga Extension, hanapin ang extension ng Docker at i-install ito (kailangan namin ng libreng bersyon):

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  2. Pumunta sa naka-install na extension, hanapin ang larawan sa pamamagitan ng paghahanap redis bitnami at i-install ang pinakabagong bersyon:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  3. Pumunta kami sa na-download na lalagyan at ayusin ang pagsasaayos: tukuyin ang port, ang maximum na inilaan na laki ng RAM, ang password sa mga variable ng kapaligiran, at i-mount ang volume:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  4. Nagsasagawa kami ng mga hakbang 2-3 para sa lalagyan ng prod, sa mga setting ay binabago lang namin ang mga parameter: port, password, laki ng RAM at path sa volume folder sa server:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

Docker Registry

Bilang karagdagan sa mga pangunahing serbisyo, mainam na ilagay ang iyong sariling Docker image repository sa server. Sa kabutihang palad, ang espasyo ng server ay medyo mura na ngayon (tiyak na mas mura kaysa sa isang subscription sa DockerHub), at ang proseso ng pag-set up ng isang pribadong repositoryo ay napakasimple.

Nais naming magkaroon ng:

Upang gawin ito:

  1. Gumawa tayo ng dalawang subdomain sa Plesk sa ating subscription: docker.helloworld.ru at docker-ui.helloworld.ru, at i-configure ang Let's Encrypt certificate para sa kanila.
  2. Idagdag ang file sa docker.helloworld.ru subdomain folder docker-compose.yml na may nilalaman tulad nito:
    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. Sa ilalim ng SSH, bubuo kami ng .htpasswd file para sa Basic authorization sa Docker repository:
    htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
  4. Kolektahin at iangat ang mga lalagyan:
    docker-compose up -d
  5. At kailangan naming i-redirect ang Nginx sa aming mga lalagyan. Magagawa ito sa pamamagitan ng Plesk.

Ang mga sumusunod na hakbang ay kailangang gawin para sa docker.helloworld.ru at docker-ui.helloworld.ru na mga subdomain:

Sa seksyon Mga tool sa Dev pumunta sa aming site Mga Panuntunan ng Docker Proxy:

CI/CD sa Github Actions para sa isang Flask+Angular na proyekto
At magdagdag ng panuntunan sa proxy na papasok na trapiko sa aming container:

CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  1. Sinusuri namin na maaari kaming mag-log in sa aming lalagyan mula sa lokal na makina:
    $ 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. Suriin din natin ang pagpapatakbo ng docker-ui.helloworld.ru subdomain:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto
    Kapag nag-click ka sa Mag-browse ng mga repositoryo, magpapakita ang browser ng window ng pahintulot kung saan kakailanganin mong ipasok ang username at password para sa repositoryo. Pagkatapos nito, ire-redirect kami sa isang pahina na may listahan ng mga repositoryo (sa ngayon, ito ay walang laman para sa iyo):

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

Pagbubukas ng mga port sa Plesk Firewall

Pagkatapos i-install at i-configure ang mga bahagi, kailangan naming buksan ang mga port upang ang mga bahagi ay ma-access mula sa mga lalagyan ng Docker at sa panlabas na network.

Tingnan natin kung paano ito gawin gamit ang extension ng Firewall para sa Plesk na na-install namin kanina.

  1. Pumunta sa Mga Tool at Setting > Mga Setting > Firewall:
    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto
  2. Pumunta sa Baguhin ang Mga Panuntunan sa Plesk Firewall > Magdagdag ng Custom na Panuntunan at buksan ang mga sumusunod na TCP port para sa Docker subnet (172.0.0.0 / 8):
    RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
    Redis: 32785, 32786

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  3. Magdaragdag din kami ng panuntunan na magbubukas ng mga PostgreSQL port at RabbitMQ management panel sa labas ng mundo:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  4. Ilapat ang mga panuntunan gamit ang button na Ilapat ang Mga Pagbabago:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

Pagse-set up ng CI/CD sa Github Actions

Bumaba tayo sa pinakakawili-wiling bahagi - ang pag-set up ng tuluy-tuloy na pipeline ng pagsasama at paghahatid ng aming proyekto sa server.

Ang pipeline na ito ay binubuo ng dalawang bahagi:

  • pagbuo ng isang imahe at pagpapatakbo ng mga pagsubok (para sa backend) - sa gilid ng Github;
  • pagpapatakbo ng mga paglilipat (para sa backend) at pag-deploy ng mga lalagyan - sa server.

I-deploy sa Plesk

Unahin natin ang pangalawang punto (dahil ang una ay nakasalalay dito).

Iko-configure namin ang proseso ng pag-deploy gamit ang Git extension para sa Plesk.

Isaalang-alang ang isang halimbawa sa isang Prod environment para sa isang Backend na repository.

  1. Pumunta kami sa subscription ng aming Helloworld website at pumunta sa Git subsection:

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  2. Magpasok ng link sa aming Github repository sa field na "Remote Git repository" at baguhin ang default na folder httpdocs sa iba (hal. /httpdocs/hw_back):

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  3. Kopyahin ang SSH Public key mula sa nakaraang hakbang at idagdag ito sa mga setting ng Github.
  4. I-click ang OK sa screen sa hakbang 2, pagkatapos nito ay ire-redirect tayo sa pahina ng repositoryo sa Plesk. Ngayon kailangan nating i-configure ang repository na ma-update sa mga commit sa master branch. Upang gawin ito, pumunta sa Mga Setting ng Imbakan at i-save ang halaga Webhook URL (kailangan namin ito sa ibang pagkakataon kapag nagse-set up ng Github Actions):

    CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

  5. Sa field ng Actions sa screen mula sa nakaraang talata, ilagay ang script para ilunsad ang deployment:
    cd {REPOSITORY_ABSOLUTE_PATH}
    .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID} 

    kung saan:

    {REPOSITORY_ABSOLUTE_PATH} - path sa prod folder ng backend repository sa server;
    {ENV} - kapaligiran (dev / prod), sa aming kaso prod;
    {DOCKER_REGISTRY_HOST} - ang host ng aming docker repository
    {TG_BOT_TOKEN} β€” Telegram bot token;
    {TG_CHAT_ID} β€” ID ng chat/channel para sa pagpapadala ng mga notification.

    Halimbawa ng script:

    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. Nagdagdag kami ng user mula sa aming subscription sa Docker group (upang mapamahalaan niya ang mga container):
    sudo usermod -aG docker helloworld_admin

Ang dev environment para sa backend repository at frontend ay naka-set up sa parehong paraan.

Deployment pipeline sa Github Actions

Magpatuloy tayo sa pag-set up ng unang bahagi ng aming CI/CD pipeline sa Github Actions.

backend

Ang pipeline ay inilarawan sa deploy.yml file.

Ngunit bago ito i-parse, punan natin ang mga Lihim na variable na kailangan natin sa Github. Upang gawin ito, pumunta sa Mga Setting -> Mga Lihim:

  • DOCKER_REGISTRY - ang host ng aming Docker repository (docker.helloworld.ru);
  • DOCKER_LOGIN - mag-login sa imbakan ng Docker;
  • DOCKER_PASSWORD - password dito;
  • DEPLOY_HOST β€” host kung saan available ang Plesk admin panel (halimbawa: helloworld.com:8443 o 123.4.56.78:8443);
  • DEPLOY_BACK_PROD_TOKEN - isang token para sa pag-deploy sa prod-repository sa server (nakuha namin ito sa Deployment sa Plesk p. 4);
  • DEPLOY_BACK_DEV_TOKEN - token para sa pag-deploy sa dev repository sa server.

Ang proseso ng pag-deploy ay simple at binubuo ng tatlong pangunahing hakbang:

  • pagbuo at pag-publish ng imahe sa aming repository;
  • pagpapatakbo ng mga pagsubok sa isang lalagyan batay sa isang bagong gawa na imahe;
  • deployment sa nais na kapaligiran depende sa sangay (dev/master).

Frontend

Ang deploy.yml file para sa front repository medyo naiiba sa Beck's. Wala itong hakbang sa pagpapatakbo ng mga pagsubok at binabago ang mga pangalan ng mga token para sa pag-deploy. Ang mga lihim para sa front repository, sa pamamagitan ng paraan, ay kailangang punan nang hiwalay.

Pag-setup ng site

Pag-proxy ng trapiko sa pamamagitan ng Nginx

Well, kami ay dumating sa dulo. Ito ay nananatiling lamang upang i-configure ang proxying ng papasok at papalabas na trapiko sa aming lalagyan sa pamamagitan ng Nginx. Nasaklaw na namin ang prosesong ito sa hakbang 5 ng Docker Registry setup. Ang parehong ay dapat na paulit-ulit para sa likod at harap na mga bahagi sa dev at prod environment.

Magbibigay ako ng mga screenshot ng mga setting.

backend

CI/CD sa Github Actions para sa isang Flask+Angular na proyekto

Frontend

CI/CD sa Github Actions para sa isang Flask+Angular na proyekto
Mahalagang paglilinaw. Ang lahat ng URL ay i-proxy sa frontend na lalagyan, maliban sa mga nagsisimula sa /api/ - sila ay i-proxy sa likod na lalagyan (kaya sa lalagyan sa likod, dapat magsimula ang lahat ng humahawak /api/).

Mga resulta ng

Ngayon ang aming site ay dapat na available sa helloworld.ru at dev.helloworld.ru (prod- at dev-environment, ayon sa pagkakabanggit).

Sa kabuuan, natutunan namin kung paano maghanda ng simpleng application sa Flask at Angular at mag-set up ng pipeline sa Github Actions para ilunsad ito sa isang server na nagpapatakbo ng Plesk.

Doblehin ko ang mga link sa mga repository na may code: backend, frontend.

Pinagmulan: www.habr.com

Magdagdag ng komento