Tagging bazat pe conținut în compilatorul werf: de ce și cum funcționează?

Tagging bazat pe conținut în compilatorul werf: de ce și cum funcționează?

werf — utilitarul nostru CLI GitOps open-source pentru construirea și livrarea aplicațiilor în Kubernetes. În versiunea v1.1 a fost introdusă o nouă funcționalitate în constructorul de imagini: etichetarea imaginilor bazată pe conținut sau content-based tagging. Până acum, schema tipică de etichetare în werf presupunea etichetarea imaginilor Docker în funcție de eticheta Git, ramura Git sau commit-ul Git. Dar toate aceste scheme au dezavantaje, care sunt complet rezolvate de noua strategie de etichetare. Detalii despre aceasta și de ce este atât de bună — mai jos.

Deploiearea unui set de microservicii dintr-un singur Git-repozitoriu

Se întâlnește adesea situația în care aplicația este împărțită în mai multe servicii mai mult sau mai puțin independente. Rapoartele acestor servicii pot avea loc independent: un sau mai multe servicii pot fi livrate simultan, în timp ce ceilalți trebuie să continue să funcționeze fără vreo modificare. Dar din perspectiva stocării codului și gestionării proiectului, este mai convenabil să păstrezi aceste servicii ale aplicației într-un singur repo.

Există situații în care serviciile sunt cu adevărat independente și nu sunt legate de o singură aplicație. În acest caz, acestea vor fi plasate în proiecte separate și livrarea lor se va realiza prin procese CI/CD separate în fiecare dintre proiecte.

Cu toate acestea, în realitate, dezvoltatorii adesea împart o aplicație unică în mai multe microservicii, dar a crea un repo și un proiect separat pentru fiecare... — este un evident overkill. Despre această situație va fi vorba mai departe: mai multe astfel de microservicii se află într-un singur repo de proiect și livrările au loc printr-un singur proces în CI/CD.

Etichetarea pe baza ramurii Git și etichetei Git

Presupunem că se folosește cea mai răspândită strategie de etichetare — tag-or-branch. Pentru ramurile Git, imaginile sunt etichetate cu numele ramurii; pentru o ramură, la un moment dat există o singură imagine publicată cu numele acestei ramuri. Pentru etichetele Git, imaginile sunt etichetate corespunzător cu numele etichetei.

Atunci când se creează o nouă etichetă Git — de exemplu, la lansarea unei noi versiuni — pentru toate imaginile proiectului din Docker Registry va fi creată o nouă etichetă Docker:

  • myregistry.org/myproject/frontend:v1.1.10
  • myregistry.org/myproject/myservice1:v1.1.10
  • myregistry.org/myproject/myservice2:v1.1.10
  • myregistry.org/myproject/myservice3:v1.1.10
  • myregistry.org/myproject/myservice4:v1.1.10
  • myregistry.org/myproject/myservice5:v1.1.10
  • myregistry.org/myproject/database:v1.1.10

Aceste noi nume de imagini sunt incluse prin șabloane Helm în configurația Kubernetes. La lansarea unui deployment cu comanda werf deploy , are loc actualizarea câmpului imagine în manifestele resurselor Kubernetes și reapăsa resursele corespunzătoare datorită schimbării numelui imaginii.

Problema: în cazul în care conținutul imaginii nu s-a schimbat de la anteriora versiune (tag-ul Git), ci doar tag-ul Docker, se produce o reapăsare a acestei aplicații și, în consecință, este posibil un anumit timp mort. Deși nu au fost motive reale pentru a efectua această reapăsare.

Ca urmare, cu schema actuală de versionare, trebuie să gestionăm mai multe repozitorii Git separate și apare problema organizării lansării acestor multiple repozitorii. În general, această schemă devine aglomerată și complexă. Ar fi mai bine să grupăm mai multe servicii într-un singur repozitoriu și să creăm astfel de tag-uri Docker pentru a evita reapăsarile inutile.

Versionarea pe baza commit-ului Git

În werf există, de asemenea, o strategie de versionare legată de commit-urile Git.

Commit-ul Git este un identificator al conținutului repozitoriului Git și depinde de istoricul modificărilor fișierelor din repozitoriu, deci pare logic să-l folosim pentru a versiona imaginile în Docker Registry.

Cu toate acestea, versionarea pe baza commit-ului Git are aceleași dezavantaje ca și pe baza ramurilor Git sau tag-urilor Git:

  • Ar putea fi creat un commit gol care nu schimbă fișiere, iar tag-ul Docker al imaginii va fi schimbat.
  • Ar putea fi creat un commit de tip merge care nu schimbă fișiere, iar tag-ul Docker al imaginii va fi schimbat.
  • Ar putea fi creat un commit care schimbă fișierele din Git, care nu sunt importate în imagine, iar tag-ul Docker al imaginii va fi din nou schimbat.

Versionarea pe baza numelui ramurii Git nu reflectă versiunea imaginii.

Există și o altă problemă legată de strategia de versionare pe baza ramurilor Git.

Versionarea pe baza numelui ramurii funcționează atâta timp cât commit-urile acestei ramuri sunt adunate secvențial în ordinea cronologică.

Dacă într-un sistem actual utilizatorul va lansa reconstructia unui vechi commit asociat cu o anumită ramură, atunci werf va suprascrie imaginea prin tag-ul Docker corespunzător cu noua versiune a imaginii pentru vechiul commit. Deployment-urile care folosesc acest tag riscă, de acum înainte, să efectueze pull pentru o altă versiune a imaginii în timpul repornirii pod-urilor, ceea ce ar putea duce la pierderea legăturii aplicației cu sistemul CI, provocând desincronizare.

