Ju ofroj mundësinë të njiheni me përmbledhjen e raportit të Aleksandr Sigachev nga Inventos "Processi i zhvillimit dhe testimit me Docker + Gitlab CI"
Ata që sapo fillojnë të implementojnë procesin e zhvillimit dhe testimit mbi bazën e Docker + Gitlab CI shpesh bëjnë pyetje bazike. Nga të filloj? Si ta organizoj? Si të testoj?
Ky raport është i mirë sepse strukturohet për të treguar procesin e zhvillimit dhe testimit duke përdorur Docker dhe Gitlab CI. Raporti vetë është i vitit 2017. Mendoj se nga ky raport mund të nxjerrim bazat, metodologjinë, idenë, përvojën e përdorimit.

Kush është i interesuar, ju lutem, shihni më poshtë.
Më prezantohem, jam Aleksandr Sigachev. Punoj në kompaninë Inventos. Do të flas për përvojën time në përdorimin e Docker dhe si e po e implementojmë gradualisht në projektet e kompanisë.
Tema e raportit: Procesi i zhvillimit duke përdorur Docker dhe Gitlab CI.

Ky është raporti im i dytë mbi Docker. Në kohën e raportit të parë, ne e përdornim Docker vetëm në zhvillim në makinat e zhvilluesve. Numri i punonjësve që përdornin Docker ishte rreth 2-3 persona. Me kalimin e kohës, u akumulua përvojë dhe avancuam pak më tej. Linku për .
Çfarë do të ketë në këtë raport? Ne do të ndajmë përvojën tonë mbi pengesat që kemi përballur, si i kemi zgjidhur problemet. Nuk gjithmonë ishte e bukur, por na lejoj të ecim përpara.
Deviza jonë: dockerizo gjithçka që arrin në duar tona.

Cilat probleme zgjidhim?
Kur në kompani ka disa ekipe, programuesi është një burim që ndahet. Ndonjëherë ndodhin etapa kur programuesi hiqet nga një projekt dhe i jepet për një kohë në një projekt tjetër.
Për të kuptuar shpejt, programuesi duhet të shkarkojë kodin burimor të projektit dhe të aktivizojë sa më shpejt një mjedis që do t'i lejojë atij të vazhdojë përpara duke zgjidhur detyrat e këtij projekti.
Zakonisht, nëse fillon nga zero, dokumentacioni në projekt është minimal. Informacioni se si të konfigurohet është vetëm te të përvojshmit. Punonjësit e vetëorganizojnë vendin e punës në një ose dy ditë. Për ta përshpejtuar këtë, ne përdorëm Docker.
Arsyeja e ardhshme është standardizimi i konfigurimeve në zhvillim. Nga përvoja ime, zhvilluesit gjithmonë tregojnë inisiativë. Në çdo rast të pestë, njohin një domen të personalizuar, për shembull vasya.dev. Pranë tij është fqinj Petya, i cili ka domen petya.dev. Ata zhvillojnë një uebfaqe ose ndonjë komponent të sistemit duke përdorur këtë emër domeni.
Kur sistemi zgjerohet dhe këto emra domain fillojnë të shfaqen në konfigurime, lind një konflikt midis mjediseve të Zhvillimit dhe rruga e uebsit rishkruhet.
E njëjta gjë ndodh me konfigurimet e bazës së të dhënave. Disa nuk shqetësohen për sigurinë dhe punojnë me një fjalëkalim të zbrazët root. Disa, gjatë fazës së instalimit të MySQL, u kërkua një fjalëkalim dhe fjalëkalimi doli të ishte 123. Ndodh shpesh që konfigurimi i bazës së të dhënave të ndryshohet vazhdimisht në varësi të commit-it të zhvilluesit. Disa kanë bërë ndryshime, disa nuk e kanë bërë konfigurimin. Ka pasur truke, kur ne nxjerrim një konfigurim testues në .gitignore dhe çdo zhvillues duhet të instalojë bazën e të dhënave. Kjo e komplikon procesin e fillimit. Përveç gjithçkaje, duhet të mbajmë mend për bazën e të dhënave. Baza e të dhënave duhet të inicializohet, duhet të shkruhet një fjalëkalim, duhet të shkruhet një përdorues, të krijohet një tabelë dhe kështu me radhë.
Një tjetër problem është për versionet e ndryshme të bibliografive. Ndodh shpesh që zhvilluesi punon me projekte të ndryshme. Ka një projekt Legacy, që e kemi filluar pesë vjet më parë (nga viti 2017 - shënim i redaktorit). Në momentin e fillimit, kemi filluar me MySQL 5.5. Ka edhe projekte moderne, ku përpiqemi të implementojmë versione më moderne të MySQL, si 5.7 ose më të reja (në vitin 2017 - shënim i redaktorit).
Atij që punon me MySQL e di se këto biblioteka sjellin varësi. Është mjaft problematike të nisi 2 baza bashkë. Të paktën, është problematike të lidhësh klientë të vjetër me një bazë të re të dhënash. Kjo sjell, nga ana tjetër, disa probleme.
Problemi tjetër është kur zhvilluesi punon në një makinë lokale, ai përdor burime lokale, skedarë lokalë, RAM lokal. Të gjitha ndërveprimet gjatë procesit të zhvillimit të zgjidhjeve realizohen në kontekstin e asaj që funksionon në një makinë. Një shembull mund të jetë kur kemi 3 serverë backend në Production, dhe zhvilluesi ruan skedarët në katalogun rrënjësor dhe nga aty nginx merr skedarët për të përgjigjur kërkesës. Kur ky kod arrin në Production, del se skedari është në një nga 3 serverët.
Aktualisht po zhvillohet drejtimi i mikrosherbimeve. Kur ndajmë aplikacionet tona të mëdha në disa komponente të vogla që ndërveprojnë me njëra-tjetrën. Kjo lejon përzgjedhjen e teknologjive sipas grykës specifike të detyrave. Po ashtu, kjo ndihmon në ndarjen e punës dhe zonës së përgjegjësisë midis zhvilluesve.
Zhvilluesi Frontend, duke punuar me JS, praktikisht nuk ndikon në Backend. Zhvilluesi Backend, nga ana tjetër, zhvillon, në rastin tonë, Ruby on Rails dhe nuk ndikon në Frontend. Ndërveprimi bëhet përmes API.
Si një bonus, me ndihmën e Docker, arritëm të optimizojmë burimet në Staging. Çdo projekt, për shkak të specifikave të tij, kërkonte konfigurime të caktuara. Fizikisht duhej të ndaheshin disa serverë virtualë dhe t’i konfiguroni veç e veç, ose të ndajmë një ambient të përbashkët dhe projektet mund të ndikojnë njëra-tjetrën në varësi të versioneve të librarive.

