Problema curățării „inteligente” a imaginilor containerelor și soluția acesteia în werf

Problema curățării „inteligente” a imaginilor containerelor și soluția acesteia în werf

Articolul discută problemele de curățare a imaginilor care se acumulează în registrele containerelor (Docker Registry și analogii săi) în realitățile conductelor moderne CI/CD pentru aplicațiile native cloud livrate Kubernetes. Sunt prezentate principalele criterii de relevanță a imaginilor și dificultățile rezultate în automatizarea curățeniei, economisirea spațiului și satisfacerea nevoilor echipelor. În cele din urmă, folosind exemplul unui anumit proiect Open Source, vă vom spune cum pot fi depășite aceste dificultăți.

Introducere

Numărul de imagini dintr-un registru de containere poate crește rapid, ocupând mai mult spațiu de stocare și crescând astfel semnificativ costul acestuia. Pentru a controla, limita sau menține creșterea acceptabilă a spațiului ocupat în registru, se acceptă:

  1. utilizați un număr fix de etichete pentru imagini;
  2. curățați imaginile într-un fel.


Prima limitare este uneori acceptabilă pentru echipele mici. Dacă dezvoltatorii au suficiente etichete permanente (latest, main, test, boris etc.), registrul nu se va umfla în dimensiune și pentru o lungă perioadă de timp nu va trebui să vă gândiți deloc la curățarea acestuia. La urma urmei, toate imaginile irelevante sunt șterse și pur și simplu nu mai rămâne de lucru pentru curățare (totul este făcut de un gunoi obișnuit).

Cu toate acestea, această abordare limitează foarte mult dezvoltarea și este rareori aplicabilă proiectelor moderne CI/CD. O parte integrantă a dezvoltării a fost automatizare, care vă permite să testați, să implementați și să furnizați noi funcționalități utilizatorilor mult mai rapid. De exemplu, în toate proiectele noastre, o conductă CI este creată automat cu fiecare comitere. În ea, imaginea este asamblată, testată, difuzată pe diverse circuite Kubernetes pentru depanare și verificări rămase, iar dacă totul este bine, modificările ajung la utilizatorul final. Și aceasta nu mai este știință rachetă, ci o întâmplare de zi cu zi pentru mulți - cel mai probabil pentru dvs., deoarece citiți acest articol.

Deoarece repararea erorilor și dezvoltarea de noi funcționalități se realizează în paralel, iar lansările pot fi efectuate de mai multe ori pe zi, este evident că procesul de dezvoltare este însoțit de un număr semnificativ de comiteri, ceea ce înseamnă un număr mare de imagini în registru. Ca urmare, se pune problema organizării curățării eficiente a registrului, adică. eliminarea imaginilor irelevante.

Dar cum poți stabili dacă o imagine este relevantă?

Criterii de relevanță a imaginii

În marea majoritate a cazurilor, criteriile principale vor fi:

1. Prima (cea mai evidentă și cea mai critică dintre toate) sunt imaginile care utilizat în prezent în Kubernetes. Îndepărtarea acestor imagini poate duce la costuri semnificative ale perioadei de nefuncționare a producției (de exemplu, imaginile pot fi necesare pentru replicare) sau poate anula eforturile echipei de depanare pe oricare dintre bucle. (Din acest motiv am făcut chiar și un special Exportator Prometheus, care urmărește absența unor astfel de imagini în orice cluster Kubernetes.)

2. Al doilea (mai puțin evident, dar și foarte important și din nou se referă la exploatare) - imagini care necesar pentru rollback în cazul detectării unor probleme grave în versiunea actuală. De exemplu, în cazul lui Helm, acestea sunt imagini care sunt folosite în versiunile salvate ale versiunii. (Apropo, în mod implicit în Helm, limita este de 256 de revizuiri, dar este puțin probabil ca cineva să aibă nevoie cu adevărat să salveze astfel de un număr mare de versiuni?..) La urma urmei, noi, în special, stocăm versiuni pentru a le putea folosi mai târziu, adică. „revenire” la ei dacă este necesar.

3. Al treilea - nevoile dezvoltatorului: Toate imaginile care au legătură cu munca lor curentă. De exemplu, dacă luăm în considerare un PR, atunci este logic să lăsăm o imagine corespunzătoare ultimului comit și, să zicem, precedentului: astfel, dezvoltatorul poate reveni rapid la orice sarcină și poate lucra cu cele mai recente modificări.

4. În al patrulea rând - imagini care corespund versiunilor aplicației noastre, adică sunt produsul final: v1.0.0, 20.04.01/XNUMX/XNUMX, sierra etc.

NB: Criteriile definite aici au fost formulate pe baza experienței de interacțiune cu zeci de echipe de dezvoltare din diferite companii. Cu toate acestea, desigur, în funcție de specificul proceselor de dezvoltare și de infrastructura utilizată (de exemplu, Kubernetes nu este utilizat), aceste criterii pot diferi.

Eligibilitate și soluții existente

Serviciile populare cu registre de containere, de regulă, oferă propriile politici de curățare a imaginilor: în ele puteți defini condițiile în care o etichetă este eliminată din registru. Cu toate acestea, aceste condiții sunt limitate de parametri precum nume, timpul de creare și numărul de etichete*.

* Depinde de implementările specifice ale registrului containerului. Am luat în considerare posibilitățile următoarelor soluții: Azure CR, Docker Hub, ECR, GCR, GitHub Packages, GitLab Container Registry, Harbour Registry, JFrog Artifactory, Quay.io - din septembrie'2020.

Acest set de parametri este suficient pentru a satisface al patrulea criteriu - adică pentru a selecta imagini care corespund versiunilor. Cu toate acestea, pentru toate celelalte criterii, trebuie să alegeți un fel de soluție de compromis (o politică mai dură sau, dimpotrivă, mai îngăduitoare) - în funcție de așteptări și capacități financiare.

De exemplu, al treilea criteriu - legat de nevoile dezvoltatorilor - poate fi rezolvat prin organizarea proceselor în cadrul echipelor: denumirea specifică a imaginilor, menținerea unor liste speciale de permise și acorduri interne. Dar, în cele din urmă, trebuie încă să fie automatizat. Și dacă capacitățile soluțiilor gata făcute nu sunt suficiente, trebuie să faci ceva propriu.

Situația cu primele două criterii este similară: nu pot fi satisfăcute fără a primi date de la un sistem extern - cel în care sunt implementate aplicații (în cazul nostru, Kubernetes).

Ilustrație a fluxului de lucru în Git

Să presupunem că lucrezi așa ceva în Git:

Problema curățării „inteligente” a imaginilor containerelor și soluția acesteia în werf

Pictograma cu un cap în diagramă indică imagini de container care sunt implementate în prezent în Kubernetes pentru orice utilizator (utilizatori finali, testeri, manageri etc.) sau sunt folosite de dezvoltatori pentru depanare și în scopuri similare.

Ce se întâmplă dacă politicile de curățare permit doar păstrarea imaginilor (nu șterse) după numele etichetelor date?

Problema curățării „inteligente” a imaginilor containerelor și soluția acesteia în werf

Evident, un astfel de scenariu nu va face pe nimeni fericit.

Ce se va schimba dacă politicile permit ca imaginile să nu fie șterse? conform unui interval de timp dat/număr de ultime comiteri?

Problema curățării „inteligente” a imaginilor containerelor și soluția acesteia în werf

Rezultatul a devenit mult mai bun, dar este încă departe de ideal. La urma urmei, mai avem dezvoltatori care au nevoie de imagini în registry (sau chiar implementate în K8s) pentru a depana erori...

