Kaj je GitOps?

Opomba. prevod: Po nedavni objavi material o metodah vlečenja in potiskanja v GitOps smo opazili zanimanje za ta model na splošno, vendar je bilo na to temo zelo malo publikacij v ruskem jeziku (na Habréju jih preprosto ni). Zato vam z veseljem ponujamo prevod drugega članka - čeprav pred skoraj enim letom! — iz podjetja Weaveworks, katerega vodja je skoval izraz »GitOps«. Besedilo pojasnjuje bistvo pristopa in ključne razlike od obstoječih.

Pred letom dni smo objavili uvod v GitOps. Takrat smo delili, kako je ekipa Weaveworks predstavila SaaS, ki je v celoti temeljil na Kubernetesu, in razvila niz predpisanih najboljših praks za uvajanje, upravljanje in spremljanje v izvornem okolju v oblaku.

Članek se je izkazal za priljubljenega. Drugi ljudje so začeli govoriti o GitOps in začeli objavljati nova orodja za git push, razvoj, skrivnosti, funkcije, stalno povezovanje in tako naprej. Pojavil se je na naši spletni strani številni publikacije in primeri uporabe GitOps. Toda nekateri imajo še vedno vprašanja. Kako se model razlikuje od tradicionalnega? infrastruktura kot koda in neprekinjeno dostavo (neprekinjena dostava)? Ali je treba uporabljati Kubernetes?

Kmalu smo ugotovili, da je potreben nov opis, ki ponuja:

  1. Veliko število primerov in zgodb;
  2. Posebna definicija GitOps;
  3. Primerjava s tradicionalno neprekinjeno dostavo.

V tem članku smo poskušali zajeti vse te teme. Zagotavlja posodobljen uvod v GitOps ter perspektivo razvijalca in CI/CD. Predvsem se osredotočamo na Kubernetes, čeprav je model mogoče posplošiti.

Spoznajte GitOps

Predstavljajte si Alice. Vodi Družinsko zavarovanje, ki ponuja zdravstveno, avtomobilsko, stanovanjsko in potovalno zavarovanje ljudem, ki so preveč zaposleni, da bi sami ugotovili podrobnosti pogodb. Njen posel se je začel kot stranski projekt, ko je Alice delala v banki kot podatkovna znanstvenica. Nekega dne je spoznala, da bi lahko uporabila napredne računalniške algoritme za učinkovitejšo analizo podatkov in oblikovanje zavarovalnih paketov. Investitorji so financirali projekt, zdaj pa njeno podjetje prinaša več kot 20 milijonov dolarjev na leto in hitro raste. Trenutno zaposluje 180 ljudi na različnih delovnih mestih. To vključuje tehnološko ekipo, ki razvija, vzdržuje spletno stran, bazo podatkov in analizira bazo strank. Ekipo 60 ljudi vodi Bob, tehnični direktor podjetja.

Bobova ekipa uvaja proizvodne sisteme v oblaku. Njihove osnovne aplikacije delujejo na GKE in izkoriščajo prednosti Kubernetesa v Google Cloudu. Poleg tega pri svojem delu uporabljajo različna podatkovna in analitična orodja.

Family Insurance se ni odločil za uporabo zabojnikov, ampak se je navdušil nad Dockerjem. Podjetje je kmalu odkrilo, da je GKE olajšal uvajanje gruč za testiranje novih funkcij. Jenkins za CI in Quay sta bila dodana za organizacijo registra vsebnikov, za Jenkins so bili napisani skripti, ki so potisnili nove vsebnike in konfiguracije v GKE.

Minilo je nekaj časa. Alice in Bob sta bila razočarana nad uspešnostjo njunega izbranega pristopa in njegovim vplivom na posel. Uvedba zabojnikov ni izboljšala produktivnosti toliko, kot je ekipa upala. Včasih bi se uvedbe zlomile in ni bilo jasno, ali so bile krive spremembe kode. Izkazalo se je tudi, da je težko slediti spremembam konfiguracije. Pogosto je bilo treba ustvariti novo gručo in vanjo preseliti aplikacije, saj je bilo to najlažji način za odpravo zmešnjave, v katero se je sistem zapletel. Alice se je bala, da se bo stanje z razvojem aplikacije poslabšalo (poleg tega se je pripravljal nov projekt, ki temelji na strojnem učenju). Bob je avtomatiziral večino dela in ni razumel, zakaj je cevovod še vedno nestabilen, se ni dobro prilagajal in občasno zahteva ročno posredovanje?