Mjetet. Çfarë përdorim?
- Vetë Docker. Në Dockerfile përshkruhen varësitë e një aplikacioni.
- Docker-compose është një lidhje që bashkon disa nga aplikacionet tona Docker.
- GitLab e përdorim për ruajtjen e kodit burimor.
- GitLab-CI e përdorim për integrimin sistemor.

Referati përbëhet nga dy pjesë.
Pjesa e parë do të flasë për mënyrën se si aktivizuam Docker në makinat e zhvilluesve.
Pjesa e dytë do të flasë për mënyrën se si ndërveprojmë me GitLab, si i aktivizojmë testet dhe si i lëshojmë në Staging.

Docker — kjo është një teknologji që lejon (duke përdorur një qasje deklarative) të përshkruajmë komponentët e nevojshëm. Kjo është një shembull i Dockerfile. Këtu shpallim se trashëgojmë nga imazhi zyrtar i Docker Ruby:2.3.0. Ai përmban Ruby version 2.3 të instaluar. Ne instalojmë bibliotekat e nevojshme për ndërtimin dhe NodeJS. Përshkruajmë se krijojmë një katalog /app. Caktojmë katalogun app si direktorinë e punës. Në këtë katalog vendosim Gemfile minimal dhe Gemfile.lock që na nevojitet. Më pas kryejmë ndërtimin e projekteve, të cilat instalojnë këto varësi të imazhit. U tregojmë se kontejneri do të jetë gati të dëgjojë në portin e jashtëm 3000. Komanda e fundit — është komanda që aktivizon aplikacionin tonë. Nëse ne realizojmë komandën e aktivizimit të projektit, aplikacioni do të përpiqet të ekzekutohet dhe do të aktivizojë komandën e specifikuar.

