{"id":32526,"date":"2019-10-31T21:47:32","date_gmt":"2019-10-31T18:47:32","guid":{"rendered":"https:\/\/prohoster.info\/blog\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci\/"},"modified":"2019-10-31T21:47:32","modified_gmt":"2019-10-31T18:47:32","slug":"protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci","status":"publish","type":"post","link":"https:\/\/prohoster.info\/no\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci","title":{"rendered":"Utviklings- og testprosess med Docker og Gitlab CI","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Eg tilbyr ei oversikt over utgreiinga av rapporten fr\u00e5 Aleksandr Sigachev fr\u00e5 Inventos \u00abUtviklings- og testprosess med Docker + Gitlab CI\u00bb<\/strong><\/p>\n<p><\/p>\n<p>De som nettopp begynner \u00e5 implementere utviklings- og testprosessen basert p\u00e5 Docker + Gitlab CI har ofte grunnleggende sp\u00f8rsm\u00e5l. Hvor skal man begynne? Hvordan organisere? Hvordan teste?<\/p>\n<p><\/p>\n<p>Denne rapporten er god fordi den systematisk forklarer utviklings- og testprosessen ved bruk av Docker og Gitlab CI. Selve rapporten er fra 2017. Jeg tror man kan hente ut grunnleggende prinsipper, metodologi, ideer og erfaring fra denne rapporten. <\/p>\n<p>\n<center><div class=\"youtube-placeholder\" data-id=\"lJsqRwULRVA\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/lJsqRwULRVA\/hqdefault.jpg\" alt=\"Spill 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>De som er interessert, vennligst klikk her. <noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><\/p>\n<p>Jeg heter Alexander Sigachev. Jeg jobber i selskapet Inventos. Jeg vil fortelle om min erfaring med \u00e5 bruke Docker og hvordan vi gradvis implementerer det i prosjektene v\u00e5re.<\/p>\n<p><\/p>\n<p>Temaet for rapporten: Utviklingsprosess med bruk av Docker og Gitlab CI. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/e30c4757e4bda1bcc3e20b16e8e2709e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dette er min andre rapport om Docker. P\u00e5 tidspunktet for den f\u00f8rste rapporten brukte vi Docker kun i utviklingsmilj\u00f8ene til utviklerne. Antallet ansatte som brukte Docker var rundt 2-3 personer. Erfaring har blitt opparbeidet gradvis, og vi har gjort noen fremskritt. Lenke til v\u00e5r <noindex><a rel=\"nofollow\" href=\"https:\/\/www.slideshare.net\/gled\/docker-development-70411088\">f\u00f8rste rapport<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Hva vil vi dekke i denne rapporten? Vi vil dele erfaringer om hvilke problemer vi har st\u00f8tt p\u00e5 og hvordan vi l\u00f8ste dem. Det var ikke alltid pent, men det tillot oss \u00e5 komme videre.<\/p>\n<p><\/p>\n<p>V\u00e5rt motto: dockeriser alt vi kommer i kontakt med.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/25ae4f97f1c502384abfe697bac502b1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvilke problemer l\u00f8ser vi?<\/p>\n<p><\/p>\n<p>N\u00e5r det er flere team i selskapet, er programmereren en delt ressurs. Det kan v\u00e6re faser der programmereren blir hentet fra ett prosjekt og midlertidig flyttet til et annet prosjekt.<\/p>\n<p><\/p>\n<p>For at programmereren raskt skal sette seg inn i prosjektet, m\u00e5 han laste ned koden og f\u00e5 opp et milj\u00f8 s\u00e5 raskt som mulig som lar ham fortsette med \u00e5 l\u00f8se oppgavene i dette prosjektet.<\/p>\n<p><\/p>\n<p>Vanligvis, hvis man starter fra bunnen av, er dokumentasjonen i prosjektet sparsom. Informasjon om hvordan man konfigurerer, finnes kun hos de erfarne. Ansatte setter vanligvis opp arbeidsplassen sin p\u00e5 en til to dager. For \u00e5 akselerere dette har vi brukt Docker.<\/p>\n<p><\/p>\n<p>Den neste grunnen er standardisering av innstillinger i Development. Etter min erfaring viser utviklere alltid initiativ. I hvert femte tilfelle blir det introdusert et egendefinert domene, for eksempel vasya.dev. Ved siden av sitter naboen Petja, som har domenet petya.dev. De utvikler et nettsted eller en del av systemet ved \u00e5 bruke dette domenet.<\/p>\n<p><\/p>\n<p>N\u00e5r systemet vokser og disse domenene begynner \u00e5 komme inn i konfigurasjonene, oppst\u00e5r det konflikt i Development-milj\u00f8ene, og nettstedets bane blir overskrevet.<\/p>\n<p><\/p>\n<p>Det samme skjer med databasinnstillingene. Noen tenker ikke p\u00e5 sikkerhet og jobber med et tomt root-passord. Noen ganger krever MySQL-passordet under installasjonen et passord, og det blir et enkelt 123. Det skjer ofte at databasekonfigurasjonen stadig blir endret avhengig av utviklerens commit. Noen korrigerer, noen glemmer \u00e5 rette opp konfigurasjonen. Det var underlige l\u00f8sninger der vi flyttet en testkonfigurasjon til <code>.gitignore<\/code> og hver utvikler m\u00e5tte installere databasen. Dette kompliserte oppstartsprosessen. I tillegg til alt annet, m\u00e5 man huske p\u00e5 databasen. Databasen m\u00e5 initialiseres, man m\u00e5 oppgi passord, oppgi bruker, opprette en tabell og s\u00e5 videre.<\/p>\n<p><\/p>\n<p>Et annet problem er forskjellige versjoner av biblioteker. Det skjer ofte at utviklerne jobber med forskjellige prosjekter. Det er et Legacy-prosjekt som ble startet for fem \u00e5r siden (fra 2017 \u2014 red. anm.). Ved starten ble det startet med MySQL 5.5. Det finnes ogs\u00e5 moderne prosjekter, der vi pr\u00f8ver \u00e5 implementere mer moderne versjoner av MySQL, for eksempel 5.7 eller eldre (i 2017 \u2014 red. anm.)<\/p>\n<p><\/p>\n<p>De som jobber med MySQL vet at disse bibliotekene drar med seg avhengigheter. Det er ganske problematisk \u00e5 kj\u00f8re 2 databaser sammen. I hvert fall er det problematisk \u00e5 koble gamle kunder til en ny database. Dette f\u00f8rer i sin tur til flere problemer.<\/p>\n<p><\/p>\n<p>Det neste problemet er n\u00e5r utvikleren jobber p\u00e5 en lokal maskin, bruker lokale ressurser, lokale filer, lokal RAM. All interaksjon under utviklingen av l\u00f8sningen skjer innenfor rammen av at det fungerer p\u00e5 \u00e9n maskin. Et eksempel kan v\u00e6re n\u00e5r vi har 3 backend-servere i produksjon, og utvikleren lagrer filer i rotkatalogen, og derfra henter nginx filer for \u00e5 svare p\u00e5 anrop. N\u00e5r slik kode g\u00e5r i produksjon, viser det seg at filen finnes p\u00e5 en av de 3 serverne.<\/p>\n<p><\/p>\n<p>N\u00e5 utvikles feltet mikroservices. N\u00e5r vi deler v\u00e5re store applikasjoner inn i mindre komponenter som interagerer med hverandre. Dette lar oss velge teknologier i henhold til spesifikke oppgaver. Det gj\u00f8r det ogs\u00e5 mulig \u00e5 dele arbeidet og ansvarsomr\u00e5dene mellom utviklerne.<\/p>\n<p><\/p>\n<p>Frontend-utvikleren, ved \u00e5 utvikle p\u00e5 JS, p\u00e5virker praktisk talt ikke backend. Backend-utvikleren, i v\u00e5rt tilfelle, utvikler Ruby on Rails og forstyrrer ikke frontend. Interaksjonen skjer ved hjelp av API.<\/p>\n<p><\/p>\n<p>Som en bonus har vi med Docker klart \u00e5 utnytte ressursene p\u00e5 Staging. Hvert prosjekt krever sine spesifikke innstillinger p\u00e5 grunn av sin natur. Fysisk m\u00e5tte vi tildele enten \u00e9n virtuell server og konfigurere dem separat, eller dele et variabelt milj\u00f8, og prosjektene kunne, avhengig av versjonen av bibliotekene, p\u00e5virke hverandre.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/fa5c99f90faef84a356d4791fd915830.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Verkt\u00f8y. Hva bruker vi? <\/p>\n<p><\/p>\n<ul>\n<li>Selve Docker. I Dockerfile beskrives avhengighetene til \u00e9n applikasjon. <\/li>\n<li>Docker-compose er koblingen som forener flere av v\u00e5re Docker-applikasjoner.<\/li>\n<li>Vi bruker GitLab for \u00e5 lagre kildekoden.<\/li>\n<li>Vi bruker GitLab-CI for systemintegrasjon.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/b6041827a6ba928e0d33add6b79c581c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Foredraget best\u00e5r av to deler.<\/p>\n<p><\/p>\n<p>Den f\u00f8rste delen vil fortelle om hvordan vi kj\u00f8rte Docker p\u00e5 utviklermaskinene.<\/p>\n<p><\/p>\n<p>Den andre delen vil fortelle om hvordan vi interagerer med GitLab, hvordan vi kj\u00f8rer tester og hvordan vi distribuerer til Staging.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/45746d3323d35e0d18f066c8bfcb2214.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Docker er en teknologi som gj\u00f8r det mulig (ved hjelp av en deklarativ tiln\u00e6rming) \u00e5 beskrive n\u00f8dvendige komponenter. Dette er et eksempel p\u00e5 Dockerfile. Her erkl\u00e6rer vi at vi arver fra det offisielle Docker-bildet Ruby:2.3.0. Det inneholder installert Ruby versjon 2.3. Vi installerer n\u00f8dvendige build-biblioteker og NodeJS. Vi beskriver at vi oppretter en katalog. <code>\/app<\/code>. Vi setter mappen app som arbeidskatalog. I denne mappen legger vi den n\u00f8dvendige minimale Gemfile og Gemfile.lock. Deretter bygger vi prosjektene som installerer dette bildet med avhengigheter. Vi spesifiserer at containeren vil v\u00e6re klar til \u00e5 lytte p\u00e5 ekstern port 3000. Den siste kommandoen er den som starter applikasjonen v\u00e5r direkte. Hvis vi kj\u00f8rer prosjektets oppstartskommando, vil applikasjonen pr\u00f8ve \u00e5 kj\u00f8re og starte den angitte kommandoen.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/ba503c305ae90f49b39f4ae2cbda1668.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dette er et minimalt eksempel p\u00e5 en docker-compose-fil. I dette tilfellet viser vi at to containere oppretter forbindelse. Dette er direkte til databasetjenesten og webtjenesten. V\u00e5re webapplikasjoner krever i de fleste tilfeller en database som backend for lagring av data. Siden vi bruker MySQL, er eksemplet med MySQL \u2014 men ingenting forhindrer oss fra \u00e5 bruke en annen database (PostgreSQL, Redis).<\/p>\n<p><\/p>\n<p>Vi tar bildet MySQL 5.7.14 fra den offisielle kilden p\u00e5 Docker hub uten endringer. Bildet som h\u00e5ndterer v\u00e5r webapplikasjon, bygger vi fra n\u00e5v\u00e6rende katalog. Ved f\u00f8rste oppstart bygger det bildet for oss. Deretter kj\u00f8rer det kommandoen vi utf\u00f8rer her. Hvis vi g\u00e5r tilbake, vil vi se at oppstartskommanden er definert gjennom Puma. Puma er en tjeneste skrevet i Ruby. I det andre tilfellet overstyrer vi. Denne kommandoen kan v\u00e6re vilk\u00e5rlig avhengig av v\u00e5re behov eller oppgaver.<\/p>\n<p><\/p>\n<p>Vi beskriver ogs\u00e5 at vi m\u00e5 videresende porten p\u00e5 utviklerens vertsmaskin fra 3000 til containerens port 3000. Dette utf\u00f8res automatisk ved hjelp av iptables og sin egen mekanisme som er innebygd i Docker. <\/p>\n<p><\/p>\n<p>Utvikleren kan ogs\u00e5, som f\u00f8r, henvende seg til hvilken som helst tilgjengelig IP-adresse, for eksempel den lokale 127.0.0.1 eller den eksterne IP-adressen til maskinen.<\/p>\n<p><\/p>\n<p>Den siste linjen sier at containeren web er avhengig av containeren db. N\u00e5r vi kaller oppstarten av containeren web, vil docker-compose f\u00f8rst starte databasen. Allerede ved oppstarten av databasen (faktisk \u2014 etter oppstarten av containeren! Klareringen av databasen er ikke garantert) vil applikasjonen v\u00e5r, v\u00e5r backend, starte.<\/p>\n<p><\/p>\n<p>Dette gj\u00f8r at vi unng\u00e5r feil n\u00e5r databasen ikke er oppe, og sparer ressurser n\u00e5r vi stopper databasen, som dermed frigj\u00f8r ressursene til andre prosjekter. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/4acbcf5de89b98db055e8abc419202de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hva gir oss bruken av dockerisering av databasen i prosjektet? Vi fester MySQL-versjonen for alle utviklere. Dette gj\u00f8r at vi unng\u00e5r noen feil som kan oppst\u00e5 ved konfigurasjonsforskjeller n\u00e5r syntaks, innstillinger og standardinnstillinger endres. Dette lar oss spesifisere felles hostname for databasen, login og passord. Vi tar avstand fra det kaotiske navnesystemet og konfliktene i konfigurasjonsfilene som eksisterte tidligere. <\/p>\n<p><\/p>\n<p>Vi har muligheten til \u00e5 bruke en mer optimal konfigurasjon for utviklingsmilj\u00f8et, som vil v\u00e6re forskjellig fra standardinnstillingen. MySQL er som standard konfigurert for svake maskiner, og ytelsen er sv\u00e6rt lav rett ut av boksen.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/417d77a06b18e2df9b71440c0f2a1653.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Docker lar oss bruke den n\u00f8dvendige versjonen av Python, Ruby, NodeJS og PHP. Vi slipper \u00e5 bruke en versjonsh\u00e5ndterer. Tidligere brukte vi rpm-pakker for Ruby som tillot oss \u00e5 endre versjon avhengig av prosjekt. Dette gj\u00f8r at vi, takket v\u00e6re Docker-containeren, jevnt kan migrere koden og versjonere den sammen med avhengighetene. Vi har ingen problemer med \u00e5 forst\u00e5 versjonen av b\u00e5de tolken og koden. For \u00e5 oppdatere versjonen, m\u00e5 vi senke den gamle containeren og heve den nye containeren. Hvis noe g\u00e5r galt, kan vi senke den nye containeren og heve den gamle.<\/p>\n<p><\/p>\n<p>Etter byggingen av bildet vil containerne b\u00e5de i utviklings- og produksjonsmilj\u00f8 v\u00e6re identiske. Dette er spesielt aktuelt for store installasjoner.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/185a1bfe257f7e3e0eecdc6e0e0d330f.jpg\" style=\"display:block;margin: 0 auto;\" \/> P\u00e5 frontend bruker vi JavaScript og NodeJS.<\/p>\n<p><\/p>\n<p>N\u00e5 har vi v\u00e5rt siste prosjekt p\u00e5 ReactJS. Utvikleren kj\u00f8rte alle containerne og utviklet med hot-reload.<\/p>\n<p><\/p>\n<p>Deretter kj\u00f8res en oppgave for \u00e5 bygge JavaScript, og koden som er bygd i statisk form, leveres gjennom nginx for \u00e5 spare ressurser.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/4c2e28319d56d7fc81845b4133a1bfe6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Her har jeg vist diagrammet over v\u00e5rt siste prosjekt.<\/p>\n<p><\/p>\n<p>Hvilke oppgaver har vi l\u00f8st? Vi hadde behov for \u00e5 bygge et system som kommuniserer med mobile enheter. De mottar data. En av mulighetene er \u00e5 sende push-varsler til disse enhetene. <\/p>\n<p><\/p>\n<p>Hva gjorde vi for dette?<\/p>\n<p><\/p>\n<p>Vi delte opp applikasjonen i komponenter som: admin-delen i JS, backend som kj\u00f8rer via REST-grensesnittet under Ruby on Rails. Backend samhandler med databasen. Resultatet som genereres, leveres til klienten. Adminpanelet samhandler med backend og databasen via REST-grensesnitt.<\/p>\n<p><\/p>\n<p>Vi hadde ogs\u00e5 behov for \u00e5 sende Push-varsler. F\u00f8r dette hadde vi et prosjekt hvor vi implementerte en mekanisme som h\u00e5ndterer levering av varsler til mobile plattformer. <\/p>\n<p><\/p>\n<p>Vi utviklet et slikt skjema: operat\u00f8ren fra nettleseren interagerer med adminpanelet, adminpanelet interagerer med backend, og det settes et oppdrag for \u00e5 sende Push-varsler.<\/p>\n<p><\/p>\n<p>Push-varsler interagerer med en annen komponent som er implementert p\u00e5 NodeJS.<\/p>\n<p><\/p>\n<p>K\u00f8er bygges, og s\u00e5 g\u00e5r sending av varsler gjennom sin egen mekanisme.<\/p>\n<p><\/p>\n<p>Her er det tegnet to databaser. For \u00f8yeblikket bruker vi 2 uavhengige databaser ved hjelp av Docker, som ikke er knyttet til hverandre, annet enn at de har et felles virtuelt nettverk, og at de fysiske dataene lagres i separate kataloger p\u00e5 utviklerens maskin.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/dfde59db7e6886d2d851dcf884049318.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det samme, men i tall. Her er gjenbruk av kode viktig.<\/p>\n<p><\/p>\n<p>Hvis vi tidligere snakket om gjenbruk av kode i form av biblioteker, s\u00e5 i dette tilfellet brukes v\u00e5r tjeneste som h\u00e5ndterer Push-varsler, som en fullverdig server. Den tilbyr et API, og v\u00e5r nye utvikling interagerer med den.<\/p>\n<p><\/p>\n<p>P\u00e5 det tidspunktet brukte vi NodeJS versjon 4. N\u00e5 (i 2017 \u2014 bemerkning fra redakt\u00f8ren) i nye utviklinger bruker vi NodeJS versjon 7. Det er ingen problemer med \u00e5 bruke nye versjoner av bibliotekene i de nye komponentene. <\/p>\n<p><\/p>\n<p>Hvis n\u00f8dvendig, kan vi gjennomf\u00f8re refaktorering og oppgradere versjonen av NodeJS for Push-varslingstjenesten. <\/p>\n<p><\/p>\n<p>Og hvis vi kan opprettholde API-kompatibilitet, kan vi erstatte den med andre prosjekter som ble brukt tidligere.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/5c58c65be078a5a1b9fc17ee2e7b4ad4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hva trengs for \u00e5 legge til Docker? Vi legger til en Dockerfile i v\u00e5rt repository som beskriver de n\u00f8dvendige avhengighetene. I dette eksemplet er komponentene delt opp etter logikk. Dette er det minimal settet for backend-utvikleren.<\/p>\n<p><\/p>\n<p>N\u00e5r vi oppretter et nytt prosjekt, lager vi en Dockerfile, beskriver den n\u00f8dvendige \u00f8kosystemet (Python, Ruby, NodeJS). I docker-compose beskriver vi n\u00f8dvendige avhengigheter \u2014 databasen. Vi spesifiserer hvilken versjon av databasen som trengs, og hvor dataene skal lagres.<\/p>\n<p><\/p>\n<p>Vi bruker en egen tredje container med nginx for \u00e5 h\u00e5ndtere statikk. Det er lagt til rette for opplasting av bilder. Backend plasserer dem i en forh\u00e5ndsforberedt volum som ogs\u00e5 er montert i containeren med nginx, som leverer statikken.<\/p>\n<p><\/p>\n<p>For storing the configurations of nginx and mysql, we have added a Docker folder where we keep the necessary configs. When a developer clones the repository to their machine, they already get a project ready for local development. There is no question about which port or settings to apply.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/e7a6b308a75cacf8ce60687a9e6081dd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Next, we have several components: admin, info API, push notifications.<\/p>\n<p><\/p>\n<p>To run all of this, we created another repository, which we named dockerized-app. Currently, we use several repositories for each component. They are just logically different \u2014 in GitLab, it looks like a folder, while on the developer's machine, it\u2019s a folder for a specific project. Below them lie the components that will be combined.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/f4e2c45c8ec20fca0bac74b3a3892543.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>This is an example of the contents of dockerized-app. We also bring the Docker directory here, where we fill in the configurations required for the interaction of all components. There is a README.md that briefly describes how to run the project.<\/p>\n<p><\/p>\n<p>Here we have applied two docker-compose files. This is done to enable a step-by-step launch. When a developer works with the core and does not need Push notifications, they simply run the docker-compose file and thereby save resources.<\/p>\n<p><\/p>\n<p>If there is a need for integration with Push notifications, then docker-compose.yaml and docker-compose-push.yaml are launched.<\/p>\n<p><\/p>\n<p>Since docker-compose.yaml and docker-compose-push.yaml are in the same folder, a unified virtual network is automatically created.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/535019c82c72c1602176fbaf4aa5640f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Description of the components. This is a more detailed file that is responsible for assembling the components. What\u2019s noteworthy here? Here we introduce the load balancer component.<\/p>\n<p><\/p>\n<p>This is a ready Docker image, which runs nginx and an application that listens to the Docker socket. Dynamically, as containers are turned on and off, it regenerates the nginx config. We distribute the interactions with components across third-level domain names.<\/p>\n<p><\/p>\n<p>For the Development environment, we use the .dev domain \u2014 api.informer.dev. Applications with the .dev domain are accessible on the developer's local machine.<\/p>\n<p><\/p>\n<p>Next, the configs are passed to each project, and all projects are launched together simultaneously.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/bc1e11e6f1fd1c837d2c8087d04145c4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>If we depict this graphically, the client becomes our browser or some tool through which we make requests to the load balancer.<\/p>\n<p><\/p>\n<p>The load balancer determines which container to contact based on the domain name.<\/p>\n<p><\/p>\n<p>Dette kan v\u00e6re nginx som leverer JS-administrasjonsverkt\u00f8yet. Det kan v\u00e6re nginx som leverer API eller statiske filer som hentes av nginx i form av bildegalleri.<\/p>\n<p><\/p>\n<p>P\u00e5 diagrammet er det synlig at containerne er koblet sammen i et virtuelt nettverk og skjult bak en proxy.<\/p>\n<p><\/p>\n<p>P\u00e5 utviklerens maskin kan man f\u00e5 tilgang til containeren ved \u00e5 vite IP-adressen, men vi bruker i prinsippet ikke dette. Det er sjelden behov for direkte tilgang.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/2908c31fd9d3c79f6189bdbeeb6d028f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvilket eksempel kan jeg se for \u00e5 dockerisere applikasjonen min? Etter mitt syn er det offisielle docker-image for MySQL et godt eksempel.<\/p>\n<p><\/p>\n<p>Det er ganske komplisert. Det finnes mange versjoner. Men funksjonaliteten dekker mange behov som kan oppst\u00e5 i l\u00f8pet av videre utvikling. Hvis du bruker tid p\u00e5 \u00e5 forst\u00e5 hvordan alt dette samhandler, tror jeg du ikke vil ha problemer med selvstendig implementering.<\/p>\n<p><\/p>\n<p>P\u00e5 hub.docker.com er det vanligvis lenker til github.com, hvor de r\u00e5 dataene er angitt, og hvor du kan bygge bildet selv.<\/p>\n<p><\/p>\n<p>I dette depotet er det ogs\u00e5 et skript som heter docker-endpoint.sh, som er ansvarlig for initialisering og videre prosessering av applikasjonsoppstart.<\/p>\n<p><\/p>\n<p>I dette eksemplet er det ogs\u00e5 mulighet for konfigurasjon ved hjelp av milj\u00f8variabler. Ved \u00e5 definere milj\u00f8variabler ved oppstart av en enkelt container eller via docker-compose kan vi angi at vi trenger \u00e5 sette et tomt passord for docker for root i MySQL eller et annet passord vi \u00f8nsker.<\/p>\n<p><\/p>\n<p>Det er en mulighet for \u00e5 lage et tilfeldig passord. Vi sier at vi trenger en bruker, m\u00e5 sette et passord for brukeren og opprette en database.<\/p>\n<p><\/p>\n<p>I prosjektene v\u00e5re har vi noe standardisert Dockerfile som h\u00e5ndterer initialiseringen. Der har vi tilpasset det etter v\u00e5re behov for \u00e5 enkelt gi brukeren utvidede rettigheter som applikasjonen bruker. Dette gjorde det senere enkelt \u00e5 opprette en database fra applikasjonens konsoll. I Ruby-applikasjoner finnes det kommandoer for oppretting, endring og sletting av databaser.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/4a9b56e21819d28dd39753134d23fee4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dette er et eksempel p\u00e5 hvordan en spesifikk versjon av MySQL ser ut p\u00e5 github.com. Dockerfile kan \u00e5pnes for \u00e5 se hvordan installasjonen der skjer.<\/p>\n<p><\/p>\n<p>docker-endpoint.sh er skriptet som svarer til inngangspunktet. Ved f\u00f8rste initiering kreves det noen forberedende handlinger, og alle disse handlingene er samlet i initieringsskriptet.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/4153fa46526f3d802931dd1db48b08cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi g\u00e5r over til del to.<\/p>\n<p><\/p>\n<p>For lagring av kildekoder har vi g\u00e5tt over til gitlab. Dette er et kraftig system med et visuelt grensesnitt.<\/p>\n<p><\/p>\n<p>En av komponentene i Gitlab er Gitlab CI. Det lar oss beskrive sekvenser av kommandoer som deretter brukes til \u00e5 organisere kodeleveransen eller kj\u00f8re automatisert testing.<\/p>\n<p><\/p>\n<p>Presentasjon om Gitlab CI 2 <noindex><a rel=\"nofollow\" href=\"https:\/\/goo.gl\/uohKjI\">https:\/\/goo.gl\/uohKjI<\/a><\/noindex> \u2014 presentasjonen fra Ruby Russia club \u2014 den er ganske detaljert og kan interessere deg.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/5d26d20500f34eeb9768e6c3d91bbefa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>N\u00e5 skal vi se p\u00e5 hva som kreves for \u00e5 aktivere Gitlab CI. For \u00e5 starte Gitlab CI er det nok \u00e5 legge filen .gitlab-ci.yml i rotmappen av prosjektet.<\/p>\n<p><\/p>\n<p>Her beskriver vi hvilke sekvenser av tester og distribusjoner vi \u00f8nsker \u00e5 utf\u00f8re.<\/p>\n<p><\/p>\n<p>Vi kj\u00f8rer skriptene som direkte kaller docker-compose for \u00e5 bygge applikasjonen v\u00e5r. Dette er et eksempel p\u00e5 backend.<\/p>\n<p><\/p>\n<p>Deretter sier vi at det er n\u00f8dvendig \u00e5 kj\u00f8re migrasjoner for \u00e5 endre databasen og utf\u00f8re tester.<\/p>\n<p><\/p>\n<p>Hvis skriptene utf\u00f8res korrekt og ikke returnerer en feilkode, g\u00e5r systemet videre til den andre distribusjonsstadiet.<\/p>\n<p><\/p>\n<p>Distribusjonsstadiet er i \u00f8yeblikket implementert for staging. Vi har ikke organisert en s\u00f8ml\u00f8s omstart.<\/p>\n<p><\/p>\n<p>Vi slukker alle containere, og deretter starter vi opp alle containerne igjen, bygget i det f\u00f8rste testingssteget.<\/p>\n<p><\/p>\n<p>Vi kj\u00f8rer migrasjoner av databasene som ble skrevet av utviklerne for det n\u00e5v\u00e6rende milj\u00f8et.<\/p>\n<p><\/p>\n<p>Det er notert at dette kun skal brukes for master-grenen.<\/p>\n<p><\/p>\n<p>Ingen handlinger utf\u00f8res ved endring i andre grener.<\/p>\n<p><\/p>\n<p>Det er mulighet for \u00e5 organisere distribusjoner basert p\u00e5 grener.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/8a5b880bd9a0d4bab0b276568e2ba413.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>For \u00e5 organisere dette videre, m\u00e5 vi installere Gitlab Runner.<\/p>\n<p><\/p>\n<p>Dette verkt\u00f8yet er skrevet i Golang. Det er en enkelt fil som det er vanlig i Golang-verdenen, som ikke har noen avhengigheter.<\/p>\n<p><\/p>\n<p>N\u00e5r vi starter, registrerer vi Gitlab Runner.<\/p>\n<p><\/p>\n<p>Vi f\u00e5r en n\u00f8kkel i webgrensesnittet til Gitlab.<\/p>\n<p><\/p>\n<p>Deretter kaller vi initialiseringskommandoen i kommandolinjen.<\/p>\n<p><\/p>\n<p>Vi setter opp Gitlab Runner i dialogmodus (Shell, Docker, VirtualBox, SSH)<\/p>\n<p><\/p>\n<p>Koden p\u00e5 Gitlab Runner vil kj\u00f8re ved hver commit, avhengig av innstillingen av .gitlab-ci.yml.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/37c8ac7499f0cfba2eb07a84083e44e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Slik ser det ut visuelt i GitLab i nettgrensesnittet. Etter at vi har koblet til GitLab CI, f\u00e5r vi et flagg som viser i hvilken tilstand bygget er p\u00e5 n\u00e5v\u00e6rende tidspunkt.<\/p>\n<p><\/p>\n<p>Vi ser at det for 4 minutter siden ble gjort en commit som bestod alle tester uten problemer.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/33ac79c45f0651a5f8bde75092c4ac44.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi kan se n\u00e6rmere p\u00e5 bygdene. Her ser vi at det allerede har v\u00e6rt to tilstander. Tilstand for testing og tilstand for distribusjon til staging.<\/p>\n<p><\/p>\n<p>Hvis vi klikker p\u00e5 et spesifikt bygg, vil der v\u00e6re konsollutdata fra kommandoene som ble kj\u00f8rt i prosessen i henhold til .gitlab-ci.yml.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/d26dd28708c7fc8a409af4be4d48f502.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Slik ser historikken til produktet v\u00e5rt ut. Vi ser at det har v\u00e6rt vellykkede fors\u00f8k. N\u00e5r testene feiler, g\u00e5r den ikke videre til neste trinn, og koden p\u00e5 staging oppdateres ikke.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/ee7bd81dc283c7af0c194779d4230780.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvilke oppgaver l\u00f8ste vi p\u00e5 staging n\u00e5r vi implementerte Docker? Systemet v\u00e5rt best\u00e5r av komponenter, og vi hadde behov for \u00e5 restarte bare de oppdaterte komponentene i depotet, ikke hele systemet.<\/p>\n<p><\/p>\n<p>For dette m\u00e5tte vi dele opp alt i separate mapper.<\/p>\n<p><\/p>\n<p>Etter at vi gjorde dette, oppsto det et problem med at Docker-compose oppretter sitt eget nettverksomr\u00e5de for hver mappe og ikke ser komponentene til nabomappen.<\/p>\n<p><\/p>\n<p>For \u00e5 omg\u00e5 dette, opprettet vi et nettverk i Docker manuelt. I Docker-compose spesifiserte vi at vi bruker dette nettverket til prosjektet.<\/p>\n<p><\/p>\n<p>Dermed ser hver komponent som starter med dette nettverket komponentene i andre deler av systemet.<\/p>\n<p><\/p>\n<p>Det neste problemet er deling av staging mellom flere prosjekter.<\/p>\n<p><\/p>\n<p>For at alt skal se bra ut og v\u00e6re s\u00e5 n\u00e6rt produksjon som mulig, er det best \u00e5 bruke port 80 eller 443, som brukes overalt p\u00e5 nettet.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/f863cf1833271bf132455a70ad7d2706.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvordan l\u00f8ste vi dette? Vi tildelte \u00e9n GitLab Runner til alle store prosjekter.<\/p>\n<p><\/p>\n<p>GitLab tillater \u00e5 kj\u00f8re flere distribuerte GitLab Runners, som vil ta alle oppgaver sekvensielt i en tilfeldig rekkef\u00f8lge.<\/p>\n<p><\/p>\n<p>For \u00e5 unng\u00e5 kaos, begrenset vi gruppen av prosjektene v\u00e5re til \u00e9n GitLab Runner, som h\u00e5ndterer volumene v\u00e5re problemfritt.<\/p>\n<p><\/p>\n<p>Vi flyttet nginx-proxy til et eget oppstartsskript og spesifiserte nettverkene til alle prosjektene der. <\/p>\n<p><\/p>\n<p>Prosjektet v\u00e5rt har ett nettverk, mens balancereren har flere nettverk etter prosjektnavn. Den kan proxy videre basert p\u00e5 domenenavn.<\/p>\n<p><\/p>\n<p>Vi f\u00e5r foresp\u00f8rslene via domenet p\u00e5 port 80, og de dirigeres til en gruppe containere som betjener dette domenet.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/25c769f029b272a17fd06bbe60cf0ea0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvilke andre problemer oppstod? Det som er standard, er at alle containere kj\u00f8res av brukeren root. Denne root er ikke den samme som root p\u00e5 vertsoperativsystemet.<\/p>\n<p><\/p>\n<p>Men hvis du logger inn i containeren, vil du v\u00e6re root, og filene som vi oppretter i denne containeren, f\u00e5r root-rettigheter.<\/p>\n<p><\/p>\n<p>Hvis utvikleren har logget inn i containeren og kj\u00f8rt kommandoer som oppretter filer, og deretter logger ut av containeren, vil han i sitt arbeidskatalog ha en fil han ikke har tilgang til.<\/p>\n<p><\/p>\n<p>Hvordan kan dette l\u00f8ses? Vi kan legge til brukere som skal v\u00e6re i containeren.<\/p>\n<p><\/p>\n<p>Hvilke problemer oppstod da vi la til en bruker?<\/p>\n<p><\/p>\n<p>N\u00e5r vi oppretter en bruker, er det ofte at gruppering ID-ene (UID) og bruker ID-ene (GID) ikke samsvarer.<\/p>\n<p><\/p>\n<p>For \u00e5 l\u00f8se dette problemet i containeren bruker vi brukere med ID 1000.<\/p>\n<p><\/p>\n<p>I v\u00e5rt tilfelle stemte dette overens med at de fleste utviklerne bruker Ubuntu-operativsystemet. Og p\u00e5 Ubuntu er den f\u00f8rste brukeren ID 1000.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/d4911374e4953fdcd807c387efeafec3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hva er planene v\u00e5re?<\/p>\n<p><\/p>\n<p>Les gjennom dokumentasjonen for Docker. Prosjektet utvikler seg aktivt, og dokumentasjonen endres. Dataene som ble samlet inn for to-tre m\u00e5neder siden, er allerede i ferd med \u00e5 bli utdaterte. <\/p>\n<p><\/p>\n<p>Noen av problemene vi har l\u00f8st, er sannsynligvis allerede l\u00f8st med standardmidler.<\/p>\n<p><\/p>\n<p>Vi \u00f8nsker s\u00e5 mye \u00e5 g\u00e5 videre og begynne med orkestrering.<\/p>\n<p><\/p>\n<p>Et eksempel er den innebygde mekanismen i Docker kalt Docker Swarm, som f\u00f8lger med standardinstallasjonen. Vi vil kj\u00f8re noe i produksjon basert p\u00e5 Docker Swarm-teknologi.<\/p>\n<p><\/p>\n<p>Generering av containere gj\u00f8r det vanskelig \u00e5 jobbe med logger. N\u00e5 er loggene isolerte. De er spredt over containerne. En av oppgavene er \u00e5 gj\u00f8re logger lett tilgjengelig via webgrensesnittet.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Utviklings- og testprosess med Docker og Gitlab CI\" src=\"\/wp-content\/uploads\/2019\/04\/cff8c72dd8af7de1fa0227601bd1d69c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Kilde: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/449742\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &#171;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&#187; \u0422\u0435, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0431\u0430\u0437\u0435 Docker + Gitlab CI \u0447\u0430\u0441\u0442\u043e \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b. \u0421 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0430\u0442\u044c? \u041a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c? \u041a\u0430\u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c? \u042d\u0442\u043e\u0442 \u0434\u043e\u043a\u043b\u0430\u0434 \u0445\u043e\u0440\u043e\u0448 \u0442\u0435\u043c, \u0447\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":24326,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-32526","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.5 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &quot;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&quot; \u0422\u0435, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438.\" \/>\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\/no\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.5\" \/>\n\t\t<meta property=\"og:locale\" content=\"nn_NO\" \/>\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\udd47\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker \u0438 Gitlab CI | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &quot;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&quot; \u0422\u0435, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/no\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci\" \/>\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-31T18:47:32+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:47:32+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\udd47Utviklings- og testprosess med Docker og Gitlab CI | ProHoster","description":"Jeg foresl\u00e5r at du ser n\u00e6rmere p\u00e5 transkripsjonen av Alexander Sigachevs foredrag fra Inventos \"Utviklings- og testprosess med Docker + Gitlab CI\". De som akkurat begynner \u00e5 implementere utviklingsprosessen.","canonical_url":"https:\/\/prohoster.info\/no\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nn_NO","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\udd47\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker \u0438 Gitlab CI | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0421\u0438\u0433\u0430\u0447\u0435\u0432\u0430 \u0438\u0437 Inventos &quot;\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Docker + Gitlab CI&quot; \u0422\u0435, \u043a\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438.","og:url":"https:\/\/prohoster.info\/no\/blog\/administrirovanie\/protsess-razrabotki-i-testirovaniya-s-docker-i-gitlab-ci","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-31T18:47:32+00:00","article:modified_time":"2019-10-31T18:47:32+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"32526","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-21 11:18:24","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:57:22","updated":"2026-01-21 11:18:24","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/posts\/32526","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/comments?post=32526"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/posts\/32526\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/media\/24326"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/media?parent=32526"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/categories?post=32526"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/tags?post=32526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}