Potem so izvedeli za GitOps. Ta odločitev se je izkazala za točno to, kar so potrebovali za samozavesten korak naprej.

Alice in Bob že leta poslušata o Gitu, DevOps in infrastrukturi kot delovnih tokovih kode. Edinstveno pri GitOps je to, da prinaša niz najboljših praks – tako dokončnih kot normativnih – za izvajanje teh zamisli v kontekstu Kubernetesa. Ta tema večkrat dvignila, vključno z Weaveworks blog.

Family Insurance se odloči implementirati GitOps. Podjetje ima zdaj avtomatiziran model delovanja, ki je združljiv s Kubernetesom in združuje hitrost s stabilnostker oni:

  • ugotovili, da se je produktivnost ekipe podvojila, ne da bi se komu zmešalo;
  • prenehal streči skripte. Namesto tega se lahko zdaj osredotočijo na nove funkcije in izboljšajo inženirske metode – na primer uvedbo kanarčkov in izboljšanje testiranja;
  • izboljšali smo postopek uvajanja, tako da se redko pokvari;
  • dobil možnost obnovitve uvajanja po delnih okvarah brez ročnega posredovanja;
  • kupljeno rabljenoоVečje zaupanje v dostavne sisteme. Alice in Bob sta odkrila, da lahko ekipo razdelita na skupine mikrostoritev, ki delujejo vzporedno;
  • vsak dan lahko naredi 30-50 sprememb v projektu s prizadevanji vsake skupine in preizkusi nove tehnike;
  • v projekt je enostavno pritegniti nove razvijalce, ki imajo možnost, da v nekaj urah uvedejo posodobitve v produkcijo z uporabo zahtev za vleko;
  • enostavno opravijo revizijo v okviru SOC2 (za skladnost ponudnikov storitev z zahtevami za varno upravljanje podatkov; preberite več, npr. tukaj — pribl. prev.).

Kaj se je zgodilo?

GitOps je dvoje:

  1. Operativni model za Kubernetes in izvorni oblak. Zagotavlja niz najboljših praks za uvajanje, upravljanje in spremljanje kontejnerskih gruč in aplikacij. Elegantna definicija v obliki en diapozitiv od Luis Faceira:
  2. Pot do ustvarjanja okolja za upravljanje aplikacij, osredotočenega na razvijalce. Potek dela Git uporabljamo tako za operacije kot za razvoj. Upoštevajte, da ne gre samo za Git push, ampak za organiziranje celotnega nabora orodij CI/CD in UI/UX.

Nekaj ​​besed o Gitu

Če niste seznanjeni s sistemi za nadzor različic in potekom dela, ki temelji na Gitu, toplo priporočamo, da se o njih poučite. Delo z vejami in zahtevami za vleko se morda sprva zdi kot črna magija, vendar so koristi vredne truda. Tukaj dober članek začeti.

Kako deluje Kubernetes

V naši zgodbi sta se Alice in Bob obrnila na GitOps, potem ko sta nekaj časa delala s Kubernetesom. Dejansko je GitOps tesno povezan s Kubernetesom – je operativni model za infrastrukturo in aplikacije, ki temeljijo na Kubernetesu.

Kaj Kubernetes daje uporabnikom?

Tukaj je nekaj glavnih značilnosti:

  1. V modelu Kubernetes je vse mogoče opisati v deklarativni obliki.
  2. Strežnik Kubernetes API sprejme to deklaracijo kot vhod in nato nenehno poskuša gručo spraviti v stanje, opisano v deklaraciji.
  3. Izjave zadostujejo za opis in upravljanje najrazličnejših delovnih obremenitev – »aplikacij«.
  4. Posledično pride do sprememb v aplikaciji in gruči zaradi:
    • spremembe slik vsebnika;
    • spremembe deklarativne specifikacije;
    • napake v okolju - na primer zrušitve vsebnika.

Kubernetesove odlične konvergenčne zmogljivosti