Ky është një shembull minimal i një skedari docker-compose. Në këtë rast, ne tregojmë se si bëhet lidhja midis dy kontejnerëve. Kjo përfshin shërbimin e bazës së të dhënave dhe shërbimin web. Aplikacionet tona web në shumicën e rasteve kërkojnë si backend një bazë të dhënash për ruajtjen e të dhënave. Pasi përdorim MySQL, shembulli me MySQL është i tillë, por asgjë nuk ndalon përdorimin e ndonjë baze tjetër të dhënash (PostgreSQL, Redis).
Ne marrim nga burimi zyrtar në Docker hub imazhin MySQL 5.7.14 pa ndryshime. Imazhi që përgjigjet për aplikacionin tonë web ne e ndërtojmë nga direktoria aktuale. Gjatë fillimit të parë, ai na ndihmon të ndërtojmë imazhin. Më pas, ai ekzekuton komandën që ne kemi këtu. Nëse kthehemi prapa, do të shohim që ishte e përcaktuar një komandë për fillimin nëpërmjet Puma. Puma është një shërbim i shkruar në Ruby. Në rastin e dytë, ne e rishkruajmë. Kjo komandë mund të jetë e rastësishme në varësi të nevojave ose detyrave tona.
Gjithashtu, ne përshkruajmë se si duhet të kalojmë portin nga makina e krijuesit në portin 3000 të kontejnerit. Kjo bëhet automatikisht përmes iptables dhe mekanizmit të tij, i cili është ndërtuar në Docker.
Krijuesi mund gjithashtu, ashtu si më parë, të aksesojë çdo adresë IP të disponueshme, për shembull, 127.0.0.1 në mënyrë lokale ose adresën IP të jashtme të makinës.
Rreshti i fundit thotë se kontejneri web varet nga kontejneri db. Kur ne thërrasim për të filluar kontejnerin web, paraprakisht docker-compose do të nisë bazën e të dhënave. Pas fillimit të bazës së të dhënave (në të vërtetë — pas aktivizimit të kontejnerit! Gatishmëria e BDrë nuk garanton këtë) do të nisë aplikacionin tonë, backend-in tonë.
Kjo lejon të shmangen gabimet kur baza e të dhënave nuk është ngritur dhe ndihmon në kursimin e burimeve, kur ne ndalojmë kontejnerin e bazës së të dhënave, duke i liruar kështu burimet për projekte të tjera.

Çfarë na ofron përdorimi i dockerizimit të bazës së të dhënave në projekt. Ne regjistrojmë versionin e MySQL për të gjithë krijuesit. Kjo ndihmon në shmangien e disa gabimeve që mund të ndodhin kur versionet ndryshojnë, kur ndodhin ndryshime në sintaksë, konfigurim, cilësime standarde. Kjo lejon të përcaktojmë hostname të përbashkëta për bazën e të dhënave, login, password. Ne largohemi nga ai zhurmë emrash dhe konflikteje në skedaret e konfigurimit, të cilat ishin më parë.
Ne kemi mundësinë të përdorim një konfigurim më optimal për mjedisin e Zhvillimit, i cili do të dallojë nga ai i parazgjedhur. MySQL, si standard, është i konfiguruar për makina të dobëta dhe performanca e tij është shumë e ulët nga kutia.

Docker lejon përdorimin e interpreterit Python, Ruby, NodeJS, PHP të versionit të dëshiruar. Ne i shpëtojmë nevojës për të përdorur ndonjë menaxher versionesh. Më parë përdornim një paketë rpm për Ruby, e cila lejonte ndërrimin e versionit në varësi të projektit. Kjo gjithashtu mundëson, falë kontejnerit Docker, të migrimin e kodit dhe versionimin e tij së bashku me varësitë. Nuk kemi problem të kuptojmë versionin e si interpreterit, ashtu edhe të kodit. Për të përditësuar versionin, duhet të mbyllim kontejnerin e vjetër dhe të ngremë një kontejner të ri. Nëse diçka shkon keq, mund të mbyllim kontejnerin e ri dhe të ngremë kontejnerin e vjetër.
Pas ndërtimit të imazhit, kontejnerët si në Zhvillim ashtu edhe në Prodhim do të jenë të njëjtë. Kjo është veçanërisht e rëndësishme për instalime të mëdha.
Në Frontend përdorim JavaScript dhe NodeJS.
Aktualisht projekti ynë më i fundit është në ReactJS. Zhvilluesi nisi të gjitha kontejnerët dhe zhvilloi duke përdorur hot-reload.
Më pas, fillon detyra për ndërtimin e JavaScript dhe kodi, i ndërtuar në statikë, jepet përmes nginx duke kursyer burime.

