{"id":85646,"date":"2020-06-18T01:42:15","date_gmt":"2020-06-17T23:42:15","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular"},"modified":"2020-06-18T01:42:15","modified_gmt":"2020-06-17T23:42:15","slug":"ci-cd-v-github-actions-dlya-proekta-na-flask-angular","status":"publish","type":"post","link":"https:\/\/prohoster.info\/lv\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular","title":{"rendered":"CI\/CD ar Github Actions Flask+Angular projektam","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/26d0945a41bbf3c98fa92f15be5b8c6c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u0160aj\u0101 rakst\u0101 es dal\u012b\u0161os ar savu pieredzi CI\/CD iestat\u012b\u0161an\u0101, izmantojot Plesk vad\u012bbas paneli un Github Actions. \u0160odien m\u0101c\u012bsimies izvietot vienk\u0101r\u0161u projektu ar nosaukumu \u201eHelloworld\u201d. Tas ir izstr\u0101d\u0101ts Python ietvar\u0101 Flask, ar uzdevumu izpild\u012bt\u0101jiem Celery un frontend\u0101 Angular 8.<\/p>\n<p><b>Saite uz repozitorijiem:<\/b> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\">backend<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld-front\">frontend<\/a><\/noindex>.<\/p>\n<p>Pirmaj\u0101 raksta da\u013c\u0101 m\u0113s apskat\u012bsim m\u016bsu projektu un t\u0101 komponentes. Otraj\u0101 \u2014 izp\u0113t\u012bsim, k\u0101 iestat\u012bt Plesk un instal\u0113t nepiecie\u0161amos papla\u0161in\u0101jumus un komponentus (DB, RabbitMQ, Redis, Docker u.t.t.).<\/p>\n<p>Tre\u0161aj\u0101 da\u013c\u0101 m\u0113s, galu gal\u0101, noskaidrosim, k\u0101 iestat\u012bt pipeline m\u016bsu projekta ievieto\u0161anai server\u012b dev- un prod-vid\u0113s. Un p\u0113c tam palaid\u012bsim vietni uz servera.<\/p>\n<p>Un j\u0101, aizmirsu sevi iepaz\u012bstin\u0101t. Mani sauc O\u013cegs Borzovs, es esmu fullstack izstr\u0101d\u0101t\u0101js CRM komand\u0101, kas str\u0101d\u0101 ar hipotek\u0101ro kred\u012btu mened\u017eeriem Domklik\u0101. <br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h1>Projekta apskats<\/h1>\n<p>\nVispirms apskat\u012bsim divus projekta repozitorijus \u2014 backend un frontend \u2014 un \u0101tri p\u0101riesim cauri kodam.<\/p>\n<h2>Backend da\u013ca: Flask+Celery<\/h2>\n<p>\nBackend da\u013cai es izmantoju diezgan popul\u0101ro kombin\u0101ciju starp Python izstr\u0101d\u0101t\u0101jiem: Flask ietvars (API) un Celery (uzdevumu rinda). ORM ir SQLAlchemy. Migr\u0101cij\u0101m izmanto Alembic. JSON valid\u0101cijai rokas rezult\u0101tos \u2014 Marshmallow.<\/p>\n<p>No <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\">repozitorij\u0101<\/a><\/noindex> ir Readme.md fails ar detaliz\u0113tu strukt\u016bras aprakstu un instrukcij\u0101m projekta palai\u0161anai.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/tree\/master\/app_web\">API web da\u013cai<\/a><\/noindex> ir diezgan vienk\u0101r\u0161s, sast\u0101v no 6 rokas:<\/p>\n<ul>\n<li><code>\/ping<\/code> \u2014 pieejam\u012bbas p\u0101rbaudei;<\/li>\n<li>roka re\u0123istr\u0101cijai, autoriz\u0101cijai, deautoriz\u0101cijai un autoriz\u0113t\u0101 lietot\u0101ja ieg\u016b\u0161anai;<\/li>\n<li>roka e-pasta s\u016bt\u012b\u0161anai, kas pievieno uzdevumu Celery rindai.<\/li>\n<\/ul>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/tree\/master\/app_celery\">Celery da\u013ca<\/a><\/noindex> v\u0113l vienk\u0101r\u0161\u0101ka, tur ir tikai viens uzdevums <code>send_mail_task<\/code>.<\/p>\n<p>Map\u0113 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/tree\/master\/conf\/\">\/conf<\/a><\/noindex> ir divas apak\u0161mapes: <\/p>\n<ul>\n<li><code>docker<\/code> ar diviem Docker failiem (<code>base.dockerfile<\/code> lai izveidotu reti main\u012bgu pamata att\u0113lu un <code>Dockerfile<\/code> galvenaj\u0101m kompil\u0101cij\u0101m);<\/li>\n<li><code>.env_files<\/code> \u2014 ar main\u012bgo apk\u0101rt\u0113jo failiem da\u017e\u0101d\u0101m vid\u0113m. <\/li>\n<\/ul>\n<p>\nProjekta sakn\u0113 atrodas \u010detri faila docker-compose:<\/p>\n<ul>\n<li><code>docker-compose.local.db.yml<\/code> lok\u0101l\u0101s DB uzst\u0101d\u012b\u0161anai izstr\u0101dei;<\/li>\n<li><code>docker-compose.local.workers.yml<\/code> lok\u0101lo darbinieka, DB, Redis un RabbitMQ uzst\u0101d\u012b\u0161anai;<\/li>\n<li><code>docker-compose.test.yml<\/code> testu veik\u0161anai izvieto\u0161anas laik\u0101;<\/li>\n<li><code>docker-compose.yml<\/code> izvieto\u0161anai.<\/li>\n<\/ul>\n<p>\nUn p\u0113d\u0113j\u0101 interesant\u0101 mape \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/tree\/master\/.ci-cd\">.ci-cd<\/a><\/noindex>. Taj\u0101 atrodas shell skripti izvieto\u0161anai:<\/p>\n<ul>\n<li><code>deploy.sh<\/code> \u2014 migr\u0101cijas un izvieto\u0161anas palai\u0161ana. S\u0101kas server\u012b p\u0113c kompil\u0101cijas un testu veik\u0161anas Github Actions;<\/li>\n<li><code>rollback.sh<\/code> \u2014 konteineru atgrie\u0161ana iepriek\u0161\u0113j\u0101 versij\u0101;<\/li>\n<li><code>curl_tg.sh<\/code> \u2014 pazi\u0146ojumu s\u016bt\u012b\u0161ana par izvieto\u0161anu Telegram.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Priek\u0161\u0113jais pl\u0101ns uz Angular<\/h2>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld-front\">Repozitorijs ar priek\u0161pusi<\/a><\/noindex> k\u0101 \u013coti vienk\u0101r\u0161s aizmugures pl\u0101ns. Priek\u0161puse sast\u0101v no trim lap\u0101m:<\/p>\n<ul>\n<li>Galven\u0101 lapa ar veidlapu e-pasta nos\u016bt\u012b\u0161anai un izejas pogu.<\/li>\n<li>Ieejas lapa.<\/li>\n<li>Re\u0123istr\u0101cijas lapa.<\/li>\n<\/ul>\n<p>\nGalven\u0101 lapa izskat\u0101s attur\u012bgi:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/4db36add2c4277397724b0d71b96ff06.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPamat\u0101 atrodas divas failu <code>Dockerfile<\/code> un <code>docker-compose.yml<\/code>, k\u0101 ar\u012b paz\u012bstam\u0101 mums mapa <code>.ci-cd<\/code> ar nedaudz maz\u0101ku skriptu skaitu nek\u0101 aizmugures pl\u0101n\u0101 (no\u0146emti skripti testu palai\u0161anai).<\/p>\n<h1>Izveidojam projektu Plesk\u0101<\/h1>\n<p>\nS\u0101ksim ar Plesk iestat\u012b\u0161anu un abonementa izveidi m\u016bsu vietnei.<\/p>\n<h2>Papla\u0161in\u0101jumu uzst\u0101d\u012b\u0161ana<\/h2>\n<p>\nPlesk\u0101 mums b\u016bs nepiecie\u0161ami \u010detri papla\u0161in\u0101jumi: <\/p>\n<ul>\n<li><code>Docker<\/code> lai vad\u012btu un vizu\u0101li att\u0113lotu konteineru st\u0101vokli Plesk administr\u0101cij\u0101;<\/li>\n<li><code>Git<\/code> lai konfigur\u0113tu izvieto\u0161anas soli server\u012b;<\/li>\n<li><code>Let's Encrypt<\/code> lai \u0123ener\u0113tu (un autom\u0101tiski atjaunotu) bezmaksas TLS sertifik\u0101tus;<\/li>\n<li><code>Ugunsm\u016bris<\/code> lai konfigur\u0113tu ien\u0101ko\u0161\u0101 trafika filtr\u0113\u0161anu.<\/li>\n<\/ul>\n<p>\nIesp\u0113jams tos uzst\u0101d\u012bt caur Plesk administr\u0101ciju sada\u013c\u0101 Papla\u0161in\u0101jumi:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/350cf7d7ca3ae1a965a0d3f8a73594ef.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDet\u0101l\u0101kas papla\u0161in\u0101jumu iestat\u012b\u0161anas m\u0113s neizskat\u012bsim, m\u016bsu demonstr\u0101cijas m\u0113r\u0137iem der\u0113s noklus\u0113juma iestat\u012bjumi.<\/p>\n<h2>Abonementa un vietnes izveide<\/h2>\n<p>\nT\u0101l\u0101k mums j\u0101izveido abonements m\u016bsu vietnei helloworld.ru un j\u0101pievieno apak\u0161dom\u0113ns dev.helloworld.ru.<\/p>\n<ol>\n<li>Izveidojam abonementu dom\u0113nam helloworld.ru un nor\u0101d\u0101m sist\u0113mas lietot\u0101ja lietot\u0101jv\u0101rdu-paroli:\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/3932dc7492aa523b6cbd540ad7a7fe6b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLapas apak\u0161da\u013c\u0101 atz\u012bm\u0113jam izv\u0113les r\u016bti\u0146u <i>Nodro\u0161iniet dom\u0113nu ar Let's Encrypt<\/i>, ja v\u0113lamies iestat\u012bt HTTPS vietnei:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/f4d23a34764fdeb411fe2ca9cc95cb45.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>T\u0101l\u0101k \u0161aj\u0101 abonement\u0101 izveidojam apak\u0161dom\u0113nu dev.helloworld.ru (kuram ar\u012b var izsniegt bezmaksas TLS sertifik\u0101tu):\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/d57e6ba71454cb537917400de4275e92.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ol>\n<p><\/p>\n<h1>Servera komponentu uzst\u0101d\u012b\u0161ana<\/h1>\n<p>\nMums ir serveris ar <i>OS Debian Stretch 9.12<\/i> un uzst\u0101d\u012btu vad\u012bbas paneli <i>Plesk Obsidian 18.0.27<\/i>.<\/p>\n<p>Mums j\u0101uzst\u0101da un j\u0101konfigur\u0113 m\u016bsu projektam:<\/p>\n<ul>\n<li>PostgreSQL (m\u016bsu gad\u012bjum\u0101 b\u016bs viens serveris ar div\u0101m DB dev- un prod-vid\u0113m).<\/li>\n<li>RabbitMQ (tas pats, viens instants ar da\u017e\u0101diem vhosts vid\u0113m).<\/li>\n<li>Divi Redis instanti (dev- un prod-vid\u0113m).<\/li>\n<li>Docker Registry (lok\u0101las saglab\u0101\u0161anas m\u0113r\u0137iem konstru\u0113tiem Docker att\u0113liem).<\/li>\n<li>UI interfeiss Docker registry.<\/li>\n<\/ul>\n<p><\/p>\n<h2>PostgreSQL<\/h2>\n<p>\nKop\u0101 ar Plesk jau ietilpst SGBD PostgreSQL, tom\u0113r ne pati jaun\u0101k\u0101 versija (raksta laik\u0101 Plesk Obsidian <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.plesk.com\/release-notes\/obsidian\/software-requirements\/\">atbalst\u012bja<\/a><\/noindex> Postgres versijas 8.4\u201310.8). M\u0113s v\u0113lamies m\u016bsu lietojumam pa\u0161laik jaun\u0101ko versiju (12.3 raksta laik\u0101), t\u0101p\u0113c uzst\u0101d\u012bsim to manu\u0101li.<\/p>\n<p>Interneta telp\u0101 ir daudz detaliz\u0113tu instrukciju par PostgreSQL uzst\u0101d\u012b\u0161anu Debian (<noindex><a rel=\"nofollow\" href=\"https:\/\/tecadmin.net\/install-postgresql-on-debian-9-stretch\/\">piem\u0113rs<\/a><\/noindex>), t\u0101p\u0113c detaliz\u0113ti t\u0101s neaprakst\u012b\u0161u, vienk\u0101r\u0161i nor\u0101d\u012b\u0161u komandas:<\/p>\n<pre><code class=\"bash\">wget -q https:\/\/www.postgresql.org\/media\/keys\/ACCC4CF8.asc -O - | sudo apt-key add -\nsudo sh -c 'echo \"deb http:\/\/apt.postgresql.org\/pub\/repos\/apt\/ stretch-pgdg main\" &gt;&gt; \/etc\/apt\/sources.list.d\/pgdg.list'\n\nsudo apt-get update\nsudo apt-get install postgresql postgresql-contrib\n<\/code><\/pre>\n<p>\n\u0145emot v\u0113r\u0101 to, ka PostgreSQL noklus\u0113juma iestat\u012bjumi ir diezgan viduv\u0113ji, ir nepiecie\u0161ams piel\u0101got konfigur\u0101ciju. Mums \u0161aj\u0101 pal\u012bdz\u0113s <noindex><a rel=\"nofollow\" href=\"http:\/\/pgconfigurator.cybertec.at\/\">kalkulators<\/a><\/noindex>: j\u0101ievada sava servera parametri un j\u0101nomaina iestat\u012bjumi fail\u0101 <code>\/etc\/postgresql\/12\/main\/postgresql.conf<\/code>uz ieteiktajiem. \u0160eit j\u0101nor\u0101da, ka \u0161\u0101di kalkulatori nav br\u012bnuml\u012bdzeklis, un datub\u0101ze j\u0101optimiz\u0113 prec\u012bz\u0101k, \u0146emot v\u0113r\u0101 j\u016bsu aparat\u016bru, lietojumprogrammu un vaic\u0101jumu sare\u017e\u0123\u012bt\u012bbu. Bet s\u0101kumam \u0161is ir pietiekami.<\/p>\n<p>Papildus kalkulatora ieteiktajiem iestat\u012bjumiem m\u0113s ar\u012b main\u0101m <code>postgresql.conf<\/code>noklus\u0113juma portu 5432 uz citu (m\u016bsu piem\u0113r\u0101 \u2014 <strong>53983<\/strong>).<\/p>\n<p>P\u0113c konfigur\u0101cijas faila izmai\u0146\u0101m restart\u0113jam postgresql-server ar komandu:<\/p>\n<pre><code class=\"bash\">service postgresql restart\n<\/code><\/pre>\n<p>\nM\u0113s esam instal\u0113ju\u0161i un konfigur\u0113ju\u0161i PostgreSQL. Tagad izveidosim datub\u0101zi, lietot\u0101jus dev- un prod-vid\u0113m un pie\u0161\u0137irsim lietot\u0101jiem ties\u012bbas p\u0101rvald\u012bt datub\u0101zi:<\/p>\n<pre><code class=\"bash\">$ su - postgres\npostgres:~$ create database hw_dev_db_name;\nCREATE DATABASE\npostgres:~$ create user hw_dev_db_user with password 'hw_dev_db_password';\nCREATE ROLE\npostgres:~$ grant ALL privileges ON database hw_dev_db_name to hw_dev_db_user;\nGRANT\npostgres:~$ create database hw_prod_db_name;\nCREATE DATABASE\npostgres:~$ create user hw_prod_db_user with password 'hw_prod_db_password';\nCREATE ROLE\npostgres:~$ grant ALL privileges ON database hw_prod_db_name to hw_prod_db_user;\nGRANT\n<\/code><\/pre>\n<p><\/p>\n<h2>RabbitMQ<\/h2>\n<p>\nP\u0101riesim pie RabbitMQ \u2014 zi\u0146ojumu starpnieka uzst\u0101d\u012b\u0161anas Celery. To uzst\u0101d\u012bt Debian ir diezgan vienk\u0101r\u0161i:<\/p>\n<pre><code class=\"bash\">wget https:\/\/packages.erlang-solutions.com\/erlang-solutions_1.0_all.deb\nsudo dpkg -i erlang-solutions_1.0_all.deb\n\nsudo apt-get update\nsudo apt-get install erlang erlang-nox\n\nsudo add-apt-repository 'deb http:\/\/www.rabbitmq.com\/debian\/ testing main'\nwget -O- https:\/\/www.rabbitmq.com\/rabbitmq-release-signing-key.asc | sudo apt-key add -\n\nsudo apt-get update\nsudo apt-get install rabbitmq-server\n<\/code><\/pre>\n<p>\nP\u0113c uzst\u0101d\u012b\u0161anas mums j\u0101izveido <i>vhosts<\/i>, lietot\u0101ji un j\u0101pie\u0161\u0137ir nepiecie\u0161am\u0101s ties\u012bbas:<\/p>\n<pre><code class=\"bash\">sudo rabbitmqctl add_user hw_dev_amqp_user hw_dev_amqp_password \nsudo rabbitmqctl set_user_tags hw_dev_amqp_user administrator\nsudo rabbitmqctl add_vhost hw_dev_vhost\nsudo rabbitmqctl set_permissions -p hw_dev_vhost hw_dev_amqp_user \".*\" \".*\" \".*\"\n\nsudo rabbitmqctl add_user hw_prod_amqp_user hw_prod_amqp_password \nsudo rabbitmqctl set_user_tags hw_prod_amqp_user administrator\nsudo rabbitmqctl add_vhost hw_prod_vhost\nsudo rabbitmqctl set_permissions -p hw_prod_vhost hw_prod_amqp_user \".*\" \".*\" \".*\"\n<\/code><\/pre>\n<p><\/p>\n<h2>Redis<\/h2>\n<p>\nTagad uzst\u0101d\u012bsim un konfigur\u0113sim p\u0113d\u0113jo komponentu m\u016bsu lietojumprogrammai \u2014 Redis. To izmantosim k\u0101 backend rezult\u0101tu uzglab\u0101\u0161anai Celery uzdevumiem.<\/p>\n<p>M\u0113s uzs\u0101ksim divus Docker konteinerus ar Redis dev- un prod-vid\u0113m, izmantojot papla\u0161in\u0101jumu <code>Docker<\/code> Plesk.<\/p>\n<ol>\n<li>Ien\u0101kam Plesk\u0101, ejam uz sada\u013cu Papla\u0161in\u0101jumi, mekl\u0113jam papla\u0161in\u0101jumu Docker un instal\u0113jam to (mums nepiecie\u0161ama bezmaksas versija):\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/5638f9b40274e4f7441434279c76a426.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>P\u0101rej\u0101m uz instal\u0113to papla\u0161in\u0101jumu, atrodam caur mekl\u0113\u0161anu att\u0113lu <code>redis bitnami<\/code> un uzst\u0101d\u0101m jaun\u0101ko versiju:\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/578bbbed6a66a60a4f7410f7d61ea542.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Ien\u0101kam lejupiel\u0101d\u0113taj\u0101 konteiner\u0101 un piel\u0101gojam konfigur\u0101ciju: nor\u0101d\u0101m portu, maksim\u0101lo pie\u0161\u0137irto RAM lielumu, paroli main\u012bgajos, un mont\u0113jam apjomu:\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/8bc804b794735412f5e510b3049c5667.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Izpild\u0101m so\u013cus 2-3 prod-konteineram, tikai iestat\u012bjumos main\u0101m parametrus: portu, paroli, RAM lielumu un ce\u013cu uz mapes apjomu server\u012b:\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/3af50181c8b3e1ace23a8de11826cb51.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ol>\n<p><\/p>\n<h2>Docker Registry<\/h2>\n<p>\nPapildus pamata pakalpojumiem neb\u016btu slikti uzst\u0101d\u012bt uz servera savu Docker att\u0113lu repozitoriju. Galu gal\u0101, vieta serveros tagad ir diezgan l\u0113ta (noteikti l\u0113t\u0101k par DockerHub abonementu), un priv\u0101t\u0101 repozitorija uzst\u0101d\u012b\u0161ana ir \u013coti vienk\u0101r\u0161a. <\/p>\n<p>M\u0113s v\u0113lamies, lai mums b\u016btu uzst\u0101d\u012bts:<\/p>\n<ul>\n<li>parole aizsarg\u0101ts Docker reposit\u0101rijs, pieejams zem apak\u0161dom\u0113na <noindex><a rel=\"nofollow\" href=\"https:\/\/docker.helloworld.ru\">https:\/\/docker.helloworld.ru<\/a><\/noindex>;<\/li>\n<li>UI interfeiss att\u0113lu apskatei repozitorij\u0101, pieejams adress\u0113 <noindex><a rel=\"nofollow\" href=\"https:\/\/docker-ui.helloworld.ru\">https:\/\/docker-ui.helloworld.ru<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>\nTam:<\/p>\n<ol>\n<li>Izveidosim Plesk\u0101 divus apak\u0161dom\u0113nus m\u016bsu abonement\u0101: docker.helloworld.lv un docker-ui.helloworld.lv, un iestat\u012bsim tiem Let\u2019s Encrypt sertifik\u0101tus.<\/li>\n<li>Apak\u0161dom\u0113na docker.helloworld.lv map\u0113 pievienosim failu <code>docker-compose.yml<\/code> ar \u0161\u0101du saturu:\n<pre><code class=\"plaintext\">version: \"3\"\n\nservices:\n  docker-registry:\n    image: \"registry:2\"\n    restart: always\n    ports:\n      - \"53985:5000\"\n    environment:\n      REGISTRY_AUTH: htpasswd\n      REGISTRY_AUTH_HTPASSWD_REALM: basic-realm\n      REGISTRY_AUTH_HTPASSWD_PATH: \/auth\/.htpasswd\n      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: \/data\n    volumes:\n      - .\/.docker-registry.htpasswd:\/auth\/.htpasswd\n      - .\/data:\/data\n\n  docker-registry-ui:\n    image: konradkleine\/docker-registry-frontend:v2\n    restart: always\n    ports:\n      - \"53986:80\"\n    environment:\n      VIRTUAL_HOST: '*, https:\/\/*'\n      ENV_DOCKER_REGISTRY_HOST: 'docker-registry'\n      ENV_DOCKER_REGISTRY_PORT: 5000\n    links:\n      - 'docker-registry'\n<\/code><\/pre>\n<p>\n<\/li>\n<li>Izmantojot SSH, izveidosim failu .htpasswd, lai veiktu pamata autoriz\u0101ciju Docker reposit\u0101rij\u0101:\n<pre><code class=\"plaintext\">htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password<\/code><\/pre>\n<\/li>\n<li>Savilksim un uzs\u0101ksim konteinerus:\n<pre><code class=\"plaintext\">docker-compose up -d<\/code><\/pre>\n<\/li>\n<li>Un j\u0101p\u0101rvirza Nginx uz m\u016bsu konteineriem. To var izdar\u012bt caur Plesk. <\/li>\n<\/ol>\n<p>\nN\u0101kam\u0101s darb\u012bbas j\u0101dara apak\u0161dom\u0113niem docker.helloworld.lv un docker-ui.helloworld.lv:<\/p>\n<p>Sada\u013c\u0101 <i>Dev Tools<\/i> m\u016bsu m\u0101jas lap\u0101 ejam uz <i>Docker Proxy Rules<\/i>:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/d9c05901d95d61ce5db27a1a7cfddf49.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nUn pievienojam noteikumu ieejas satiksmes p\u0101rs\u016bkn\u0113\u0161anai uz m\u016bsu konteineru:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/faa85cf6da648ef55b7c87c44040efb1.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<ol>\n<li>P\u0101rbaud\u0101m, vai varam autoriz\u0113ties m\u016bsu konteiner\u0101 no lok\u0101l\u0101s ma\u0161\u012bnas:\n<pre><code class=\"plaintext\">$ docker login docker.helloworld.lv -u hw_docker_admin -p hw_docker_password\nWARNING! Using --password via the CLI is insecure. Use --password-stdin.\nLogin Succeeded<\/code><\/pre>\n<\/li>\n<li>T\u0101pat p\u0101rbaud\u012bsim apak\u0161dom\u0113na docker-ui.helloworld.lv darb\u012bbu:\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/fdd6e1396c27c02a88bcbd7efb12f247.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nNoklik\u0161\u0137inot uz Browse repositories, p\u0101rl\u016bkprogramma par\u0101d\u012bs autentifik\u0101cijas logu, kur\u0101 j\u0101ievada piesl\u0113g\u0161an\u0101s v\u0101rds un parole, lai piek\u013c\u016btu repozitorijam. P\u0113c tam m\u016bs novirz\u012bs uz repozitoriju saraksta lapu (j\u016bsu v\u0113l b\u016bs tuk\u0161a):<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/f2d75edb530e9d746095ae02d7793c1f.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ol>\n<p><\/p>\n<h2>Atveram portus Plesk ugunsm\u016br\u012b<\/h2>\n<p>\nP\u0113c komponentu instal\u0113\u0161anas un iestat\u012b\u0161anas mums j\u0101atver porti, lai komponenti b\u016btu pieejami no Docker konteinera un \u0101r\u0113j\u0101s t\u012bkla.<\/p>\n<p>Apskat\u012bsim, k\u0101 to izdar\u012bt, \u0146emot v\u0113r\u0101 iepriek\u0161 instal\u0113t\u0101 Plesk ugunsm\u016bra papla\u0161in\u0101juma piem\u0113ru.<\/p>\n<ol>\n<li>P\u0101rejam uz <i>Tools &amp; Settings &gt; Settings &gt; Firewall<\/i>:<br \/>\n<img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/d54b4941944fe191574472a475cbaebe.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>P\u0101rejam uz <i>Modify Plesk Firewall Rules &gt; Add Custom Rule<\/i> un atveram \u0161\u0101dus TCP portus Docker apak\u0161t\u012bklam (<strong>172.0.0.0\/8)<\/strong>:<br \/>\nRabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614<br \/>\nRedis: 32785, 32786<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/3359845f9bd6dc303274da737d4b27a2.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>T\u0101pat pievienosim noteikumu, kas atv\u0113rs \u0101r\u0113jai pasaulei PostgreSQL un RabbitMQ p\u0101rvald\u012bbas pane\u013ca portus:\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/f812cfc7127da469507538ea48b2c80d.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Piem\u0113rojam noteikumus, izmantojot pogu Apply Changes:\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/e85444ae717aaefa796664003fc86578.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ol>\n<p><\/p>\n<h1>CI\/CD konfigur\u0101cija Github Actions<\/h1>\n<p>\nS\u0101ksim ar pa\u0161u interesant\u0101ko da\u013cu \u2014 m\u016bsu projekta nep\u0101rtraukt\u0101s integr\u0101cijas un pieg\u0101des l\u012bnijas iestat\u012b\u0161anu l\u012bdz serverim.<\/p>\n<p>\u0160\u012b l\u012bnija sast\u0101v\u0113s no div\u0101m da\u013c\u0101m: <\/p>\n<ul>\n<li>att\u0113la izveide un testu izpilde (aizmugur\u0113) \u2014 Github pus\u0113;<\/li>\n<li>migr\u0101ciju izpilde (aizmugur\u0113) un konteineru izvieto\u0161ana \u2014 server\u012b.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Izvieto\u0161ana Plesk<\/h2>\n<p>\nS\u0101ksim vispirms ar otro punktu (jo tas ietekm\u0113 pirmo).<\/p>\n<p>Izvieto\u0161anas procesu m\u0113s konfigur\u0113sim, izmantojot Git papla\u0161in\u0101jumu Plesk.<\/p>\n<p>APSkat\u012bsim piem\u0113ru ar Prod vidi aizmugures repozitorijam.<\/p>\n<ol>\n<li>Ieejam m\u016bsu vietnes Helloworld abonement\u0101 un p\u0101rejam uz apak\u0161sada\u013cu Git:\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/b55b371560ea87a2954b6553a7cefc49.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Ievietojam lauk\u0101 \"Remote Git repository\" saiti uz m\u016bsu Github repozitoriju un main\u0101m noklus\u0113juma mapi <code>httpdocs<\/code> uz citu (piem\u0113ram, <code>\/httpdocs\/hw_back<\/code>):\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/db9ba9adb6e2e1bed5da7ae8e88c76e1.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Kop\u0113jam SSH Public key no iepriek\u0161\u0113j\u0101 posma un <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/settings\/ssh\/new\">pievienojam<\/a><\/noindex> to Github iestat\u012bjumos.<\/li>\n<li>Noklik\u0161\u0137in\u0101m uz OK ekr\u0101n\u0101 punkt\u0101 2, p\u0113c tam m\u016bs novirza uz repozitorija lapu Plesk. Tagad mums j\u0101sak\u0101rto repozitorija atjaunin\u0101\u0161ana, ja tiek veikti komandi pie galven\u0101s fili\u0101les. Tam p\u0101rejam uz <i>Repository Settings<\/i> un saglab\u0101jam v\u0113rt\u012bbu <code>Webhook URL<\/code> (tas b\u016bs nepiecie\u0161ams v\u0113l\u0101k, konfigur\u0113jot Github Actions):\n<p><img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/14d48a357f821d734d40dc434ab3682a.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Lauk\u0101 Actions ekr\u0101n\u0101 no iepriek\u0161\u0113j\u0101 punkta ievad\u0101m skriptu izvieto\u0161anai:\n<pre><code class=\"plaintext\">cd {REPOSITORY_ABSOLUTE_PATH}\n.ci-cd\/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID} <\/code><\/pre>\n<p>\nkur: <\/p>\n<p><code>{REPOSITORY_ABSOLUTE_PATH}<\/code> \u2014 ce\u013c\u0161 uz prod aizmugures repozitorija mapi server\u012b;<br \/>\n<code>{ENV}<\/code> \u2014 vide (dev\/prod), m\u016bsu gad\u012bjum\u0101 <code>prod<\/code>;<br \/>\n<code>{DOCKER_REGISTRY_HOST}<\/code> \u2014 m\u016bsu docker repozitorija hosta;<br \/>\n<code>{TG_BOT_TOKEN}<\/code> \u2014 Telegram bota tokens;<br \/>\n<code>{TG_CHAT_ID}<\/code> \u2014 \u010data\/kan\u0101la ID, lai nos\u016bt\u012btu pazi\u0146ojumus.<\/p>\n<p>Skriptu piem\u0113rs:<\/p>\n<pre><code class=\"plaintext\">cd \/var\/www\/vhosts\/helloworld.ru\/httpdocs\/hw_back\/\n.ci-cd\/deploy.sh dev docker.helloworld.ru docker_user docker_password 12345678:AAbcdEfghCH1vGbCasdfSAs0K5PALDsaw -1001234567890<\/code><\/pre>\n<\/li>\n<li>Pievienojam lietot\u0101ju no m\u016bsu abonementa Docker grupai (lai vi\u0146\u0161 var\u0113tu p\u0101rvald\u012bt konteinerus):\n<pre><code class=\"plaintext\">sudo usermod -aG docker helloworld_admin<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>\nIzstr\u0101des vide backend repozitorijam un frontend tiek iestat\u012bta l\u012bdz\u012bgi.<\/p>\n<h2>Palaidnes pipelines Github Actions<\/h2>\n<p>\nP\u0101rejiet uz pirm\u0101s da\u013cas konfigur\u0101ciju m\u016bsu CI\/CD pipeline Github Actions.<\/p>\n<h3>Backend<\/h3>\n<p>\nPipelins tiek aprakst\u012bts <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/blob\/master\/.github\/workflows\/deploy.yml\">fail\u0101 deploy.yml<\/a><\/noindex>. <\/p>\n<p>Bet pirms to izskat\u0101m, aizpild\u012bsim Github nepiecie\u0161am\u0101s Secret main\u012bg\u0101s. Lai to izdar\u012btu, dodamies uz <i>Iestat\u012bjumi -&gt; Slepenie<\/i>:<\/p>\n<ul>\n<li><code>DOCKER_REGISTRY<\/code> \u2014 m\u016bsu Docker repozitorija hosta (docker.helloworld.ru);<\/li>\n<li><code>DOCKER_LOGIN<\/code> \u2014 pieteik\u0161an\u0101s Docker repozitorijam;<\/li>\n<li><code>DOCKER_PASSWORD<\/code> \u2014 parole tam;<\/li>\n<li><code>DEPLOY_HOST<\/code> \u2014 host, kur pieejama Plesk administr\u0101cija (piem\u0113rs: <noindex><a rel=\"nofollow\" href=\"https:\/\/helloworld.ru\">helloworld.ru<\/a><\/noindex>:8443 vai <noindex><a rel=\"nofollow\" href=\"http:\/\/123.4.56.78\">123.4.56.78<\/a><\/noindex>:8443);<\/li>\n<li><code>DEPLOY_BACK_PROD_TOKEN<\/code> \u2014 tokenam produkta repozitorij\u0101 server\u012b (m\u0113s to sa\u0146\u0113m\u0101m sada\u013c\u0101 Izvieto\u0161ana Plesk p. 4);<\/li>\n<li><code>DEPLOY_BACK_DEV_TOKEN<\/code> \u2014 tokenam izstr\u0101des repozitorij\u0101 server\u012b.<\/li>\n<\/ul>\n<p>\nIzvieto\u0161anas process ir vienk\u0101r\u0161s un sast\u0101v no trim galvenajiem so\u013ciem: <\/p>\n<ul>\n<li>att\u0113la b\u016bv\u0113\u0161ana un public\u0113\u0161ana m\u016bsu repozitorij\u0101;<\/li>\n<li>testu palai\u0161ana konteiner\u0101, pamatojoties uz jaunizveidoto att\u0113lu;<\/li>\n<li>izvieto\u0161ana vajadz\u012bgaj\u0101 vid\u0113 atkar\u012bb\u0101 no zara (dev\/master).<\/li>\n<\/ul>\n<p><\/p>\n<h3>Frontend<\/h3>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld-front\/blob\/master\/.github\/workflows\/deploy.yml\">Fails deploy.yml frontend repozitorijam<\/a><\/noindex> mazliet at\u0161\u0137iras no backend. Taj\u0101 nav so\u013ca ar testu palai\u0161anu un tiek main\u012bti tokenu nosaukumi izvieto\u0161anai. Slepenie dati frontend repozitorijam, starp citu, j\u0101aizpilda atsevi\u0161\u0137i.<\/p>\n<h1>M\u0101jaslapas konfigur\u0101cija<\/h1>\n<p><\/p>\n<h2>T\u012bkla trafika p\u0101rs\u016bt\u012b\u0161ana caur Nginx<\/h2>\n<p>\nNu, m\u0113s esam non\u0101ku\u0161i pie beig\u0101m. Atlikusi tikai ien\u0101ko\u0161\u0101 un izejo\u0161\u0101 trafika p\u0101rs\u016bt\u012b\u0161ana m\u016bsu konteiner\u0101 caur Nginx. \u0160o procesu m\u0113s jau apspried\u0101m punkt\u0101 5 Docker Registry konfigur\u0101cij\u0101. To pa\u0161u j\u0101atk\u0101rto backend un frontend da\u013cai izstr\u0101des un produkta vid\u0113s.<\/p>\n<p>Iek\u013cau\u0161u ekr\u0101nuz\u0146\u0113mumus ar iestat\u012bjumiem.<\/p>\n<h3>Backend<\/h3>\n<p>\n<img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/f3c38dc1c25b648db000c72ef2d30b2a.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h3>Frontend<\/h3>\n<p>\n<img decoding=\"async\" alt=\"CI\/CD ar Github Actions Flask+Angular projektam\" src=\"\/wp-content\/uploads\/2020\/06\/35d4d8ef3489608db1e173b7f214ca03.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<strong>Svar\u012bgs preciz\u0113jums<\/strong>. Frontend konteiner\u0101 tiks p\u0101rs\u016bt\u012bti visi URL, iz\u0146emot tos, kas s\u0101kas ar <code>\/api\/<\/code> \u2014 tie tiks p\u0101rs\u016bt\u012bti uz backend konteineru (t\u0101p\u0113c <strong>backend konteiner\u0101 visiem apstr\u0101d\u0101t\u0101jiem j\u0101uzs\u0101k ar <\/strong><strong><code>\/api\/<\/code><\/strong>).<\/p>\n<h2>Secin\u0101jumi<\/h2>\n<p>\nTagad m\u016bsu m\u0101jaslapa j\u0101piek\u013c\u016bst adres\u0113m helloworld.ru un dev.helloworld.ru (atbilsto\u0161i produkta un izstr\u0101des vid\u0113m).<\/p>\n<p>Kopum\u0101 m\u0113s uzzin\u0101j\u0101m, k\u0101 sagatavot vienk\u0101r\u0161u lietojumprogrammu uz Flask un Angular un konfigur\u0113t Github Actions pipeline t\u0101s izvieto\u0161anai server\u012b, kuru p\u0101rvalda Plesk.<\/p>\n<p>Atk\u0101rto\u0161u saites uz repozitorijiem ar kodu: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\">backend<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld-front\">frontend<\/a><\/noindex>.<br \/>\n<br \/>Avots: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/domclick\/blog\/506802\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 CI\/CD \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0430\u043d\u0435\u043b\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f Plesk \u0438 Github Actions. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0431\u0443\u0434\u0435\u043c \u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u043d\u0435\u0437\u0430\u043c\u044b\u0441\u043b\u043e\u0432\u0430\u0442\u044b\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u00abHelloworld\u00bb. \u041e\u043d \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Python-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 Flask, \u0441 \u0432\u043e\u0440\u043a\u0435\u0440\u0430\u043c\u0438 \u043d\u0430 Celery \u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u043e\u043c \u043d\u0430 Angular 8. \u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438: \u0431\u044d\u043a\u0435\u043d\u0434, \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434. \u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":85647,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-85646","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/lv\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"lv_LV\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47CI\/CD \u0432 Github Actions \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 Flask+Angular | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/lv\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-06-17T23:42:15+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-06-17T23:42:15+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47CI\/CD GitHub Actions projektiem uz Flask + Angular | ProHoster","description":"\u0160aj\u0101 rakst\u0101 es dal\u012b\u0161os ar savu pieredzi.","canonical_url":"https:\/\/prohoster.info\/lv\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"lv_LV","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47CI\/CD \u0432 Github Actions \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 Flask+Angular | ProHoster","og:description":"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c.","og:url":"https:\/\/prohoster.info\/lv\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-06-17T23:42:15+00:00","article:modified_time":"2020-06-17T23:42:15+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"85646","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 13:12:50","updated":"2022-09-29 06:56:26","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/posts\/85646","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/comments?post=85646"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/posts\/85646\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/media\/85647"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/media?parent=85646"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/categories?post=85646"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/lv\/wp-json\/wp\/v2\/tags?post=85646"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}