Ko skrbnik spremeni konfiguracijo, jih Kubernetes orkestrator uporabi za gručo, dokler je njeno stanje se ne bo približal novi konfiguraciji. Ta model deluje za kateri koli vir Kubernetes in je razširljiv z definicijami virov po meri (CRD). Zato imajo uvedbe Kubernetes naslednje čudovite lastnosti:

  • Avtomatizacija: Posodobitve Kubernetes zagotavljajo mehanizem za avtomatizacijo postopka elegantne in pravočasne uporabe sprememb.
  • Konvergenca: Kubernetes bo še naprej poskušal posodobiti, dokler ne bo uspešen.
  • Idempotenca: Ponavljajoče se aplikacije konvergence vodijo do istega rezultata.
  • Determinizem: Ko je sredstev dovolj, je stanje posodobljene gruče odvisno le od želenega stanja.

Kako deluje GitOps

O Kubernetesu smo se naučili dovolj, da lahko razložimo, kako deluje GitOps.

Vrnimo se k ekipam za mikrostoritve Family Insurance. Kaj morajo običajno narediti? Oglejte si spodnji seznam (če se kateri od elementov na njem zdi nenavaden ali nepoznan, nehajte kritizirati in ostanite z nami). To so samo primeri delovnih tokov, ki temeljijo na Jenkinsu. Pri delu z drugimi orodji je veliko drugih procesov.

Glavna stvar je, da vidimo, da se vsaka posodobitev konča s spremembami konfiguracijskih datotek in repozitorijev Git. Te spremembe v Gitu povzročijo, da "operater GitOps" posodobi gručo:

1. Delovni proces: "Jenkins build - glavna veja".
Seznam opravil:

  • Jenkins potisne označene slike v Quay;
  • Jenkins potisne konfiguracijske in Helmove grafikone v glavno vedro za shranjevanje;
  • Funkcija oblaka kopira konfiguracijo in grafikone iz glavnega vedra za shranjevanje v glavno skladišče Git;
  • Operater GitOps posodobi gručo.

2. Jenkinsova zgradba – izdaja ali hitri popravek:

  • Jenkins potisne neoznačene slike v Quay;
  • Jenkins potisne konfiguracijske in Helmove grafikone v uprizoritveno vedro za shranjevanje;
  • Funkcija oblaka kopira konfiguracijo in grafikone iz uprizoritvenega pomnilniškega vedra v uprizoritveni repozitorij Git;
  • Operater GitOps posodobi gručo.

3. Jenkinsova gradnja – razvoj ali predstavljanje veje:

  • Jenkins potisne neoznačene slike v Quay;
  • Jenkins potisne konfiguracijske in Helmove grafikone v razvojno vedro za shranjevanje;
  • Funkcija oblaka kopira konfiguracijo in grafikone iz vedra za shranjevanje za razvoj v repozitorij za razvoj Git;
  • Operater GitOps posodobi gručo.

4. Dodajanje novega odjemalca:

  • Upravitelj ali skrbnik (LCM/ops) pokliče Gradle, da najprej uvede in konfigurira izravnalnike obremenitve omrežja (NLB);
  • LCM/ops objavi novo konfiguracijo, da pripravi uvajanje za posodobitve;
  • Operater GitOps posodobi gručo.

Kratek opis GitOps

  1. Opišite želeno stanje celotnega sistema z uporabo deklarativnih specifikacij za vsako okolje (v naši zgodbi Bobova ekipa definira celotno konfiguracijo sistema v Gitu).
    • Repozitorij Git je edini vir resnice glede želenega stanja celotnega sistema.
    • Vse spremembe želenega stanja se izvedejo s potrditvami v Gitu.
    • Vsi želeni parametri gruče so opazni tudi v sami gruči. Na ta način lahko ugotovimo, ali sovpadata (konvergirata, zbližati) ali se razlikujejo (razhajajo se, razhajajo) želena in opazovana stanja.
  2. Če se želeno in opazovano stanje razlikujeta, potem:
    • Obstaja konvergenčni mehanizem, ki prej ali slej samodejno sinhronizira ciljno in opazovano stanje. Znotraj gruče to počne Kubernetes.
    • Postopek se začne takoj z opozorilom »sprememba izvedena«.
    • Po določenem nastavljivem časovnem obdobju se lahko pošlje opozorilo "diff", če sta stanja različna.
  3. Na ta način vse potrditve v Gitu povzročijo preverljive in idempotentne posodobitve gruče.
    • Povratek nazaj je konvergenca v predhodno želeno stanje.
  4. Konvergenca je dokončna. Na njegov pojav kažejo:
    • Določeno časovno obdobje ni opozoril na razlike.
    • "konvergentno" opozorilo (npr. webhook, povratni dogodek Git).

Kaj je divergenca?

Ponovimo še enkrat: vse želene lastnosti gruče morajo biti opazne v sami gruči.

Nekaj ​​primerov razhajanj:

  • Sprememba konfiguracijske datoteke zaradi združevanja vej v Git.
  • Sprememba konfiguracijske datoteke zaradi potrditve Git, ki jo je naredil odjemalec GUI.
  • Večkratne spremembe želenega stanja zaradi PR v Gitu, ki jim sledi izgradnja slike vsebnika in spremembe konfiguracije.
  • Sprememba stanja gruče zaradi napake, konflikta virov, ki povzroči "slabo vedenje", ali preprosto naključnega odstopanja od prvotnega stanja.

Kakšen je mehanizem konvergence?

Nekaj ​​primerov:

  • Za vsebnike in gruče konvergenčni mehanizem zagotavlja Kubernetes.
  • Isti mehanizem je mogoče uporabiti za upravljanje aplikacij in dizajnov, ki temeljijo na Kubernetesu (kot sta Istio in Kubeflow).
  • Zagotavlja mehanizem za upravljanje operativne interakcije med Kubernetesom, repozitoriji slik in Gitom Operater GitOps Weave Flux, ki je del Weave Cloud.
  • Za osnovne stroje mora biti konvergenčni mehanizem deklarativen in avtonomen. Iz lastnih izkušenj lahko to trdimo Terraform najbližje tej definiciji, vendar še vedno zahteva človeški nadzor. V tem smislu GitOps razširja tradicijo infrastrukture kot kode.

GitOps združuje Git z odličnim konvergenčnim motorjem Kubernetes, da zagotovi model za izkoriščanje.

GitOps nam omogoča, da rečemo: Samo tiste sisteme, ki jih je mogoče opisati in opazovati, je mogoče avtomatizirati in nadzorovati.

GitOps je namenjen celotnemu izvornemu skladu v oblaku (na primer Terraform itd.)

GitOps ni samo Kubernetes. Želimo, da se celoten sistem vodi deklarativno in uporablja konvergenco. S celotnim sistemom mislimo na zbirko okolij, ki delujejo s Kubernetesom - na primer "dev cluster 1", "production" itd. Vsako okolje vključuje stroje, gruče, aplikacije, kot tudi vmesnike za zunanje storitve, ki zagotavljajo podatke, spremljanje in itd.

Upoštevajte, kako pomemben je Terraform za problem zagona v tem primeru. Kubernetes je treba nekje namestiti in uporaba Terraforma pomeni, da lahko uporabimo iste poteke dela GitOps za ustvarjanje nadzorne plasti, ki podpira Kubernetes in aplikacije. To je koristna najboljša praksa.

Močan poudarek je na uporabi konceptov GitOps na slojih na vrhu Kubernetesa. Trenutno obstajajo rešitve tipa GitOps za Istio, Helm, Ksonnet, OpenFaaS in Kubeflow ter na primer za Pulumi, ki ustvarjajo plast za razvoj aplikacij za native v oblaku.

Kubernetes CI/CD: primerjava GitOps z drugimi pristopi

Kot rečeno, je GitOps dve stvari:

  1. Zgoraj opisan operativni model za Kubernetes in izvorni oblak.
  2. Pot do okolja za upravljanje aplikacij, osredotočenega na razvijalce.

Za mnoge je GitOps predvsem potek dela, ki temelji na potiskanju Git. Tudi mi ga imamo radi. Vendar to še ni vse: poglejmo zdaj cevovode CI/CD.

GitOps omogoča neprekinjeno uvajanje (CD) za Kubernetes

GitOps ponuja mehanizem neprekinjenega uvajanja, ki odpravlja potrebo po ločenih »sistemih za upravljanje uvajanja«. Kubernetes opravi vse delo namesto vas.

  • Posodabljanje aplikacije zahteva posodobitev v Gitu. To je posodobitev transakcije na želeno stanje. "Uvajanje" nato izvede Kubernetes sam znotraj gruče na podlagi posodobljenega opisa.
  • Zaradi narave delovanja Kubernetesa so te posodobitve konvergentne. To zagotavlja mehanizem za neprekinjeno uvajanje, pri katerem so vse posodobitve atomske.
  • Opomba: Weave Cloud ponuja operater GitOps, ki integrira Git in Kubernetes ter omogoča izvedbo CD z usklajevanjem želenega in trenutnega stanja gruče.