Këtu kam paraqitur skemën e projektit tonë më të fundit.
Cilat probleme zgjidhëm? Na duhej të ndihmonim në ndërtimin e një sistemi me të cilin ndërveprojnë pajisjet mobile. Ato marrin të dhëna. Një nga mundësitë është dërgimi i njoftimeve push në këtë pajisje.
Çfarë bëmë për këtë?
Ne ndamë aplikacionin në komponente të tilla si: pjesa administrative në JS, backend që punon përmes një ndërfaqe REST nën Ruby on Rails. Backend ndërvepron me bazën e të dhënave. Rezultati, që gjenerohet jepet klientit. Adminja ndërvepron me backend dhe bazën e të dhënave përmes ndërfaqes REST.
Gjithashtu na duhej të dërgonim njoftime push. Para kësaj patëm një projekt, në të cilin ishte zbatua një mekanizëm që ishte përgjegjës për dorëzimin e njoftimeve në platformat mobile.
Ne zhvilluam një skemë të tillë: operatori nga shfletuesi interakton me adminin, admini interakton me backend, vendoset detyra se duhet të dërgojmë njoftime push.
Njoftimet push ndërveprojnë me një komponent tjetër, i cili është i implementuar në NodeJS.
Këtu ndodhen radhët dhe më pas vazhdon mekanizmi i dërgimit të njoftimeve.
Këtu janë vizatuar dy baza të dhënash. Momentin aktual, ne po përdorim me anë të Docker dy baza të dhënash të pavarura, të cilat nuk janë të lidhura me njëra-tjetrën. Përveç faktit që ato ndajnë një rrjet virtual të përbashkët, të dhënat fizike ruhen në kataloge të ndryshme në makinën e zhvilluesit.

E njëjta gjë por në numra. Këtu është e rëndësishme ri-përdorimi i kodit.
Nëse më parë folëm për ri-përdorimin e kodit në formën e bibliotekave, në këtë shembull shërbimi ynë që menaxhon njoftimet Push ri-përdoret si një server i plotë. Ai ofron një API. Ndërsa me të ndërveprohet zhvillimi ynë i ri.
Në atë kohë ne përdornim versionin 4 të NodeJS. Aktualisht (në vitin 2017 - shënimi i redaktorit) në zhvillimet e reja përdorim versionin 7 të NodeJS. Nuk ka probleme të attrahojmë versione të reja bibliotekash në komponentët e rinj.
Nëse është e nevojshme, mund të kryejmë refaktorim dhe të rrisim versionin e NodeJS për shërbimin e njoftimeve Push.
Dhe nëse arrijmë të ruajmë kompatibilitetin në API, atëherë do të mund ta zëvendësojmë në projekte të tjera që janë përdorur më parë.

Çfarë nevojitet për të shtuar Docker? Shtojmë nëRepository Dockerfile, i cili përshkruan varësitë e nevojshme. Në këtë shembull komponentët janë të ndarë sipas logjikës. Ky është një set minimal për zhvilluesin backend.
Kur krijojmë një projekt të ri, krijojmë Dockerfile, përshkruajmë ekosistemin e nevojshme (Python, Ruby, NodeJS). Në docker-compose përshkruajmë varësitë e nevojshme - bazën e të dhënave. Përcaktojmë se na nevojitet një bazë e caktuar versioni, për të ruajtur të dhënat atje ku duhet.
Ne përdorim një kontejner të tretë të veçantë me nginx për ofrimin e statikës. Është parashikuar mundësia e ngarkimit të imazheve. Backend i vendos ato në një volum të përgatitur më parë, i cili gjithashtu është montuar në kontejnerin me nginx, i cili ofron statikat.
Për të ruajtur konfigurimin e nginx dhe mysql, ne kemi shtuar një dosje Docker, në të cilën ruajmë konfiguratat e nevojshme. Kur zhvilluesi bën git clone të repository-t në makinën e tij, ai merr një projekt tashmë të përgatitur për zhvillimin lokal. Nuk lind problemi se cili port ose cilat cilësime duhet të aplikohen.

Më pas ne kemi disa komponentë: admin, inform-API, njoftime push.
Për të nisur gjithçka, ne krijuam një depo të re, të cilën e quajtëm dockerized-app. Në momentin aktual, ne po përdorim disa depo për çdo komponent. Ato dallohen thjesht logjikisht — në GitLab duket si një dosje, ndërsa në kompjuterin e zhvilluesit është një dosje për projektin specifik. Nën nivelin e saj gjenden komponentët që do të bashkohen.