Pentru a rezuma situația actuală a pieței: funcțiile disponibile în registrele de containere nu oferă suficientă flexibilitate la curățare, iar motivul principal pentru aceasta este nicio modalitate de a interacționa cu lumea exterioară. Se pare că echipele care necesită o astfel de flexibilitate sunt forțate să implementeze în mod independent ștergerea imaginilor „din exterior”, folosind API-ul Docker Registry (sau API-ul nativ al implementării corespunzătoare).

Cu toate acestea, căutam o soluție universală care să automatizeze curățarea imaginilor pentru diferite echipe folosind registre diferite...

Calea noastră către curățarea universală a imaginii

De unde această nevoie? Cert este că nu suntem un grup separat de dezvoltatori, ci o echipă care îi deservește pe mulți dintre ei simultan, ajutând la rezolvarea cuprinzătoare a problemelor CI/CD. Și principalul instrument tehnic pentru aceasta este utilitarul Open Source werf. Particularitatea sa este că nu îndeplinește o singură funcție, ci însoțește procesele continue de livrare în toate etapele: de la asamblare până la implementare.

Publicarea imaginilor în registru* (imediat după ce sunt construite) este o funcție evidentă a unui astfel de utilitar. Și deoarece imaginile sunt plasate acolo pentru depozitare, atunci - dacă stocarea dvs. nu este nelimitată - trebuie să fiți responsabil pentru curățarea lor ulterioară. Cum am obținut succesul în acest sens, satisfăcând toate criteriile specificate, va fi discutat în continuare.

* Deși registrele în sine pot fi diferite (Docker Registry, GitLab Container Registry, Harbour etc.), utilizatorii lor se confruntă cu aceleași probleme. Soluția universală în cazul nostru nu depinde de implementarea registrului, deoarece rulează în afara registrelor și oferă același comportament pentru toată lumea.

Deși folosim werf ca exemplu de implementare, sperăm că abordările folosite vor fi utile altor echipe care se confruntă cu dificultăți similare.

Deci ne-am ocupat extern implementarea unui mecanism de curățare a imaginilor - în locul acelor capabilități care sunt deja încorporate în registrele pentru containere. Primul pas a fost utilizarea API-ului Docker Registry pentru a crea aceleași politici primitive pentru numărul de etichete și ora creării lor (menționate mai sus). Adăugat la ei lista de permisiuni bazată pe imaginile utilizate în infrastructura implementată, adică Kubernetes. Pentru acesta din urmă, a fost suficient să utilizați API-ul Kubernetes pentru a itera toate resursele implementate și a obține o listă de valori image.

Această soluție banală a rezolvat cea mai critică problemă (criteriul nr. 1), dar a fost doar începutul călătoriei noastre de îmbunătățire a mecanismului de curățare. Următorul pas – și mult mai interesant – a fost decizia asociați imaginile publicate cu istoria Git.

Scheme de etichetare

Pentru început, am ales o abordare în care imaginea finală ar trebui să stocheze informațiile necesare pentru curățare și am construit procesul pe scheme de etichetare. La publicarea unei imagini, utilizatorul a selectat o anumită opțiune de etichetare (git-branch, git-commit sau git-tag) și a folosit valoarea corespunzătoare. În sistemele CI, aceste valori au fost setate automat pe baza variabilelor de mediu. De fapt imaginea finală a fost asociată cu o anumită primitivă Git, stocând datele necesare curățării în etichete.

Această abordare a dus la un set de politici care au permis ca Git să fie folosit ca sursă unică de adevăr:

  • La ștergerea unei ramuri/etichete în Git, imaginile asociate din registru au fost șterse automat.
  • Numărul de imagini asociate cu etichetele Git și commit-urile ar putea fi controlat de numărul de etichete utilizate în schema selectată și momentul la care a fost creat commit-ul asociat.

În general, implementarea rezultată a satisfăcut nevoile noastre, dar ne-a așteptat în curând o nouă provocare. Faptul este că în timp ce folosim scheme de etichetare bazate pe primitive Git, am întâlnit o serie de neajunsuri. (Deoarece descrierea lor depășește scopul acestui articol, toată lumea se poate familiariza cu detaliile aici.) Prin urmare, după ce am decis să trecem la o abordare mai eficientă a etichetării (etichetarea bazată pe conținut), a trebuit să reconsiderăm implementarea curățării imaginilor.