Brez kubectla in skriptov

Izogibajte se uporabi Kubectl za posodabljanje vaše gruče, predvsem pa se izogibajte uporabi skriptov za združevanje ukazov kubectl. Namesto tega lahko s cevovodom GitOps uporabnik posodobi svojo gručo Kubernetes prek Gita.

Prednosti vključujejo:

  1. Prav. Skupino posodobitev je mogoče uporabiti, konvergirati in končno potrditi, kar nas približa cilju atomske uvedbe. Nasprotno pa uporaba skriptov ne zagotavlja nobenega jamstva za konvergenco (več o tem spodaj).
  2. varnost. Citiranje Kelsey Hightower: "Omejite dostop do svoje gruče Kubernetes na orodja za avtomatizacijo in skrbnike, ki so odgovorni za odpravljanje napak ali vzdrževanje." Poglej tudi moja objava o varnosti in skladnosti s tehničnimi specifikacijami ter članek o vdoru v Homebrew s krajo poverilnic iz malomarno napisanega Jenkinsovega scenarija.
  3. Uporabniška izkušnja. Kubectl razkriva mehaniko objektnega modela Kubernetes, ki je precej zapletena. V idealnem primeru bi morali uporabniki komunicirati s sistemom na višji ravni abstrakcije. Tu se bom spet skliceval na Kelsey in priporočam ogled tak življenjepis.

Razlika med CI in CD

GitOps izboljšuje obstoječe modele CI/CD.

Sodoben strežnik CI je orodje za orkestracijo. Predvsem je orodje za orkestriranje cevovodov CI. Ti vključujejo gradnjo, testiranje, združevanje v deblo itd. Strežniki CI avtomatizirajo upravljanje kompleksnih večstopenjskih cevovodov. Pogosta skušnjava je skript niza posodobitev Kubernetes in ga zagnati kot del cevovoda za potiskanje sprememb v gručo. Dejansko to počnejo številni strokovnjaki. Vendar to ni optimalno in tukaj je razlog.

CI je treba uporabiti za pošiljanje posodobitev v deblo, gruča Kubernetes pa bi se morala spremeniti na podlagi teh posodobitev za notranje upravljanje CD-ja. To imenujemo potegni model za CD, za razliko od modela CI push. CD je del izvedbeno orkestracijo.

Zakaj strežniki CI ne bi smeli izvajati CD-jev prek neposrednih posodobitev v Kubernetesu

Ne uporabljajte strežnika CI za usklajevanje neposrednih posodobitev Kubernetesa kot niza opravil CI. To je anti-vzorec, o katerem govorimo že povedano na svojem blogu.

Vrnimo se k Alice in Bobu.

S kakšnimi težavami so se srečevali? Bobov strežnik CI uveljavi spremembe v gruči, vendar če se med postopkom zruši, Bob ne bo vedel, v kakšnem stanju je (ali bi morala biti) gruča ali kako to popraviti. Enako velja v primeru uspeha.

Predpostavimo, da je Bobova ekipa zgradila novo sliko in nato popravila svoje uvedbe za uvedbo slike (vse iz cevovoda CI).

Če se slika normalno gradi, vendar cevovod ne uspe, bo morala ekipa ugotoviti:

  • Ali je posodobitev uvedena?
  • Ali lansiramo novo gradnjo? Ali bo to povzročilo nepotrebne stranske učinke – z možnostjo dveh gradenj iste nespremenljive slike?
  • Ali naj počakamo na naslednjo posodobitev, preden zaženemo gradnjo?
  • Kaj točno je šlo narobe? Katere korake je treba ponoviti (in katere je varno ponoviti)?

Vzpostavitev poteka dela, ki temelji na Gitu, ne zagotavlja, da Bobova ekipa ne bo naletela na te težave. Še vedno lahko naredijo napako s pritiskom na objavo, oznako ali kakšnim drugim parametrom; vendar je ta pristop še vedno veliko bližje eksplicitnemu pristopu vse ali nič.