Ky është një shembull i përmbajtjes së dockerized-app. Ne gjithashtu e nxjerrim këtu katalogun Docker, ku plotësojmë konfigurimet e nevojshme për ndërveprimet e të gjitha komponentëve. Ka një README.md, ku përshkruhet shkurtimisht se si të nisni projektin.
Këtu ne aplikojmë dy skeda docker-compose. Kjo është bërë për të pasur mundësinë e nisjes hap pas hapi. Kur zhvilluesi punon me bërthamën, nuk i nevojiten njoftimet Push, kështu që ai thjesht nis skedën docker-compose dhe për rrjedhojë resurset ekonomizohen.
Nëse ka nevojë për integrim me njoftimet Push, atëherë niset docker-compose.yaml dhe docker-compose-push.yaml.
Duke qenë se docker-compose.yaml dhe docker-compose-push.yaml ndodhen në dosje, krijohet automatikisht një rrjet virtual i njëjtë.

Përshkrimi i komponentëve. Ky është një skedë më e zgjatur, e cila përgjigjet për ndërtimin e komponentëve. Çfarë është e rëndësishme këtu? Këtu ne prezantojmë komponentin balancues.
Ky është një imazh i gatshëm Docker, në të cilin niset nginx dhe aplikacioni që dëgjon socket-in Docker. Dinamikisht, me aktivizimin dhe çaktivizimin e kontejnerëve, rigjeneron konfigurimin nginx. Ndërveprimet me komponentët i ndajmë sipas emrave të domain-it të tretë.
Për ambientin e zhvillimit përdorim domenin .dev — api.informer.dev. Aplikacionet me domenin .dev janë të aksesueshme në kompjuterin lokal të zhvilluesit.
Pastaj, konfigurimet kalojnë për çdo projekt dhe të gjitha projektet nisen së bashku në të njëjtën kohë.

Nëse e ilustrojmë në mënyrë grafike, atëherë klienti është shfletuesi ynë ose ndonjë mjet me të cilin bëjmë kërkesa te balancuesi.
Balancuesi përcakton nëpërmjet emrit të domain-it se cilit kontejner duhet t'i drejtohet.
Ky mund të jetë nginx, që jep JS të adminëve. Ky mund të jetë nginx, që jep API-në ose skedarët statikë, që jepen nga nginx si ngarkesë imazhesh.
Në diagram shikohet se kontejnerët janë të bashkuar në një rrjet virtual dhe janë të fshehur pas një proxy.
Në makinë e zhvilluesit, mund të qaseni në kontejner duke e ditur IP-në, por në parim nuk e përdorim këtë. D nearly necessiteti i qasjes direkte nuk lind praktikisht.

Cili është një shembull që mund të shihni për të dockerizuar aplikacionin tuaj? Në mendimin tim, një shembull i mirë është imazhi zyrtar i docker për MySQL.
Ai është mjaft kompleks. Ka shumë versione. Por funksionaliteti i tij mund të mbulojë shumë nevoja që mund të lindin gjatë zhvillimit të mëtejshëm. Nëse shpenzoni kohë dhe kuptoni sesi të gjitha këto bashkëveprojnë, mendoj se nuk do të keni probleme me implementimin e vetë.
Në hub.docker.com zakonisht ka lidhje me github.com, ku janë të dhëna të papërpunuara, nga të cilat mund të krijoni vetë imazhin.
Më pas në këtë depo, ka një skenar docker-endpoint.sh, që është përgjegjës për inicializimin e parë dhe për përpunimin e mëtejshëm të nisjes së aplikacionit.
Gjithashtu, në këtë shembull ka mundësi konfigurimi përmes variablave të ambientit. Duke përcaktuar variablën e ambientit në nisjen e një kontejneri të vetëm ose përmes docker-compose, mund të themi se na nevojitet të vendosim një fjalëkalim të zbrazët për root në MySQL, ose një tjetër që ne duam.
Ka mundësi për të krijuar një fjalëkalim rastësor. Ne themi se na nevojitet një përdorues, duhet të vendosim një fjalëkalim për përdoruesin dhe duhet të krijojmë një bazë të dhënash.
Në projektet tona kemi paksa unifikuar Dockerfile-in, i cili është përgjegjës për inicializimin. Atje kemi bërë disa ndryshime sipas nevojave tona për të thjeshtuar zgjerimin e të drejtave të përdoruesit që përdoret nga aplikacioni. Kjo na ka lejuar më pas të krijojmë thjesht një bazë të dhënash nga konsola e aplikacionit. Në aplikacionet Ruby ka komandë për krijimin, ndryshimin dhe fshirjen e bazave të të dhënave.