În plus, în cazul unor push-uri succesive într-o ramură cu intervale scurte între ele, vechiul commit poate fi compilat mai târziu decât unul mai nou: versiunea veche a imaginii pierde tag-ul nou al ramurii Git. Aceste probleme pot fi rezolvate de sistemele CI/CD (de exemplu, în GitLab CI, un pipeline este lansat pentru seria de commits ultime). Totuși, nu toate sistemele susțin acest lucru și ar trebui să existe o modalitate mai fiabilă de a preveni o problemă atât de fundamentală.

Ce este tagging-ul bazat pe conținut?

Deci, ce este tagging-ul bazat pe conținut — etichetarea imaginilor în funcție de conținut.

Pentru a crea tag-uri Docker, nu sunt folosite primitivele Git-ului (ramură Git, tag Git...), ci o sumă de control asociată cu:

  • conținutul imaginii. Identificatorul-tag al imaginii reflectă conținutul acesteia. La compilarea unei noi versiuni, acest identificator nu se va schimba dacă fișierele din imagine nu au fost modificate;
  • istoria creării acestei imagini în Git. Imaginele asociate cu diferite ramuri Git și diferite istorii de compilare prin werf vor avea identificatori de tag-uri diferiți.

Ca atare, un astfel de identificator de tag este denumit semnătura stadiilor imaginii.

Fiecare imagine este compusă dintr-un set de etape: from, before-install, git-archive, install, imports-after-install, before-setup,… git-latest-patch ș.a.m.d. Fiecare etapă are un identificator care reflectă conținutul său — semnătura etapei (stage signature).

Imaginea finală, formată din aceste etape, este etichetată cu așa-numita semnătură a setului acestor etape — stages signature, — care este generalizatoare pentru toate etapele imaginii.

Fiecare imagine din configurație werf.yaml în general va avea o astfel de semnătură și, în consecință, un tag Docker.

Semnătura stadiilor rezolvă toate problemele menționate:

  • Este rezistentă la commit-urile Git goale.
  • Este rezistentă la commit-urile Git care modifică fișiere care nu sunt relevante pentru imagine.
  • Nu duce la problema de suprascriere a versiunii actuale a imaginii în timpul relansării compilărilor pentru vechile commit-uri Git din ramură.

Aceasta este acum strategia de etichetare recomandată și este utilizată implicit în werf pentru toate sistemele CI.

Cum să activați și să utilizați în werf

Opțiunea corespunzătoare a fost introdusă pentru comanda werf publish: --tag-by-stages-signature=true|false

În sistemul CI, strategia de etichetare este specificată prin comanda werf ci-env. Anterior, pentru aceasta se definea parametrul werf ci-env --tagging-strategy=tag-or-branch. Acum, dacă specificați werf ci-env --tagging-strategy=stages-signature sau nu specificați această opțiune, werf va folosi implicit strategia de etichetare stages-signature. Comanda werf ci-env va seta automat flag-urile necesare pentru comanda werf build-and-publish (sau werf publish), de aceea nu este nevoie să specificați opțiuni suplimentare pentru aceste comenzi.

De exemplu, comanda:

werf publish --stages-storage :local --images-repo registry.hello.com/web/core/system --tag-by-stages-signature

… poate crea următoarele imagini:

  • registry.hello.com/web/core/system/backend:4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d
  • registry.hello.com/web/core/system/frontend:f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6

Aici 4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d — aceasta este semnătura stadiilor imaginii backend, iar f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6 — semnătura stadiilor imaginii frontend.

Când utilizați funcții speciale werf_container_image și werf_container_env în șabloanele Helm nu este nevoie să schimbați nimic: aceste funcții vor genera automat numele corecte pentru imagini.

Exemplu de configurare în sistemul CI:

type multiwerf && source <(multiwerf use 1.1 beta)
type werf && source <(werf ci-env gitlab)
werf build-and-publish|deploy

Mai multe informații despre configurare sunt disponibile în documentație:

În concluzie

  • O nouă opțiune werf publish --tag-by-stages-signature=true|false.
  • Nouă valoare a opțiunii werf ci-env --tagging-strategy=stages-signature|tag-or-branch (dacă nu este specificată, va fi implicit stages-signature).
  • Dacă anterior a fost utilizată etichetarea pe baza comitelor Git (WERF_TAG_GIT_COMMIT sau opțiunea werf publish --tag-git-commit COMMIT), atunci este imperativ să schimbați strategia de etichetare stages-signature.
  • Proiectele noi ar trebui să fie imediat setate pe noul sistem de etichetare.
  • Proiectele vechi, când sunt migrate la werf 1.1, ar trebui să fie setate pe noul sistem de etichetare, dar vechiul tag-or-branch este în continuare suportat.

Etichetarea bazată pe conținut rezolvă toate problemele menționate în articol:

  • Stabilitatea numelui etichetei Docker față de comitele Git goale.
  • Stabilitatea numelui etichetei Docker față de comitele Git care modifică fișiere nerelevante pentru imagine.
  • Nu duce la o problemă de suprascriere a versiunii actuale a imaginii atunci când se repornesc construcțiile pentru commituri vechi de Git pentru ramurile Git.

Folosiți-l! Și nu uitați să ne vizitați pe GitHub, pentru a crea o problemă sau a găsi una existentă, a adăuga un vot, a crea un PR sau pur și simplu a observa dezvoltarea proiectului.

P.S.

Citiți și în blogul nostru:

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster