{"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\/et\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular","title":{"rendered":"CI\/CD Github Actions-i jaoks Flask+Angular projektile","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/26d0945a41bbf3c98fa92f15be5b8c6c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSelles artiklis jagan oma kogemusi CI\/CD seadistamisest Plesk'i juhtpaneeli ja Github Actions'i abil. T\u00e4na \u00f5pime, kuidas rakendada lihtsat projekti nimega \"Helloworld\", mis on kirjutatud Python'i raamistiku Flask abil, Celery t\u00f6\u00f6tluse ja Angular 8 esipaneeliga.<\/p>\n<p><b>Aadressid hoidlatele:<\/b> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\">tagaplaan<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld-front\">esine<\/a><\/noindex>.<\/p>\n<p>Artikli esimeses osas vaatame meie projekti ja selle komponente. Teises osas uurime, kuidas seadistada Plesk ja installida vajalikud laiendused ja komponendid (andmebaas, RabbitMQ, Redis, Docker jne).<\/p>\n<p>Kolmandas osas uurime, kuidas seadistada t\u00f6\u00f6protsess meie projekti juurutamiseks serverisse arendus- ja tootmisvahendites. Seej\u00e4rel k\u00e4ivitame veebilehe serveris.<\/p>\n<p>Ja jah, unustasin tutvustada. Minu nimi on Oleg Borzov, olen t\u00e4isvirna arendaja CRM meeskonnas, mis tegeleb kodulaenude halduritega Domklik'is. <br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h1>Projekti \u00fclevaade<\/h1>\n<p>\nAlustame kahe projekti hoidla \u2014 tagumise ja esipaneeli \u2014 uurimisest ja vaatame koodi.<\/p>\n<h2>Tagaplaan: Flask+Celery<\/h2>\n<p>\nTagumise osa jaoks valisin piisavalt populaarse kombinatsiooni Python'i arendajate seas: raamistik Flask (API jaoks) ja Celery (\u00fclesannete j\u00e4rjekorra jaoks). ORM-ina kasutatakse SQLAlchemy't. Migratsioonide jaoks kasutatakse Alembic'ut. JSON-i valideerimiseks manipulatsioonides kasutatakse Marshmallow't.<\/p>\n<p>Uues <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\">hoidlad<\/a><\/noindex> on olemas fail Readme.md, mis sisaldab \u00fcksikasjalikku kirjeldust struktuurist ja projekti k\u00e4ivitamise juhiseid.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/tree\/master\/app_web\">Veebiosa API<\/a><\/noindex> on piisavalt lihtne, koosneb kuuest l\u00f5pp-punktist:<\/p>\n<ul>\n<li><code>\/ping<\/code> \u2014 k\u00e4ttesaadavuse kontrollimiseks;<\/li>\n<li>l\u00f5pp-punktid registreerimiseks, autoriseerimiseks, deauthoriseerimiseks ja autoriseeritud kasutaja saamiseks;<\/li>\n<li>l\u00f5pp-punkt e-kirja saatmiseks, mis lisab \u00fclesande Celery j\u00e4rjekorda.<\/li>\n<\/ul>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/tree\/master\/app_celery\">Celery osa<\/a><\/noindex> on veel lihtsam, seal on ainult \u00fcks \u00fclesanne <code>send_mail_task<\/code>.<\/p>\n<p>Kaustas <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/tree\/master\/conf\/\">\/conf<\/a><\/noindex> on kaks alamkausta: <\/p>\n<ul>\n<li><code>docker<\/code> kahe Docker-failiga (<code>base.dockerfile<\/code> harva muudetava p\u00f5hifoto kogumise jaoks ja <code>Dockerfile<\/code> peamiste kogumite jaoks);<\/li>\n<li><code>.env_files<\/code> \u2014 failide komplektid keskkonnamuutujate jaoks erinevates keskkondades. <\/li>\n<\/ul>\n<p>\nProjekti juures on neli docker-compose faili:<\/p>\n<ul>\n<li><code>docker-compose.local.db.yml<\/code> kohaliku andmebaasi seadistamiseks arenduseks;<\/li>\n<li><code>docker-compose.local.workers.yml<\/code> kohaliku t\u00f6\u00f6tluse, andmebaasi, Redis'i ja RabbitMQ \u00fcles t\u00f5stmiseks;<\/li>\n<li><code>docker-compose.test.yml<\/code> testide l\u00e4biviimiseks paigaldamisel;<\/li>\n<li><code>docker-compose.yml<\/code> juurutamiseks.<\/li>\n<\/ul>\n<p>\nJa viimane huvitav kaust, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/tree\/master\/.ci-cd\">.ci-cd<\/a><\/noindex>Sisaldab \u00fclekande shell-skripte:<\/p>\n<ul>\n<li><code>deploy.sh<\/code> \u2014 migratsioonide ja juurutamise k\u00e4ivitamiseks. K\u00e4ivitatakse serveris p\u00e4rast kogumist ja testide l\u00e4biviimist Github Actions'is;<\/li>\n<li><code>rollback.sh<\/code> \u2014 konteinerite tagasiviimine eelmisse versioon<\/li>\n<li><code>curl_tg.sh<\/code> \u2014 teavituste saatmine Telegrami k\u00e4ivitamise kohta.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Frontend Angularil<\/h2>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld-front\">Frontend'i hoidla<\/a><\/noindex> on m\u00e4rksa lihtsam kui backend. Frontend koosneb kolmest lehek\u00fcljest:<\/p>\n<ul>\n<li>Pealehe, kus on e-posti saatmise vorm ja v\u00e4ljumise nupp.<\/li>\n<li>Sisestamise leht.<\/li>\n<li>Registreerimise leht.<\/li>\n<\/ul>\n<p>\nPealeht on tagasihoidlik:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/4db36add2c4277397724b0d71b96ff06.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJuurdes on kaks faili <code>Dockerfile<\/code> ja <code>docker-compose.yml<\/code>, samuti tuttav kaust <code>.ci-cd<\/code> m\u00f5nev\u00f5rra v\u00e4hem skripte kui backend'i hoidlas (testide k\u00e4ivitamise skriptid on eemaldatud).<\/p>\n<h1>Loome projekti Pleskis<\/h1>\n<p>\nAlustame Pleski seadistamisega ja tellimuse loomisega meie saidile.<\/p>\n<h2>Lisandmoodulite installimine<\/h2>\n<p>\nPleskis vajame nelja lisandmoodulit: <\/p>\n<ul>\n<li><code>Docker<\/code> konteinerite haldamiseks ja nende oleku visuaalseks kuvamiseks Pleski administraatoris;<\/li>\n<li><code>Git<\/code> serveri juurutamise etapi seadistamiseks;<\/li>\n<li><code>Let's Encrypt<\/code> tasuta TLS-sertifikaatide genereerimiseks (ja automaatseks pikendamiseks);<\/li>\n<li><code>Tulekahju<\/code> sissetuleva liikluse filtreerimise seadistamiseks.<\/li>\n<\/ul>\n<p>\nSaame need installida Pleski administraatoris, vaates Extensions:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/350cf7d7ca3ae1a965a0d3f8a73594ef.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDetailset seadistust me ei k\u00e4sitle, meie demoteks sobivad vaikes\u00e4tet.<\/p>\n<h2>Tellimuse ja saidi loomine<\/h2>\n<p>\nSeej\u00e4rel peame looma tellimuse meie saidile helloworld.ru ja lisama sinna alldomeeni dev.helloworld.ru.<\/p>\n<ol>\n<li>Loome tellimuse domeenile helloworld.ru ja m\u00e4\u00e4rame s\u00fcsteemi kasutaja sisselogimise ja parooli:\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/3932dc7492aa523b6cbd540ad7a7fe6b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLehe allosas paneme linnukese <i>Kaitse domeen Let&#8217;s Encryptiga<\/i>, kui soovime seadistada saidile HTTPS:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/f4d23a34764fdeb411fe2ca9cc95cb45.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Seej\u00e4rel loome selles tellimuses alldomeeni dev.helloworld.ru (millele saab samuti v\u00e4lja anda tasuta TLS-sertifikaadi):\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/d57e6ba71454cb537917400de4275e92.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ol>\n<p><\/p>\n<h1>Serverikomponentide installimine<\/h1>\n<p>\nMeil on olemas server, millel <i>OS Debian Stretch 9.12<\/i> ja paigaldatud juhtimispaneel <i>Plesk Obsidian 18.0.27<\/i>.<\/p>\n<p>Peame installima ja seadistama oma projekti jaoks:<\/p>\n<ul>\n<li>PostgreSQL (meie puhul on \u00fcks server kahe andmebaasiga dev- ja prod-keskkondade jaoks).<\/li>\n<li>RabbitMQ (sama, \u00fcks instants erinevate vhost'idega keskkondade jaoks).<\/li>\n<li>Kaks Redis'i instantsi (dev- ja prod-keskkondade jaoks).<\/li>\n<li>Docker Registry (kogutud Docker-piltide kohaliku salvestamise jaoks).<\/li>\n<li>Docker registry UI-liides.<\/li>\n<\/ul>\n<p><\/p>\n<h2>PostgreSQL<\/h2>\n<p>\nPleskiga kaasneb juba PostgreSQL andmebaas, kuid mitte k\u00f5ige uuema versiooniga (artikli kirjutamise ajal toetas Plesk Obsidian <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.plesk.com\/release-notes\/obsidian\/software-requirements\/\">Postgres versioone 8.4\u201310.8). Me soovime oma rakendusele k\u00f5ige v\u00e4rskemat versiooni (12.3 artikli kirjutamise ajal), seega paigaldame selle k\u00e4sitsi.<\/a><\/noindex> Postgres versioonid 8.4\u201310.8). Meie soovime oma rakendusele k\u00f5ige uuemat versiooni (12.3 artikli kirjutamise ajal), seega installime selle k\u00e4sitsi.<\/p>\n<p>Interneti on palju \u00fcksikasjalikke juhiseid Postgresi installimiseks Debianile (<noindex><a rel=\"nofollow\" href=\"https:\/\/tecadmin.net\/install-postgresql-on-debian-9-stretch\/\">n\u00e4ide<\/a><\/noindex>), seega ei hakka ma neid \u00fcksikasjalikult kirjeldama, lihtsalt toon v\u00e4lja k\u00e4sud:<\/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>\nArvestades, et PostgreSQL-i vaikeseaded on piisavalt keskp\u00e4rased, tuleb konfiguratsiooni kindlasti kohandada. Sellega aitab meid <noindex><a rel=\"nofollow\" href=\"http:\/\/pgconfigurator.cybertec.at\/\">kalkulaator<\/a><\/noindex>: peate sisestama oma serveri parameetrid ja muutma seadeid failis <code>\/etc\/postgresql\/12\/main\/postgresql.conf<\/code>pakutud v\u00e4\u00e4rtustega. Siinkohal tasub m\u00e4rkida, et sellised kalkulaatorid ei ole maagilised lahendused ning andmebaasi tuleks t\u00e4psemalt h\u00e4\u00e4lestada, l\u00e4htudes teie riistvarast, rakendusest ja p\u00e4ringute keerukusest. Kuid selleks, et alustada, on see piisav.<\/p>\n<p>Lisaks kalkulaatori pakutud seadetele muudame <code>postgresql.conf<\/code>vaikimisi pordi 5432 teiseks (meie n\u00e4ites \u2014 <strong>53983<\/strong>).<\/p>\n<p>P\u00e4rast konfiguratsioonifaili muutmist taask\u00e4ivitame postgresql-serveri k\u00e4suga:<\/p>\n<pre><code class=\"bash\">service postgresql restart\n<\/code><\/pre>\n<p>\nOleme installinud ja seadistanud PostgreSQL-i. N\u00fc\u00fcd loome andmebaasid, kasutajad dev- ja prod-keskkondade jaoks ning anname kasutajatele \u00f5igused andmebaaside haldamiseks:<\/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>\nLiigume RabbitMQ installimise juurde \u2014 s\u00f5numite edastaja Celery jaoks. Seda on Debianile piisavalt lihtne installida:<\/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\u00e4rast installimist peame looma <i>vhosts<\/i>, kasutajad ja andma vajalikud \u00f5igused:<\/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>\nN\u00fc\u00fcd installime ja seadistame meie rakenduse viimase koostisosade \u2014 Redis. Seda kasutatakse bakenina Celery \u00fclesannete tulemuste salvestamiseks.<\/p>\n<p>Me t\u00f5stame kaks Docker-konteinerit Redis \u00fcles dev- ja prod-keskkondade jaoks laienduse abil <code>Docker<\/code> Pleskile.<\/p>\n<ol>\n<li>Siseneme Pleski, l\u00e4heme laienduste jaotisse, otsime Docker laiendust ja installime selle (me vajame tasuta versiooni):\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/5638f9b40274e4f7441434279c76a426.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>L\u00e4heme installitud laiendusse, leiame pildi otsingu kaudu <code>redis bitnami<\/code> ja paigaldame viimase versiooni:\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/578bbbed6a66a60a4f7410f7d61ea542.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Siseneme alla laaditud konteinerisse ja kohandame konfiguratsiooni: m\u00e4\u00e4rame pordi, maksimaalse eraldatud RAM-i suuruse, parooli keskkonnamuutujates ja montime mahu:\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/8bc804b794735412f5e510b3049c5667.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Kordame samme 2-3 prod-konteineri jaoks, muutes ainult seadistusi: port, parool, RAM-i suurus ja faili tee serveris:\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" 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>\nLisaks p\u00f5hiteenustele oleks tore serverisse paigaldada oma Docker-piltide repositoorium. T\u00e4nap\u00e4eval on serverites koht piisavalt odav (kindlasti odavam kui DockerHub'i tellimus) ja privaatse repositooriumi paigaldamine on v\u00e4ga lihtne. <\/p>\n<p>Me tahame, et meil oleks installitud:<\/p>\n<ul>\n<li>parooliga kaitstud Docker-repositoorium, millele p\u00e4\u00e4seb juurde alamdomeeni kaudu <noindex><a rel=\"nofollow\" href=\"https:\/\/docker.helloworld.ru\">https:\/\/docker.helloworld.ru<\/a><\/noindex>;<\/li>\n<li>Kasutajaliides piltide vaatamiseks repositooriumis, saadaval aadressil <noindex><a rel=\"nofollow\" href=\"https:\/\/docker-ui.helloworld.ru\">https:\/\/docker-ui.helloworld.ru<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>\nSelleks:<\/p>\n<ol>\n<li>Loome Pleskis kaks alamdomeeni meie tellimuses: docker.helloworld.ru ja docker-ui.helloworld.ru, ning seadistame nende jaoks Let\u2019s Encrypt sertifikaadid.<\/li>\n<li>Alamdomeeni docker.helloworld.ru kausta lisame faili <code>docker-compose.yml<\/code> sellise sisuga:\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>SSH kaudu genereerime faili .htpasswd Docker-repositooriumi Basic-autoriseerimise jaoks:\n<pre><code class=\"plaintext\">htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password<\/code><\/pre>\n<\/li>\n<li>Kogume ja t\u00f5stame konteinerid \u00fcles:\n<pre><code class=\"plaintext\">Vaatame lihtsat n\u00e4idet.<\/code><\/pre>\n<\/li>\n<li>Ja peame suunama Nginxi meie konteineritele. Seda saab teha Pleski kaudu. <\/li>\n<\/ol>\n<p>\nJ\u00e4rgmiseks tuleb teostada j\u00e4rgmised toimingud alamdomeenidel docker.helloworld.ru ja docker-ui.helloworld.ru:<\/p>\n<p>Jaotises <i>Dev Tools<\/i> siseneme meie saidile <i>Docker Proxy Rules<\/i>:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/d9c05901d95d61ce5db27a1a7cfddf49.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJa lisame reegli sissetuleva liikluse suunamiseks meie konteinerisse:<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/faa85cf6da648ef55b7c87c44040efb1.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<ol>\n<li>Kontrollime, et saaksime oma konteinerisse autentida kohalikust masinast:\n<pre><code class=\"plaintext\">$ docker login docker.helloworld.ru -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>Samuti kontrollime alamdomeeni docker-ui.helloworld.ru t\u00f6\u00f6d.\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/fdd6e1396c27c02a88bcbd7efb12f247.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nKui vajutate nuppu Browse repositories, avab brauser autentimise akna, kuhu tuleb sisestada kasutajanimi ja parool repole. P\u00e4rast seda suunatakse meid repo nimekirja lehele (praegu on see t\u00fchi):<\/p>\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/f2d75edb530e9d746095ae02d7793c1f.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ol>\n<p><\/p>\n<h2>Avame pordid Plesk Firewallis.<\/h2>\n<p>\nP\u00e4rast komponentide installimist ja seadistamist peame avama pordid, et need oleksid Docker-konteineritest ja v\u00e4lisest v\u00f5rgust ligip\u00e4\u00e4setavad.<\/p>\n<p>Vaadakem, kuidas seda teha, v\u00f5ttes n\u00e4iteks varem installitud Firewall laiendust Pleskile.<\/p>\n<ol>\n<li>Liigume <i>Tools &amp; Settings &gt; Settings &gt; Firewall<\/i>:<br \/>\n<img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/d54b4941944fe191574472a475cbaebe.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Liigume <i>Muuda Plesk Firewall reegleid &gt; Lisa kohandatud reegel<\/i> ja avame j\u00e4rgmised TCP-pordid Docker alams\u00fcsteemi jaoks (<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 Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/3359845f9bd6dc303274da737d4b27a2.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Lisame ka reegli, mis avab v\u00e4list maailma PostgreSQL ja RabbitMQ haldust\u00f6\u00f6riistaribade pordid:\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/f812cfc7127da469507538ea48b2c80d.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Rakendame reeglid nuppu Apply Changes abi.\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/e85444ae717aaefa796664003fc86578.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ol>\n<p><\/p>\n<h1>CI\/CD seadistamine Github Actionsis<\/h1>\n<p>\nAlustame k\u00f5ige huvitavama osaga \u2014 meie projekti pideva integreerimise ja kohaletoimetamise toru seadistamisega serverisse.<\/p>\n<p>See toru koosneb kahest osast: <\/p>\n<ul>\n<li>pildi koostamine ja testide l\u00e4biviimine (tagapinnal) \u2014 Githubis;<\/li>\n<li>r\u00e4nde k\u00e4itamine (tagapinnal) ja konteinerite deploy \u2014 serveris.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Deploy Pleskis<\/h2>\n<p>\nHakkame esmalt tegelema teise punktiga (sest see s\u00f5ltub esimesest).<\/p>\n<p>Seadistame deploy Protsessi Pleski Git laienduse abil.<\/p>\n<p>Vaatame n\u00e4idet Prod keskkonna kohta tagapinna repole.<\/p>\n<ol>\n<li>Logime sisse meie saidi Helloworld tellimusse ja liigume Git alasperesse:\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/b55b371560ea87a2954b6553a7cefc49.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Kopeerime v\u00e4ljal \"Remote Git repository\" link meie Github repository ja muutame vaikimisi kausta <code>httpdocs<\/code> teiseks (n\u00e4iteks, <code>\/httpdocs\/hw_back<\/code>):\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/db9ba9adb6e2e1bed5da7ae8e88c76e1.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Kopeerime SSH avaliku v\u00f5tme eelmisest etapist ja <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/settings\/ssh\/new\">lisame<\/a><\/noindex> selle Githubi seadetes.<\/li>\n<li>Klikkame OK ekraanil punktis 2, seej\u00e4rel suunatakse meid Pleski repo lehele. N\u00fc\u00fcd peame seadistama repo uuendamise, kui teeme master haru commite. Selleks liigume <i>Repository Settings<\/i> ja salvestame v\u00e4\u00e4rtuse <code>Webhook URL<\/code> (me vajame seda hiljem Github Actionsi seadistamisel):\n<p><img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/14d48a357f821d734d40dc434ab3682a.png\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<li>Eelneva ekraani Actions v\u00e4ljal sisestame skripti deploy k\u00e4ivitamiseks:\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>\nkus: <\/p>\n<p><code>{REPOSITORY_ABSOLUTE_PATH}<\/code> \u2014 tee prod tagapinna repo kausta serveris;<br \/>\n<code>{ENV}<\/code> \u2014 keskkond (dev\/prod), meie puhul <code>prod<\/code>;<br \/>\n<code>{DOCKER_REGISTRY_HOST}<\/code> \u2014 meie docker repo host<br \/>\n<code>{TG_BOT_TOKEN}<\/code> \u2014 Telegrami boti token;<br \/>\n<code>{TG_CHAT_ID}<\/code> \u2014 Chat\/channel ID for sending notifications.<\/p>\n<p>Script example:<\/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>Adding a user from our subscription to the Docker group (so they can manage containers):\n<pre><code class=\"plaintext\">sudo usermod -aG docker helloworld_admin<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>\nThe development environment for the backend repository and frontend is configured similarly.<\/p>\n<h2>Deployment pipeline in Github Actions<\/h2>\n<p>\nWe proceed to configure the first part of our CI\/CD pipeline in Github Actions.<\/p>\n<h3>Backend<\/h3>\n<p>\nThe pipeline is described in <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\/blob\/master\/.github\/workflows\/deploy.yml\">the deploy.yml file<\/a><\/noindex>. <\/p>\n<p>But before we examine it, let's fill in the necessary Secret variables in Github. For that, go to <i>Settings -&gt; Secrets<\/i>:<\/p>\n<ul>\n<li><code>DOCKER_REGISTRY<\/code> \u2014 the host of our Docker repository (docker.helloworld.ru);<\/li>\n<li><code>DOCKER_LOGIN<\/code> \u2014 login to the Docker repository;<\/li>\n<li><code>DOCKER_PASSWORD<\/code> \u2014 password for it;<\/li>\n<li><code>DEPLOY_HOST<\/code> \u2014 the host where the Plesk admin panel is accessible (example: <noindex><a rel=\"nofollow\" href=\"https:\/\/helloworld.ru\">helloworld.ru<\/a><\/noindex>:8443 or <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 token for deployment to the prod repository on the server (we obtained it in Deployment in Plesk p. 4);<\/li>\n<li><code>DEPLOY_BACK_DEV_TOKEN<\/code> \u2014 token for deployment to the dev repository on the server.<\/li>\n<\/ul>\n<p>\nThe deployment process is simple and consists of three main steps: <\/p>\n<ul>\n<li>building and publishing the image in our repository;<\/li>\n<li>running tests in a container based on the freshly built image;<\/li>\n<li>deployment to the desired environment depending on the branch (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\">The deploy.yml file for the frontend repository<\/a><\/noindex> does not differ much from the backend one. It lacks the step to run tests and changes the names of the tokens for deployment. Secrets for the frontend repository, by the way, need to be filled in separately.<\/p>\n<h1>Site Configuration<\/h1>\n<p><\/p>\n<h2>Traffic proxying through Nginx<\/h2>\n<p>\nWell, we have reached the end. We just need to configure the proxying of incoming and outgoing traffic to our container via Nginx. We already covered this process in step 5 of Docker Registry setup. The same needs to be repeated for the backend and frontend parts in dev and prod environments.<\/p>\n<p>I will provide screenshots of the settings.<\/p>\n<h3>Backend<\/h3>\n<p>\n<img decoding=\"async\" alt=\"CI\/CD Github Actions-i jaoks Flask+Angular projektile\" 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 Github Actions-i jaoks Flask+Angular projektile\" src=\"\/wp-content\/uploads\/2020\/06\/35d4d8ef3489608db1e173b7f214ca03.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<strong>Important clarification<\/strong>. All URLs except those starting with will be proxied to the frontend container, <code>\/api\/<\/code> \u2014 they will be proxied to the backend container (therefore, <strong>in the backend container, all handlers must start with <\/strong><strong><code>\/api\/<\/code><\/strong>).<\/p>\n<h2>Summary<\/h2>\n<p>\nNow our site should be accessible at helloworld.ru and dev.helloworld.ru (prod and dev environments respectively).<\/p>\n<p>In summary, we learned how to prepare a simple application using Flask and Angular, and set up a pipeline in Github Actions for its deployment to a server managed by Plesk.<\/p>\n<p>I will duplicate the links to the repositories with the code: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld_back\">tagaplaan<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/olegborzov\/helloworld-front\">esine<\/a><\/noindex>.<br \/>\n<br \/>Allikas: <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.1.1 - 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\/et\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"et_EE\" \/>\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\/et\/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 Githubi toimingutes Flask+Angular projekti jaoks | ProHoster","description":"Selles artiklis jagan oma kogemust.","canonical_url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/ci-cd-v-github-actions-dlya-proekta-na-flask-angular","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","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\/et\/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\/et\/wp-json\/wp\/v2\/posts\/85646","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=85646"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/85646\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media\/85647"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=85646"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=85646"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=85646"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}