Ky është një shembull i asaj si duket një version specifik i MySQL në github.com. Mund ta hapni Dockerfile-in dhe të shihni se si ndodh instalimi.
docker-endpoint.sh është skenari përgjegjës për pikën e hyrjes. Gjatë inicializimit të parë kërkohen disa veprime përgatitore dhe të gjitha këto veprime janë hequr në skenarin e inicializimit.

Kalojmë në pjesën e dytë.
Për të ruajtur kodin burimor, kemi kaluar në gitlab. Kjo është një sistem mjaft i fuqishëm, i cili ka një ndërfaqe vizuale.
Një nga komponentët e Gitlab është Gitlab CI. Ai lejon përshkrimin e një serie komandash, të cilat më vonë do të përdoren për të organizuar sistemin e dorëzimit të kodit ose për të nisur testimin automatizuar.
Raporti mbi Gitlab CI 2 — një raport nga Ruby Russia club — mjaft i detajuar dhe ndoshta do t'ju interesoje.

Tani do të shohim çfarë kërkohet për të aktivizuar Gitlab CI. Për të nisur Gitlab CI, mjafton të vendosim skedarin .gitlab-ci.yml në rrënjën e projektit.
Këtu përshkruajmë se çfarë duam të ekzekutojmë si një seri gjendjesh, si teste, dërgime.
Ekzekutojmë skriptet që thërrasin ndryshe ndërtimin e aplikacionit tonë me docker-compose. Ky është një shembull i backend.
Pastaj themi se duhet të kalojmë migrimet për ndryshimin e bazës së të dhënave dhe të zbatojmë testet.
Nëse skriptet ekzekutohen saktë dhe nuk kthejnë kod gabimi, atëherë sistemi kalon në fazën e dytë të dërgimit.
Faza e dërgimit aktualisht është e realizuar për staging. Nuk e kemi organizuar rindërtimin pa downtime.
Ne mbyllim me forcë të gjitha kontejnerët, dhe pastaj i ngremë sërish të gjitha kontejnerët, të ndërtuar në fazën e parë gjatë testimit.
Kalon tashmë migrimet e bazës së të dhënave për ambientin aktual të ndryshueshëm, të cilat janë shkruar nga zhvilluesit.
Ka një shënim, që kjo të aplikohet vetëm për degën master.
Kur ndryshohen degë të tjera, nuk ekzekutohet.
Ka mundësinë për të organizuar përvidhë nëpër degë.

Për ta organizuar më tej, na nevojitet të instalojmë Gitlab Runner.
Kjo utilitare është e shkruar në Golang. Ajo është një skedar unik siç është zakon në botën Golang, i cili nuk kërkon asnjë varësi.
Kur e nisi, regjistrojmë Gitlab Runner.
Marrim një çelës në ndërfaqen web të Gitlab.
Pastaj thërrasim komandën e inicializimit në rreshtin e komandave.
Konfigurojmë Gitlab Runner në modalitetin dialog (Shell, Docker, VirtualBox, SSH).
Kodi në Gitlab Runner do të ekzekutohet me çdo commit në varësi të konfigurimit të .gitlab-ci.yml.

Si duket vizualisht në Gitlab në ndërfaqen web. Pas lidhjes me Gitlab CI, na shfaqet një flamur, i cili tregon në çfarë gjendje ndodhet ndërtimi në këtë moment.
Ne shohim që 4 minuta më parë u bë një commit, i cili kaloi të gjitha testet dhe nuk shkaktoi probleme.

Mund të shohim më në detaje ndërtimet. Këtu shohim që tashmë janë kaluar dy gjendje. Gjendja e testimit dhe gjendja e shpërndarjes në staging.
Nëse ne klikojmë në një ndërtim specifik, atje do të ketë daljen e konsolës së komandave që janë ekzekutuar gjatë procesit sipas .gitlab-ci.yml.