Če povzamemo, tukaj je razlog, zakaj se strežniki CI ne bi smeli ukvarjati s CD-jem:

  • Posodobitveni skripti niso vedno deterministični; V njih je enostavno delati napake.
  • Strežniki CI ne konvergirajo k deklarativnemu modelu gruč.
  • Težko je zagotoviti idempotenco. Uporabniki morajo razumeti globoko semantiko sistema.
  • Po delni okvari je težje okrevati.

Opomba o Helmu: Če želite uporabljati Helm, priporočamo, da ga kombinirate z operaterjem GitOps, kot je npr. Flux-Helm. To bo pomagalo zagotoviti konvergenco. Helm sam ni niti determinističen niti atomski.

GitOps kot najboljši način za implementacijo neprekinjene dostave za Kubernetes

Ekipa Alice in Boba implementira GitOps in odkrije, da je postalo veliko lažje delati s programskimi izdelki, ohranjati visoko zmogljivost in stabilnost. Zaključimo ta članek z ilustracijo, ki prikazuje, kako izgleda njihov novi pristop. Ne pozabite, da večinoma govorimo o aplikacijah in storitvah, vendar se GitOps lahko uporablja za upravljanje celotne platforme.

Operacijski model za Kubernetes

Oglejte si naslednji diagram. Predstavlja Git in repozitorij slik vsebnika kot skupna vira za dva orkestrirana življenjska cikla:

  • Neprekinjen integracijski cevovod, ki bere in piše datoteke v Git ter lahko posodobi repozitorij slik vsebnika.
  • Cevovod Runtime GitOps, ki združuje uvajanje z upravljanjem in opazovanjem. Bere in piše datoteke v Git in lahko prenaša slike vsebnikov.

Katere so glavne ugotovitve?

  1. Ločitev skrbi: Upoštevajte, da lahko oba cevovoda komunicirata samo s posodobitvijo Gita ali repozitorija slik. Z drugimi besedami, med CI in izvajalnim okoljem obstaja požarni zid. Imenujemo ga "požarni zid nespremenljivosti" (požarni zid nespremenljivosti), saj vse posodobitve repozitorija ustvarijo nove različice. Za več informacij o tej temi glejte diapozitive 72-87 to predstavitev.
  2. Uporabite lahko kateri koli strežnik CI in Git: GitOps deluje s katero koli komponento. Še naprej lahko uporabljate svoje najljubše strežnike CI in Git, repozitorije slik in testne zbirke. Skoraj vsa druga orodja za neprekinjeno dostavo na trgu zahtevajo lasten strežnik CI/Git ali repozitorij slik. To lahko postane omejevalni dejavnik pri razvoju izvornega oblaka. Z GitOps lahko uporabljate znana orodja.
  3. Dogodki kot integracijsko orodje: Takoj ko so podatki v Gitu posodobljeni, Weave Flux (ali operater Weave Cloud) obvesti čas izvajanja. Kadarkoli Kubernetes sprejme nabor sprememb, se Git posodobi. To zagotavlja preprost integracijski model za organiziranje delovnih tokov za GitOps, kot je prikazano spodaj.

Zaključek

GitOps zagotavlja močna jamstva za posodobitev, ki jih zahteva vsako sodobno orodje CI/CD:

  • avtomatizacija;
  • konvergenca;
  • idempotenca;
  • determinizem.

To je pomembno, ker ponuja operativni model za domače razvijalce v oblaku.

  • Tradicionalna orodja za upravljanje in spremljanje sistemov so povezana z operativnimi ekipami, ki delujejo v runbooku (nabor rutinskih postopkov in operacij – pribl. prev.), vezano na določeno uvedbo.
  • Pri izvornem upravljanju v oblaku so orodja za opazovanje najboljši način za merjenje rezultatov uvajanja, tako da se lahko razvojna ekipa hitro odzove.

Predstavljajte si veliko gruč, raztresenih po različnih oblakih, in veliko storitev s svojimi ekipami in načrti uvajanja. GitOps ponuja merilno nespremenljiv model za upravljanje vsega tega izobilja.

PS od prevajalca

Preberite tudi na našem blogu:

V anketi lahko sodelujejo samo registrirani uporabniki. Prijaviti se, prosim.

Ali ste vedeli za GitOps, preden sta se ta dva prevoda pojavila na Habréju?

  • Ja, vse sem vedel

  • Le površno

  • Št

Glasovalo je 35 uporabnikov. 10 uporabnikov se je vzdržalo.

Vir: www.habr.com

Dodaj komentar