Algoritm nou

De ce? Cu etichetarea bazată pe conținut, fiecare etichetă poate satisface mai multe comitări în Git. Când curățați imaginile, nu vă mai puteți presupune numai din commit-ul în care noua etichetă a fost adăugată în registry.

Pentru noul algoritm de curățare, s-a decis să se îndepărteze de schemele de etichetare și să se construiască proces meta-imagine, fiecare dintre ele stochează o grămadă de:

  • commit-ul pe care a fost efectuată publicarea (nu contează dacă imaginea a fost adăugată, schimbată sau a rămas aceeași în registrul containerelor);
  • și identificatorul nostru intern corespunzător imaginii asamblate.

Cu alte cuvinte, a fost furnizat conectarea etichetelor publicate cu commit-uri în Git.

Configurare finală și algoritm general

La configurarea curățării, utilizatorii au acum acces la politicile care selectează imaginile curente. Fiecare astfel de politică este definită:

  • multe referințe, adică Etichete Git sau ramuri Git care sunt utilizate în timpul scanării;
  • și limita imaginilor căutate pentru fiecare referință din set.

Pentru a ilustra, așa a început să arate configurația implicită a politicii:

cleanup:
  keepPolicies:
  - references:
      tag: /.*/
      limit:
        last: 10
  - references:
      branch: /.*/
      limit:
        last: 10
        in: 168h
        operator: And
    imagesPerReference:
      last: 2
      in: 168h
      operator: And
  - references:  
      branch: /^(main|staging|production)$/
    imagesPerReference:
      last: 10

Această configurație conține trei politici care respectă următoarele reguli:

  1. Salvați imaginea pentru ultimele 10 etichete Git (după data creării etichetei).
  2. Salvați nu mai mult de 2 imagini publicate în ultima săptămână pentru cel mult 10 fire cu activitate în ultima săptămână.
  3. Salvați 10 imagini pentru ramuri main, staging и production.

Algoritmul final se rezumă la următorii pași:

  • Preluarea manifestelor din registrul containerului.
  • Excluzând imaginile utilizate în Kubernetes, deoarece Le-am preselectat deja prin sondajul API-ului K8s.
  • Scanarea istoricului Git și excluderea imaginilor pe baza politicilor specificate.
  • Eliminarea imaginilor rămase.

Revenind la ilustrația noastră, iată ce se întâmplă cu werf:

Problema curățării „inteligente” a imaginilor containerelor și soluția acesteia în werf

Cu toate acestea, chiar dacă nu utilizați werf, o abordare similară a curățării avansate a imaginii - într-o implementare sau alta (în funcție de abordarea preferată a etichetării imaginilor) - poate fi aplicată și altor sisteme/utilități. Pentru a face acest lucru, este suficient să vă amintiți problemele care apar și să găsiți acele oportunități în stiva dvs. care vă permit să integrați soluția lor cât mai ușor posibil. Sperăm că drumul pe care l-am parcurs vă va ajuta să vă uitați la cazul dumneavoastră particular cu detalii și gânduri noi.

Concluzie

  • Mai devreme sau mai târziu, majoritatea echipelor se confruntă cu problema depășirii registrului.
  • Când căutați soluții, este mai întâi necesar să determinați criteriile de relevanță a imaginii.
  • Instrumentele oferite de serviciile populare de înregistrare a containerelor vă permit să organizați o curățare foarte simplă, care nu ține cont de „lumea exterioară”: imaginile utilizate în Kubernetes și particularitățile fluxurilor de lucru ale echipei.
  • Un algoritm flexibil și eficient trebuie să înțeleagă procesele CI/CD și să funcționeze nu numai cu datele de imagine Docker.

PS

Citește și pe blogul nostru:

Sursa: www.habr.com

Adauga un comentariu