{"id":36754,"date":"2019-10-31T22:13:37","date_gmt":"2019-10-31T19:13:37","guid":{"rendered":"https:\/\/prohoster.info\/blog\/werf-nash-instrument-dlya-ci-cd-v-kubernetes-obzor-i-video-doklada\/"},"modified":"2019-10-31T22:13:37","modified_gmt":"2019-10-31T19:13:37","slug":"werf-nash-instrument-dlya-ci-cd-v-kubernetes-obzor-i-video-doklada","status":"publish","type":"post","link":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/werf-nash-instrument-dlya-ci-cd-v-kubernetes-obzor-i-video-doklada","title":{"rendered":"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>27. svibnja u glavnoj dvorani konferencije DevOpsConf 2019, koja se odr\u017eava u okviru festivala <noindex><a rel=\"nofollow\" href=\"http:\/\/ritfest.ru\/2019\/\">RIT++ 2019<\/a><\/noindex>, u okviru sekcije \u201eNeprestana isporuka\u201c, odr\u017eano je predavanje \u201ewerf \u2014 na\u0161 alat za CI\/CD u Kubernetesu\u201c. U njemu se govori o <b>problemima i izazovima s kojima se svi susre\u0107u prilikom implementacije u Kubernetes<\/b>, kao i o nijansama koje mo\u017eda nisu odmah vidljive. Razmatraju\u0107i mogu\u0107e puteve rje\u0161enja, prikazujemo kako je to ostvareno u Open Source alatu <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf\">werf<\/a><\/noindex>.<\/p>\n<p>Od trenutka prikazivanja, na\u0161 alat (ranije poznat kao dapp) pre\u0161ao je povijesnu granicu od <b>1000 zvijezda na GitHubu<\/b> \u2014 nadamo se da \u0107e rastu\u0107a zajednica korisnika olak\u0161ati \u017eivot mnogim DevOps in\u017eenjerima.<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/c2d1ad5133c0de944b60ae37e3dbe598.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDakle, predstavljamo <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=cK3ackGUTLw\"><b>video s predavanja<\/b><\/a><\/noindex> (~47 minuta, puno informativnije od \u010dlanka) i glavnu sa\u017eetak iz njega u tekstualnom obliku. Po\u010dnimo!<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Isporuka koda u Kubernetes<\/h2>\n<p>\nTema predavanja \u0107e biti vi\u0161e ne o werfu, ve\u0107 o CI\/CD u Kubernetesu, podrazumijevaju\u0107i da je na\u0161 softver upakovan u Docker kontejnere <i>(o tome sam govorio u <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/322686\/\">predavanju iz 2016. godine<\/a><\/noindex>)<\/i>, a K8s \u0107e se koristiti za pokretanje u produkciji <i>(o tome \u2014 u <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/331188\/\">2017. godini<\/a><\/noindex>)<\/i>.<\/p>\n<p>Kako izgleda isporuka u Kubernetes?<\/p>\n<ul>\n<li> Postoji Git repozitorij s kodom i uputama za izradu. Aplikacija se gradi u Docker slici i objavljuje u Docker Registry.<\/li>\n<li> U istom repozitoriju postoje i upute o tome kako implementirati i pokrenuti aplikaciju. U fazi implementacije, ove upute se \u0161alju u Kubernetes, koji preuzima potrebnu sliku iz registry i pokre\u0107e je.<\/li>\n<li> Osim toga, obi\u010dno postoje i testovi. Neki od njih se mogu izvr\u0161iti prilikom objavljivanja slike. Tako\u0111er, mo\u017ee se (po istim uputama) rasporediti kopija aplikacije (u zasebnom prostoru imena K8s ili zasebnom klasteru) i izvr\u0161avati testove tamo.<\/li>\n<li> Na kraju, potreban nam je CI sustav koji prima doga\u0111aje iz Gita (ili pritiske tipki) i poziva sve ozna\u010dene faze: build, publish, deploy, test.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/ec0d1fd1bf1a68cca92badf7cf1affe1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEvo nekoliko va\u017enih napomena:<\/p>\n<ol>\n<li> Budu\u0107i da imamo nepromjenjivu infrastrukturu <i>(immutable infrastructure)<\/i>, slika aplikacije koja se koristi u svim fazama (staging, produkcija itd.) <b>mora biti jedna<\/b>. <i>Vi\u0161e o tome i s primjerima sam govorio <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/324274\/\">ovdje<\/a><\/noindex>.<\/i><\/li>\n<li> Budu\u0107i da pratimo pristup infrastruktura kao kod <i>(IaC)<\/i>, kod aplikacije, upute za njegovu izradu i pokretanje trebaju biti <b>upravo u jednom repozitoriju<\/b>. <i>Vi\u0161e o tome \u2014 pogledajte u <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/324274\/\">tome istom predavanju<\/a><\/noindex>.<\/i><\/li>\n<li> Lanac isporuke <i>(delivery)<\/i> obi\u010dno vidimo ovako: aplikacija je izgra\u0111ena, testirana, objavljena <i>(faza release)<\/i> i to je to \u2014 isporuka je izvr\u0161ena. No u stvarnosti korisnik dobiva ono \u0161to ste objavili, <b>ne<\/b> kada ste to isporu\u010dili u proizvodnju, a kada je mogao pristupiti toj proizvodnji i kada je ta proizvodnja radila. Stoga smatram da lanac isporuke zavr\u0161ava <b>samo na fazi eksploatacije<\/b> <i>(run)<\/i>, a ako \u017eelimo biti precizniji, \u010dak i u trenutku kada je kod uklonjen iz proizvodnje (zamjenom novim).<\/li>\n<\/ol>\n<p>\nVratimo se na gore navedenu shemu isporuke u Kubernetesu: izmislili su je ne samo mi, ve\u0107 doslovno svatko tko se bavio tim problemom. U osnovi, ovaj obrazac sada nazivamo GitOps <i>(vi\u0161e o pojmu i idejama koje stoje iza njega mo\u017eete pro\u010ditati <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/458878\/\">ovdje<\/a><\/noindex>)<\/i>. Pogledajmo faze sheme.<\/p>\n<h2>Faza izgradnje (build)<\/h2>\n<p>\nNaizgled, \u0161to se mo\u017ee re\u0107i 2019. godine o izgradnji Docker slika, kada svi znaju pisati Dockerfile-ove i pokretati <code>docker build<\/code>?.. \u0412\u043e\u0442 \u043d\u044e\u0430\u043d\u0441\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435:<\/p>\n<ol>\n<li> <b>Veli\u010dina slike<\/b> ima zna\u010daj, stoga koristite <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/develop\/develop-images\/multistage-build\/\">multi-stage<\/a><\/noindex>, kako biste u slici ostavili samo ono \u0161to je zaista potrebno za rad aplikacije.<\/li>\n<li> <b>Broj slojeva<\/b> treba minimizirati spajanjem nizova od <code>POCNI<\/code>-komandi po zna\u010denju.<\/li>\n<li> Me\u0111utim, to dodaje probleme <b>debuggiranju<\/b>, budu\u0107i da prilikom pada izgradnje trebate prona\u0107i onu pravu komandu iz lanca koja je uzrokovala problem.<\/li>\n<li> <b>Brzina izgradnje<\/b> je va\u017ena, jer \u017eelimo brzo implementirati promjene i gledati rezultate. Na primjer, ne \u017eelimo ponovo graditi ovisnosti u bibliotekama jezika pri svakom buildanju aplikacije.<\/li>\n<li> \u010cesto se iz jednog Git repozitorija zahtijeva <b>vi\u0161e slika<\/b>, \u0161to se mo\u017ee rije\u0161iti skupom Dockerfile-ova (ili imenovanim fazama u jednoj datoteci) i Bash skriptom koja ih sekvencijalno sastavlja.<\/li>\n<\/ol>\n<p>\nOvo je samo vrh sante leda s kojim se svi suo\u010davaju. No postoje i drugi problemi, izme\u0111u ostalog:<\/p>\n<ol>\n<li> \u010cesto tokom izgradnje trebamo ne\u0161to <b>montirati<\/b> (na primjer, ke\u0161irati rezultat naredbe poput apt-a u vanjsku direktoriju).<\/li>\n<li> \u017delimo <b>Ansible<\/b> umjesto da pi\u0161emo na shell-u.<\/li>\n<li> \u017delimo <b>graditi bez Dockera<\/b> (za\u0161to nam treba dodatna virtualna ma\u0161ina u kojoj treba sve za to postaviti, kada ve\u0107 postoji Kubernetes klaster u kojem se mogu pokretati kontejneri?).<\/li>\n<li> <b>Paralelno graditi<\/b>, koji se mo\u017ee tuma\u010diti na razli\u010dite na\u010dine: razli\u010dite naredbe iz Dockerfile-a (ako se koristi multi-stage), nekoliko commit-a jednog repozitorija, nekoliko Dockerfile-ova.<\/li>\n<li> <b>Distribuirana izgradnja<\/b>: \u017eelimo sastavljati ne\u0161to u podovima koji su 'efemerni', jer im se ke\u0161 gubi, stoga se mora pohranjivati negdje odvojeno.<\/li>\n<li> Na kraju, vrh \u017eelja sam nazvao <b>automagijom<\/b>: bilo bi idealno u\u0107i u repozitorij, upisati neku naredbu i dobiti gotovu sliku, sastavljenu s razumijevanjem kako i \u0161to pravilno u\u010diniti. Ipak, osobno nisam siguran da se svi detalji mogu tako predvidjeti.<\/li>\n<\/ol>\n<p>\nI evo projekata:<\/p>\n<ul>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/moby\/buildkit\">moby\/buildkit<\/a><\/noindex> \u2014 graditelj tvrtke Docker Inc (ve\u0107 integriran u aktualne verzije Dockera), koja poku\u0161ava rije\u0161iti sve te probleme;<\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/GoogleContainerTools\/kaniko\">kaniko<\/a><\/noindex> \u2014 graditelj iz Googlea, koji omogu\u0107uje sastavljanje bez Dockera;<\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/buildpacks.io\/\">Buildpacks.io<\/a><\/noindex> \u2014 poku\u0161aj CNCF-a da napravi automagiju i, izme\u0111u ostalog, zanimljivo rje\u0161enje s rebaseom za slojeve;<\/li>\n<li> i jo\u0161 mno\u0161tvo drugih alata, kao \u0161to su <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/containers\/buildah\">buildah<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/genuinetools\/img\">genuinetools\/img<\/a><\/noindex>\u2026<\/li>\n<\/ul>\n<p>\n\u2026 i pogledajte koliko imaju zvjezdica na GitHubu. Dakle, s jedne strane, <code>docker build<\/code> ima i mo\u017ee ne\u0161to u\u010diniti, ali u stvarnosti <b>pitanje nije do kraja rije\u0161eno<\/b> \u2014 dokaz tome je paralelni razvoj alternativnih graditelja, od kojih svaki rje\u0161ava neki dio problema.<\/p>\n<h2>Gradnja u werfu<\/h2>\n<p>\nTako smo do\u0161li do <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf\">werf<\/a><\/noindex> <i>(ranije <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/333682\/\">poznatoj<\/a><\/noindex> kao dapp)<\/i> \u2014 Open Source alat tvrtke 'Flant', koji razvijamo ve\u0107 mnogo godina. Sve je po\u010delo prije 5 godina s Bash skriptama koje su optimizirale izgradnju Dockerfile-ova, a posljednje 3 godine se vodi potpuna razvojna aktivnost unutar jednog projekta s vlastitim Git repozitorijem <i>(isprva na Ruby-ju, a potom <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/437044\/\">prepisali<\/a><\/noindex> na Go, a usput i preimenovali)<\/i>. Koje su probleme sastavljanja rije\u0161ili u werfu?<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/ab6aa8831b49977a419fd4cc3543eb83.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nProblemi obojeni plavom su ve\u0107 realizirani, paralelno sastavljanje je napravljeno unutar jednog hosta, a pitanja ozna\u010dena \u017eutom planiramo dovr\u0161iti do kraja ljeta.<\/p>\n<h2>Faza objavljivanja u registru (publish)<\/h2>\n<p>\nPrikupili smo <code>docker push<\/code>\u2026 \u2014 \u0161to bi moglo biti te\u0161ko u tome da se slika u\u010dita u registar? I ovdje se javlja pitanje: \"Koju oznaku staviti slici?\" Ono nastaje zbog toga \u0161to imamo <b>Gitflow<\/b> (ili druga strategija Gita) i Kubernetes, a industrija te\u017ei tome da se ono \u0161to se doga\u0111a u Kubernetesu uskladi s onim \u0161to se radi u Gitu. Jer Git je na\u0161 jedini izvor istine.<\/p>\n<p>\u0160to je u tome te\u0161ko? <b>Jam\u010diti reproducibilnost<\/b>: od commit-a u Gitu, koji po svojoj prirodi ostaje nepromijenjen <i>(immutable)<\/i>, do Docker slike koja se mora \u010duvati istom.<\/p>\n<p>Nama je tako\u0111er va\u017eno <b>utvrditi podrijetlo<\/b>, jer \u017eelimo razumjeti iz kojeg commit-a je aplikacija pokrenuta u Kubernetesu (tada \u0107emo mo\u0107i raditi diff-ove i sli\u010dne stvari).<\/p>\n<h3>Strategije ozna\u010davanja<\/h3>\n<p>\nPrva \u2014 jednostavna <b>git tag<\/b>. Imamo registry s slikom, ozna\u010denom kao <code>1.0<\/code>. U Kubernetesu imamo stage i production, gdje je ta slika preuzeta. U Git-u radimo commit-e i u nekom trenutku postavljamo oznaku <code>2.0<\/code>. Gra\u0111ujemo je prema uputama iz repozitorija i stavljamo u registry s oznakom <code>2.0<\/code>. Implementiramo na stage, a ako je sve uredu, onda na production.<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/8545b84bfa63a91773f0d7dc1c2bd49f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nProblem ovog pristupa je \u0161to prvo postavljamo oznaku, a tek onda testiramo i objavljujemo. Za\u0161to? Prvo, to je jednostavno nelogi\u010dno: izdajemo verziju softvera koji jo\u0161 nismo provjerili (ne mo\u017eemo druga\u010dije, jer da bismo provjerili, trebamo postaviti oznaku). Drugo, takav put se ne sla\u017ee s Gitflow.<\/p>\n<p>Druga opcija \u2014 <b>git commit + tag<\/b>. U master grani postoji oznaka <code>1.0<\/code>; za nju u registry je slika, implementirana na production. Osim toga, u Kubernetes klasteru postoje konture preview i staging. Dalje slijedimo Gitflow: u glavnoj grani za razvoj (<code>develop<\/code>) radimo nove zna\u010dajke, uslijed \u010dega nastaje commit s identifikatorom <code>#c1<\/code>. Gra\u0111ujemo ga i objavljujemo u registry, koriste\u0107i taj identifikator (<code>#c1<\/code>). S istim identifikatorom implementiramo na preview. Sli\u010dno \u010dinimo s commit-ima <code>#c2<\/code> i <code>#c3<\/code>.<\/p>\n<p>Kada shvatimo da je zna\u010dajki dovoljno, po\u010dinjemo sve stabilizirati. U Git-u kreiramo granu <code>release_1.1<\/code> (na osnovi <code>#c3<\/code> iz <code>develop<\/code>). Gra\u0111enje ovog izdanja ne\u0107e biti potrebno, jer je to ve\u0107 u\u010dinjeno u prethodnoj fazi. Stoga ga mo\u017eemo jednostavno implementirati na staging. Ispravljamo gre\u0161ke u <code>#c4<\/code> i sli\u010dno objavljujemo na staging. Paralelno se u isto vrijeme odvija razvoj u <code>develop<\/code>, kamo povremeno preuzimamo promjene iz <code>release_1.1<\/code>. U nekom trenutku dobivamo dignuti i objavljen commit na staging-u, s kojim smo zadovoljni (<code>#c25<\/code>).<\/p>\n<p>Tada radimo merge (s fast-forward-om) izdanja grane (<code>release_1.1<\/code>) u master. Stavljamo oznaku na ovaj commit s novom verzijom (<code>1.1<\/code>). No, ova slika je ve\u0107 sakupljena u registry, tako da, kako ne bismo opet sakupljali, jednostavno dodajemo drugu oznaku na postoje\u0107u sliku (sada ima oznake <code>#c25<\/code> i <code>1.1<\/code>). Nakon toga implementiramo ga na production.<\/p>\n<p>Postoji nedostatak, \u0161to je na staging-u implementirana jedna slika (<code>#c25<\/code>), a na production-u \u2014 kao da je druga (<code>1.1<\/code>), ali znamo da je 'fizi\u010dki' to ista slika iz registry.<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/b3fa2c34442aa401d1e7b30eb593be9a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMe\u0111utim, pravi nedostatak je \u0161to nema podr\u0161ke za merge commit-ove, treba raditi fast-forward.<\/p>\n<p>Mo\u017eemo i\u0107i dalje i napraviti trik... Razmotrimo primjer jednostavnog Dockerfile-a:<\/p>\n<pre><code class=\"plaintext\">FROM ruby:2.3 as assets\nRUN mkdir -p \/app\nWORKDIR \/app\nCOPY . .\/\nRUN gem install bundler &amp;&amp; bundle install\nRUN bundle exec rake assets:precompile\nCMD bundle exec puma -C config\/puma.rb\n\nFROM nginx:alpine\nCOPY --from=assets \/app\/public \/usr\/share\/nginx\/www\/public<\/code><\/pre>\n<p>\nIzgradimo datoteku prema na\u010delu da \u0107emo uzeti:<\/p>\n<ul>\n<li> SHA256 od identifikatora kori\u0161tenih slika (<code>ruby:2.3<\/code> i <code>nginx:alpine<\/code>), koji predstavljaju kontrolne sume njihovog sadr\u017eaja;<\/li>\n<li> sve naredbe (<code>POCNI<\/code>, <code>CMD<\/code> itd.);<\/li>\n<li> SHA256 od datoteka koje su dodane.<\/li>\n<\/ul>\n<p>\n... i uzet \u0107emo kontrolnu sumu (ponovno SHA256) od takve datoteke. To je <b>potpis<\/b> svega \u0161to definira sadr\u017eaj Docker slike.<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/b2af0b7952eefe26ddbb145955e778e8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nVratimo se shemi i <b>umjesto commit-a koristit \u0107emo takve potpise<\/b>, tj. ozna\u010davati slike potpisima.<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/115f290bd5951614c041b3d510fae38e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSada, kada bude potrebno, na primjer, merge-ati promjene iz izdanja u master, mo\u017eemo napraviti pravi merge commit: imat \u0107e drugi identifikator, ali istu potpis. S tim istim identifikatorom izvadi\u0107emo sliku i na produkciji.<\/p>\n<p>Nedostatak je u tome \u0161to sada ne mo\u017eemo odrediti koji je commit izvu\u010den na produkciju - kontrolne sume rade samo u jednom smjeru. Ovaj problem rje\u0161ava dodatni sloj s metapodacima - vi\u0161e \u0107u detaljno objasniti kasnije.<\/p>\n<h3>Ozna\u010davanje u werfu<\/h3>\n<p>\nU werfu smo oti\u0161li jo\u0161 dalje i pripremamo raspodijeljenu izgradnju s cache-om koji se ne pohranjuje na jednoj ma\u0161ini... Dakle, sastavljamo Docker slike dvaju tipova, nazivamo ih <i>) - jedinica organizacije pipeline-a, sadr\u017ei 1+ zadatak,<\/i> i <i>image<\/i>.<\/p>\n<p>U Git repozitoriju werf pohranjene su specifi\u010dne upute za izgradnju, koje opisuju razli\u010dite faze izgradnje (<i>beforeInstall<\/i>, <i>install<\/i>, <i>beforeSetup<\/i>, <i>setup<\/i>). Prvu stage sliku sastavljamo s potpisom, koji je definiran kao kontrolna suma prvih koraka. Zatim dodajemo izvorni kod, za novu stage sliku ra\u010dunamo njenu kontrolnu sumu... Ove operacije se ponavljaju za sve faze, kao rezultat \u010dega dobivamo set od stage slika. Zatim radimo kona\u010dnu image sliku, koja tako\u0111er sadr\u017ei metapodatke o njenom porijeklu. I tu sliku ozna\u010davamo na razli\u010dite na\u010dine (vi\u0161e detalja kasnije).<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/22df8b6347b45be19ecb889c102b92b5.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNeka nakon toga nastane nova promjena, u kojoj je izmijenjen samo kod aplikacije. \u0160to \u0107e se dogoditi? Za promjene koda bit \u0107e stvoren zakrpa, pripremljen nova stage slika. Njegova potpis bit \u0107e odre\u0111ena kao kontrolna suma stare stage slike i nove zakrpe. Iz te slike bit \u0107e formirana nova finalna slika.<\/p>\n<p>Dakle, stage slike \u2014 ke\u0161 koji se mo\u017ee pohranjivati distribuirano, a slike koje se iz njega stvaraju se u\u010ditavaju u Docker Registry.<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/35805eca81605bd64c6910b7965b567e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>\u010ci\u0161\u0107enje registra<\/h3>\n<p>\nRije\u010d nije o brisanju slojeva koji su ostali visi nakon obrisanih oznaka \u2014 to je standardna mogu\u0107nost samog Docker Registry. Rije\u010d je o situaciji kada se nakuplja mno\u0161tvo Docker oznaka i shva\u0107amo da nam neki od njih vi\u0161e nisu potrebni, a zauzimaju prostor (i\/ili za njega pla\u0107amo).<\/p>\n<p>Koje postoje strategije \u010di\u0161\u0107enja?<\/p>\n<ol>\n<li> Mo\u017eete jednostavno ni\u0161ta <b>ne \u010distiti<\/b>. Ponekad je zaista lak\u0161e malo platiti za dodatni prostor nego odmotati ogroman klupko oznaka. No, to funkcionira samo do odre\u0111enog trenutka.<\/li>\n<li> <b>Potpuni reset<\/b>. Ako izbri\u0161ete sve slike i ponovo sastavite samo aktualne u CI sustavu, mo\u017ee se pojaviti problem. Ako se na produkciji ponovno pokrene kontejner, za njega \u0107e se u\u010ditati nova slika \u2014 tako da jo\u0161 nikada nije testirana. To ubija ideju nepromjenjive infrastrukture.<\/li>\n<li> <b>Plava-zelena<\/b>. Jedan registry je po\u010deo prepunjavati \u2014 u\u010ditavamo slike u drugi. Ista problema kao u prethodnom na\u010dinu: kada mo\u017eemo o\u010distiti taj registry koji je po\u010deo prepunjavati?<\/li>\n<li> <b>Po vremenu<\/b>. Izbrisati sve slike starije od 1 mjeseca? No, sigurno \u0107e se na\u0107i usluga koja nije a\u017eurirana cijeli mjesec...<\/li>\n<li> <b>Ru\u010dni<\/b> utvr\u0111ivati \u0161to se ve\u0107 mo\u017ee brisati.<\/li>\n<\/ol>\n<p>\nPostoje dvije stvarno odr\u017eive mogu\u0107nosti: ne \u010distiti ili kombinacija plavi-zelena + ru\u010dno. U potonjem slu\u010daju, kada shvatite da je vrijeme za \u010di\u0161\u0107enje registrija, kreirate novu i dodajete sve nove slike u nju tijekom, na primjer, mjesec dana. A nakon mjesec dana pogledate koje pod-ove u Kubernetesu jo\u0161 uvijek koriste stari registrij i tako\u0111er ih prebacite u novi registrij.<\/p>\n<p>K \u010demu smo do\u0161li u <b>werf<\/b>? \u041c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c:<\/p>\n<ol>\n<li> Git head: sve oznake, sve grane \u2014 pretpostavljaju\u0107i da je sve \u0161to je ozna\u010deno u Gitu potrebno i u slikama (a ako nije, treba to ukloniti u samom Gitu);<\/li>\n<li> svi podovi koji su trenutno preuzeti u Kubernetesu;<\/li>\n<li> stari ReplicaSet-ovi (ono \u0161to je nedavno preuzeto), kao i planiramo skenirati Helm-releases i odabrati najnovije slike tamo.<\/li>\n<\/ol>\n<p>\n\u2026 i od ovog skupa kreiramo whitelist \u2014 popis slika koje ne\u0107emo brisati. Sve ostalo \u010distimo, nakon \u010dega pronalazimo siro\u010de stage-slike i bri\u0161emo ih tako\u0111er.<\/p>\n<h2>Faza implementacije (deploy)<\/h2>\n<p><\/p>\n<h3>Pouzdana deklarativnost<\/h3>\n<p>\nPrva stvar na koju bih skrenuo pa\u017enju u implementaciji je izdavanje a\u017eurirane konfiguracije resursa, koja je deklarativno objavljena. Izvorni YAML-dokument s opisom Kubernetes resursa \u010desto se zna\u010dajno razlikuje od rezultata koji stvarno radi u klasteru. To se doga\u0111a jer Kubernetes dodaje u konfiguraciju:<\/p>\n<ol>\n<li> identifikatore;<\/li>\n<li> administrativne informacije;<\/li>\n<li> mnogo zadatih vrijednosti;<\/li>\n<li> odjeljak s trenutnim statusom;<\/li>\n<li> promjene u\u010dinjene tijekom rada admission webhook-a;<\/li>\n<li> rezultat rada razli\u010ditih kontrolera (i planera).<\/li>\n<\/ol>\n<p>\nStoga, kada se pojavi nova konfiguracija resursa (<i>new<\/i>), ne mo\u017eemo jednostavno zamijeniti trenutnu, \u201e\u017eivu\u201c konfiguraciju (<i>live<\/i>). Zato \u0107emo morati usporediti <i>new<\/i> s prethodno primijenjenom konfiguracijom (<i>last-applied<\/i>) i primijeniti <i>live<\/i> dobiveni patch.<\/p>\n<p>Ovaj pristup se naziva <b>2-way merge<\/b>. Koristi se, primjerice, u Helm-u.<\/p>\n<p>Postoji i <b>3-way merge<\/b>, koji se razlikuje po tome \u0161to:<\/p>\n<ul>\n<li> uspore\u0111uju\u0107i <i>last-applied<\/i> i <i>new<\/i>, gledamo \u0161to je uklonjeno;<\/li>\n<li> uspore\u0111uju\u0107i <i>new<\/i> i <i>live<\/i>, gledamo \u0161to je dodano ili promijenjeno;<\/li>\n<li> zbrojeni patch primjenjujemo na <i>live<\/i>.<\/li>\n<\/ul>\n<p>\nDeplojujemo vi\u0161e od 1000 aplikacija s Helmom, zbog \u010dega zapravo \u017eivimo s 2-way merge. Me\u0111utim, postoji niz problema koje smo rije\u0161ili svojim zakrpama, poma\u017eu\u0107i Helmu da normalno radi.<\/p>\n<h3>Stvarni status implementacije<\/h3>\n<p>\nNakon \u0161to je zbog doga\u0111aja na\u0161a CI-sustav generirao novu konfiguraciju za Kubernetes, ona ju \u0161alje na primjenu <i>(apply)<\/i> u klaster \u2014 pomo\u0107u Helm-a ili <code>kubectl apply<\/code>. Potom se odvija ve\u0107 opisani N-way merge, na \u0161to Kubernetes API odobrava CI sustavu, a on korisniku.<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/fcc8251525f32c913f30fbcdc4296198.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMe\u0111utim, postoji veliki problem: uspje\u0161na primjena ne zna\u010di uspje\u0161nu implementaciju. <b>Ako je Kubernetes shvatio koje promjene treba primijeniti, primjenjuje ih \u2014 jo\u0161 ne znamo kakav \u0107e biti rezultat. Na primjer, a\u017euriranje i ponovo pokretanje pod-ova na frontend-u mo\u017ee pro\u0107i uspje\u0161no, dok na backend-u \u2014 ne, i dobit \u0107emo razli\u010dite verzije pokrenutih slika aplikacije.<\/b>. Ako Kubernetes razumije koja su a\u017euriranja potrebno primijeniti, primijenit \u0107e ih \u2014 jo\u0161 uvijek ne znamo \u0161to \u0107e rezultirati. Na primjer, a\u017euriranje i ponovno pokretanje podova u frontend-u mo\u017ee pro\u0107i uspje\u0161no, dok u backend-u mo\u017eda ne\u0107e, i dobit \u0107emo razli\u010dite verzije pokrenutih slika aplikacije.<\/p>\n<p>Da bismo sve radili ispravno, u ovoj shemi name\u0107e se dodatna jedinica \u2014 poseban traker koji \u0107e primati informacije o statusu putem Kubernetes API-a i prenositi ih za dalju analizu stvarnog stanja. Stvorili smo Open Source biblioteku na Go \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/kubedog\"><b>kubedog<\/b><\/a><\/noindex> <i>(vidi njen najavu <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/434160\/\">ovdje<\/a><\/noindex>)<\/i>, \u2014 koja re\u0161ava ovaj problem i integrisana je u werf.<\/p>\n<p>Pona\u0161anje ovog trakera na nivou werf pode\u0161ava se pomo\u0107u anotacija koje se postavljaju na Deploymente ili StatefulSets. Glavna anotacija \u2014 <code>fail-mode<\/code> \u2014 razume slede\u0107e vrednosti:<\/p>\n<ul>\n<li> <code>IgnoreAndContinueDeployProcess<\/code> \u2014 ignori\u0161emo probleme u vezi sa implementacijom ovog dela i nastavljamo proces implementacije;<\/li>\n<li> <code>FailWholeDeployProcessImmediately<\/code> \u2014 gre\u0161ka u ovom delu zaustavlja proces implementacije;<\/li>\n<li> <code>HopeUntilEndOfDeployProcess<\/code> \u2014 nadamo se da \u0107e ovaj deo raditi do kraja implementacije.<\/li>\n<\/ul>\n<p>\nNa primer, kombinacija resursa i vrednosti anotacije <code>fail-mode<\/code>:<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/40e161710e8a535cd95f1eb66ca8407b.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKada prvi put deplojujemo, baza podataka (MongoDB) mo\u017eda jo\u0161 nije spremna \u2014 Deployments \u0107e pasti. No, mo\u017eemo pri\u010dekati trenutak da se pokrene, i deploy \u0107e i dalje pro\u0107i.<\/p>\n<p>Postoje jo\u0161 dve anotacije za kubedog u werf:<\/p>\n<ul>\n<li> <code>failures-allowed-per-replica<\/code> \u2014 broj dozvoljenih padova za svaku replikaciju;<\/li>\n<li> <code>show-logs-until<\/code> \u2014 regulira trenutak do kojeg werf prikazuje (u stdout) logove iz svih izbacivanih podova. Po defaultu, to je <code>PodIsReady<\/code> (kako bismo ignorisali poruke koje nam verovatno nisu potrebne kada pod po\u010dne primati saobra\u0107aj), ali su tako\u0111e prihvatljive vrednosti <code>ControllerIsReady<\/code> i <code>EndOfDeploy<\/code>.<\/li>\n<\/ul>\n<p><\/p>\n<h3>\u0160ta jo\u0161 \u017eelimo od implementacije?<\/h3>\n<p>\nPored ve\u0107 opisana dva aspekta, \u017eeleli bismo:<\/p>\n<ul>\n<li> videti <b>logove<\/b> \u2014 ali samo potrebne, a ne sve nasumi\u010dno;<\/li>\n<li> pratiti <b>napredak<\/b>, jer ako se job \"tiho\" zadr\u017ei nekoliko minuta, va\u017eno je razumeti \u0161ta se doga\u0111a;<\/li>\n<li> imati <b>automatizovani rollback<\/b> u slu\u010daju da ne\u0161to po\u0111e po zlu (stoga je klju\u010dno znati stvarni status implementacije). Implementacija bi trebala biti atomska: ili prolazi do kraja, ili se sve vra\u0107a na prethodno stanje.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Zaklju\u010dci<\/h2>\n<p>\nNama kao kompaniji za realizaciju svih ovih nijansi na razli\u010ditim fazama isporuke (build, publish, deploy) dovoljna je CI sistem i alat <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf\">werf<\/a><\/noindex>.<\/p>\n<p>Umesto zaklju\u010dka:<\/p>\n<p><img decoding=\"async\" alt=\"werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacija)\" src=\"\/wp-content\/uploads\/2019\/08\/bafba54f2df8740a1a12c93b3476e49a.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUz pomo\u0107 werf-a postigli smo zna\u010dajan napredak u re\u0161avanju mnogih problema DevOps in\u017eenjera i bi\u0107e nam drago ako \u0161ira zajednica isproba ovaj alat u praksi. Postizanje dobrog rezultata zajedno bi\u0107e lak\u0161e.<\/p>\n<h2>Video i slajdovi<\/h2>\n<p>\nVideo sa nastupa (~47 minuta):<\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"cK3ackGUTLw\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/cK3ackGUTLw\/hqdefault.jpg\" alt=\"Pogledajte video\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><\/p>\n<p>Prezentacija izlaganja:<\/p>\n<p><center><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"\/\/speakerdeck.com\/player\/2033277984c04900b18940588edf1161\" frameborder=\"0\" allowfullscreen><\/iframe><\/center><\/p>\n<h2>P.S.<\/h2>\n<p>\nDruge objave o Kubernetesu na na\u0161em blogu:<\/p>\n<ul>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/459326\/\">Automatsko skaliranje i upravljanje resursima u Kubernetesu<\/a><\/noindex>\u00bb <i>(Dmitrij Stoljjarov; 27. travnja 2019. na \u201eStakli\u010dnoj\u201d)<\/i>;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/449096\/\">Pro\u0161irujemo i dodatno oboga\u0107ujemo Kubernetes<\/a><\/noindex>\u00bb <i>(Andrej Polovov; 8. travnja 2019. na Saint HighLoad++)<\/i>;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">Baze podataka i Kubernetes<\/a><\/noindex>\u00bb <i>(Dmitrij Stoljjarov; 8. studenog 2018. na HighLoad++)<\/i>;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/412901\/\">Pra\u0107enje i Kubernetes<\/a><\/noindex>\u00bb <i>(Dmitrij Stolyarov; 28. svibnja 2018. na RootConf)<\/i>;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/345116\/\">Najbolje prakse CI\/CD s Kubernetesom i GitLabom<\/a><\/noindex>\u00bb <i>(Dmitrij Stolyarov; 7. studenog 2017. na HighLoad++)<\/i>;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/331188\/\">Na\u0161e iskustvo s Kubernetesom u manjim projektima<\/a><\/noindex>\u00bb <i>(Dmitrij Stolyarov; 6. lipnja 2017. na RootConf)<\/i>.<\/li>\n<\/ul>\n<p>Izvor: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/460351\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>27 \u043c\u0430\u044f \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u0437\u0430\u043b\u0435 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 DevOpsConf 2019, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0444\u0435\u0441\u0442\u0438\u0432\u0430\u043b\u044f \u0420\u0418\u0422++ 2019, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0435\u043a\u0446\u0438\u0438 \u00ab\u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0430\u00bb, \u043f\u0440\u043e\u0437\u0432\u0443\u0447\u0430\u043b \u0434\u043e\u043a\u043b\u0430\u0434 \u00abwerf \u2014 \u043d\u0430\u0448 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f CI\/CD \u0432 Kubernetes\u00bb. \u0412 \u043d\u0451\u043c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e \u0442\u0435\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0445 \u0438 \u0432\u044b\u0437\u043e\u0432\u0430\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u0440\u0438 \u0434\u0435\u043f\u043b\u043e\u0435 \u0432 Kubernetes, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e \u043d\u044e\u0430\u043d\u0441\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043c\u0435\u0442\u043d\u044b \u043d\u0435 \u0441\u0440\u0430\u0437\u0443. [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":27531,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-36754","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=\"27 \u043c\u0430\u044f \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u0437\u0430\u043b\u0435 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 DevOpsConf 2019, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0444\u0435\u0441\u0442\u0438\u0432\u0430\u043b\u044f \u0420\u0418\u0422++ 2019, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0435\u043a\u0446\u0438\u0438 \u00ab\u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0430\u00bb, \u043f\u0440\u043e\u0437\u0432\u0443\u0447\u0430\u043b.\" \/>\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\/hr\/blog\/administrirovanie\/werf-nash-instrument-dlya-ci-cd-v-kubernetes-obzor-i-video-doklada\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"hr_HR\" \/>\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\udd47werf \u2014 \u043d\u0430\u0448 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f CI\/CD \u0432 Kubernetes (\u043e\u0431\u0437\u043e\u0440 \u0438 \u0432\u0438\u0434\u0435\u043e \u0434\u043e\u043a\u043b\u0430\u0434\u0430) | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"27 \u043c\u0430\u044f \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u0437\u0430\u043b\u0435 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 DevOpsConf 2019, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0444\u0435\u0441\u0442\u0438\u0432\u0430\u043b\u044f \u0420\u0418\u0422++ 2019, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0435\u043a\u0446\u0438\u0438 \u00ab\u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0430\u00bb, \u043f\u0440\u043e\u0437\u0432\u0443\u0447\u0430\u043b.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/werf-nash-instrument-dlya-ci-cd-v-kubernetes-obzor-i-video-doklada\" \/>\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=\"2019-10-31T19:13:37+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:13:37+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\udd47werf \u2014 na\u0161 alat za CI\/CD u Kubernetesu (pregled i video prezentacije) | ProHoster","description":"27. svibnja u glavnoj dvorani konferencije DevOpsConf 2019, koja se odr\u017eava u sklopu festivala RIT++ 2019, u okviru sekcije \u201eKontinuirana isporuka\u201d, izre\u010deno je.","canonical_url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/werf-nash-instrument-dlya-ci-cd-v-kubernetes-obzor-i-video-doklada","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hr_HR","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\udd47werf \u2014 \u043d\u0430\u0448 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f CI\/CD \u0432 Kubernetes (\u043e\u0431\u0437\u043e\u0440 \u0438 \u0432\u0438\u0434\u0435\u043e \u0434\u043e\u043a\u043b\u0430\u0434\u0430) | ProHoster","og:description":"27 \u043c\u0430\u044f \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u0437\u0430\u043b\u0435 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 DevOpsConf 2019, \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0444\u0435\u0441\u0442\u0438\u0432\u0430\u043b\u044f \u0420\u0418\u0422++ 2019, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0435\u043a\u0446\u0438\u0438 \u00ab\u041d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0430\u00bb, \u043f\u0440\u043e\u0437\u0432\u0443\u0447\u0430\u043b.","og:url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/werf-nash-instrument-dlya-ci-cd-v-kubernetes-obzor-i-video-doklada","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":"2019-10-31T19:13:37+00:00","article:modified_time":"2019-10-31T19:13:37+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"36754","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":"2026-01-22 04:44:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:39:23","updated":"2026-01-22 04:44:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/36754","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/comments?post=36754"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/36754\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media\/27531"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media?parent=36754"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/categories?post=36754"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/tags?post=36754"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}