Këtu gjendet historia e produktit tonë. Ne shohim që ka pasur përpjekje të suksesshme. Kur testet dështojnë, atëherë nuk kalon në hapin tjetër dhe kodi në staging nuk përditësohet.

Cilat probleme kishim në staging gjatë implementimit të dockerit? Sistemi ynë përbëhet nga komponente dhe na duhej të ri-fillonim vetëm pjesën e komponenteve që ishin përditësuar në repository, jo tërë sistemin.
Për këtë, na duhej të ndanim gjithçka në dosje të veçanta.
Pas kësaj, shfaqej problemi se Docker-compose krijon për çdo dosje hapësirën e vet të rrjetit dhe nuk shkonte përbërësit fqinj.
Për të gjetur një zgjidhje, krijuam një rrjet manualisht në Docker. Në Docker-compose e përshkruam që për këtë projekt të përdoret ky rrjet.
Kështu, çdo komponent që fillon me këtë rrjet i sheh komponentet në pjesë të tjera të sistemit.
Problemi tjetër — është ndarja e staging midis disa projekteve.
Sepse që gjithçka të duket bukur dhe sa më afër production, është mirë të përdoret porta 80 ose 443, që përdoret në mënyrë universale në WEB.

Si e zgjidhëm këtë? Ne caktuam një Gitlab Runner për të gjitha projektet e mëdha.
Gitlab lejon të nisë disa Gitlab Runner të shpërndara, të cilat thjesht porositen ndërshe në rend të rastësishëm për të marrë të gjitha detyrat dhe për t'i ekzekutuar ato.
Për të shmangur kaosin, ne e kufizuam grupin tonë të projekteve në një Gitlab Runner, i cili për volumin tonë e menaxhon pa probleme.
E nxorrëm nginx-proxy në një skenar të veçantë nisjeje dhe në të përshkruam rrjetet e të gjitha projekteve.
Projekti ynë ka një rrjet, ndërsa balancuesi ka disa rrjete sipas emrave të projekteve. Ai mund të proksi në vazhdimësi sipas emrave të domain-eve.
Kërkesat tona vijnë përmes domain-it në portin 80 dhe drejtohen në grupin e kontejnerëve që shërbejnë për këtë domain.

Cilat ishin problemet e tjera? Kjo është se të gjitha kontejnerët në mënyrë default ekzekutohen si përdoruesi root. Ky root nuk është njëlloj si root i sistemit host.
Megjithatë, nëse hyni në kontejner, do të jetë root dhe skedari që krijojmë në këtë kontejner ka të drejtat root.
Nëse zhvilluesi ka hyrë në kontejner dhe ka bërë disa komanda që krijojnë skedarë, pastaj del nga kontejneri, ai ka një skedar në direktorinë e tij të punës, për të cilin nuk ka qasje.
Si mund ta zgjidhim këtë? Mund të shtojmë përdorues që do të jenë në kontejner.
Çfarë problemesh u paraqitën kur shtuam përdoruesin?
Duke krijuar përdorues, shpesh nuk përputhen ID e grupit (UID) dhe ID e përdoruesit (GID).
Për të zgjidhur këtë problem në kontejner, ne përdorim përdorues me ID 1000.
Në rastin tonë, kjo përputhet me faktin se praktikisht të gjithë zhvilluesit përdorin OS-në Ubuntu. Dhe në OS-në Ubuntu, përdoruesi i parë ka ID 1000.

Cilat janë planet tona?
Të rishikojmë dokumentacionin për Docker. Projekti po zhvillohet aktivisht, dokumentacioni ndryshon. Të dhënat që janë marrë dy-tre muaj më parë, tashmë po bëhen gradualisht të vjetra.
Disa probleme që kemi zgjidhur, është shumë e mundshme që tashmë janë zgjidhur me mjete standarde.
Ka aq shumë dëshirë të shkojmë përpara dhe të kalojmë drejtpërdrejt në orkestrim.
Një nga shembujt është mekanizmi i ndërtuar në Docker i quajtur Docker Swarm, i cili paraqitet nga kutia. Dëshirojmë të fillojmë diçka në prodhim në bazë të teknologjisë Docker Swarm.
Krijimi i konteinerëve e bën të komplikuar punën me logjet. Aktualisht, logjet janë të izoluar. Ato janë shpërndarë nëpër kontejnerë. Një nga detyrat është të sigurojmë qasje të lehtë në logjet përmes një ndërfaqeje web.

Burimi: habr.com
