Problemet med "smart" rengjøring av beholderbilder og løsningen på det i werf

Problemet med "smart" rengjøring av beholderbilder og løsningen på det i werf

Artikkelen diskuterer problemene med å rense bilder som akkumuleres i containerregistre (Docker Registry og dets analoger) i realitetene til moderne CI/CD-rørledninger for skybaserte applikasjoner levert til Kubernetes. Hovedkriteriene for relevansen til bilder og de resulterende vanskelighetene med å automatisere rengjøring, spare plass og møte behovene til team er gitt. Til slutt, ved å bruke eksempelet på et spesifikt åpen kildekode-prosjekt, vil vi fortelle deg hvordan disse vanskelighetene kan overvinnes.

Innledning

Antall bilder i et beholderregister kan vokse raskt, ta opp mer lagringsplass og dermed øke kostnadene betydelig. For å kontrollere, begrense eller opprettholde akseptabel vekst av plass okkupert i registeret, er det akseptert:

  1. bruk et fast antall tagger for bilder;
  2. rense bildene på en eller annen måte.


Den første begrensningen er noen ganger akseptabel for små team. Hvis utviklere har nok permanente tagger (latest, main, test, boris etc.), vil ikke registeret svulme i størrelse, og i lang tid trenger du ikke tenke på å rense det i det hele tatt. Tross alt blir alle irrelevante bilder slettet, og det er rett og slett ikke noe arbeid igjen for rengjøring (alt gjøres av en vanlig søppeloppsamler).

Denne tilnærmingen begrenser imidlertid utviklingen sterkt og er sjelden anvendelig for moderne CI/CD-prosjekter. En integrert del av utviklingen var automasjon, som lar deg teste, distribuere og levere ny funksjonalitet til brukere mye raskere. For eksempel, i alle våre prosjekter, opprettes en CI-pipeline automatisk med hver forpliktelse. I den er bildet satt sammen, testet, rullet ut til ulike Kubernetes-kretser for feilsøking og gjenværende kontroller, og hvis alt er bra, når endringene sluttbrukeren. Og dette er ikke lenger rakettvitenskap, men en hverdagslig foreteelse for mange - mest sannsynlig for deg, siden du leser denne artikkelen.

Siden fiksing av feil og utvikling av ny funksjonalitet utføres parallelt, og utgivelser kan utføres flere ganger om dagen, er det åpenbart at utviklingsprosessen er ledsaget av et betydelig antall forpliktelser, noe som betyr et stort antall bilder i registeret. Som et resultat oppstår spørsmålet om å organisere effektiv rengjøring av registeret, dvs. fjerning av irrelevante bilder.

Men hvordan avgjør du i det hele tatt om et bilde er relevant?

Kriterier for relevansen til bildet

I de aller fleste tilfeller vil hovedkriteriene være:

1. Den første (den mest åpenbare og mest kritiske av alle) er bildene som brukes for tiden i Kubernetes. Fjerning av disse bildene kan resultere i betydelige produksjonsstanskostnader (for eksempel kan bildene være nødvendige for replikering) eller oppheve innsatsen til teamets feilsøking på noen av løkkene. (Av denne grunn har vi til og med laget en spesiell Prometheus eksportører, som sporer fraværet av slike bilder i enhver Kubernetes-klynge.)

2. For det andre (mindre åpenbart, men også veldig viktig og igjen relaterer seg til utnyttelse) - bilder som nødvendig for tilbakerulling ved oppdagelse av alvorlige problemer i gjeldende versjon. For eksempel, når det gjelder Helm, er dette bilder som brukes i lagrede versjoner av utgivelsen. (Forresten, som standard i Helm er grensen 256 revisjoner, men det er usannsynlig at noen virkelig trenger å lagre en slik et stort antall versjoner?..) Vi lagrer tross alt versjoner slik at vi kan bruke dem senere, dvs. "rull tilbake" til dem om nødvendig.

3. Tredje - utviklerens behov: Alle bilder som er relatert til deres nåværende arbeid. For eksempel, hvis vi vurderer en PR, er det fornuftig å legge igjen et bilde som tilsvarer den siste forpliktelsen og for eksempel den forrige forpliktelsen: på denne måten kan utvikleren raskt gå tilbake til enhver oppgave og jobbe med de siste endringene.

4. Fjerde - bilder som samsvarer med versjonene av applikasjonen vår, dvs. er sluttproduktet: v1.0.0, 20.04.01/XNUMX/XNUMX, sierra, etc.

NB: Kriteriene som er definert her ble formulert basert på erfaring fra interaksjon med dusinvis av utviklingsteam fra forskjellige selskaper. Men selvfølgelig, avhengig av spesifikasjonene i utviklingsprosessene og infrastrukturen som brukes (for eksempel Kubernetes brukes ikke), kan disse kriteriene variere.

Kvalifikasjon og eksisterende løsninger

Populære tjenester med beholderregistre tilbyr som regel sine egne retningslinjer for opprydding av bilder: i dem kan du definere betingelsene for at en tag skal fjernes fra registret. Disse betingelsene er imidlertid begrenset av parametere som navn, opprettelsestid og antall tagger*.

* Avhenger av spesifikke beholderregisterimplementeringer. Vi vurderte mulighetene for følgende løsninger: Azure CR, Docker Hub, ECR, GCR, GitHub-pakker, GitLab Container Registry, Harbor Registry, JFrog Artifactory, Quay.io - fra og med september 2020.

Dette settet med parametere er ganske nok til å tilfredsstille det fjerde kriteriet - det vil si å velge bilder som tilsvarer versjonene. For alle andre kriterier må man imidlertid velge en slags kompromissløsning (en tøffere eller omvendt mildere politikk) – avhengig av forventninger og økonomiske evner.

For eksempel kan det tredje kriteriet - relatert til utviklernes behov - løses ved å organisere prosesser i team: spesifikk navngivning av bilder, opprettholde spesielle tillatelseslister og interne avtaler. Men til syvende og sist må det fortsatt automatiseres. Og hvis evnene til ferdige løsninger ikke er nok, må du gjøre noe selv.

Situasjonen med de to første kriteriene er lik: de kan ikke tilfredsstilles uten å motta data fra et eksternt system - det der applikasjoner er distribuert (i vårt tilfelle Kubernetes).

Illustrasjon av arbeidsflyt i Git

La oss si at du jobber noe sånt som dette i Git:

Problemet med "smart" rengjøring av beholderbilder og løsningen på det i werf

Ikonet med et hode i diagrammet indikerer beholderbilder som for øyeblikket er distribuert i Kubernetes for alle brukere (sluttbrukere, testere, ledere, etc.) eller brukes av utviklere til feilsøking og lignende formål.

Hva skjer hvis oppryddingspolicyer bare tillater at bilder beholdes (ikke slettes) etter gitte merkenavn?

Problemet med "smart" rengjøring av beholderbilder og løsningen på det i werf

Det er klart at et slikt scenario ikke vil gjøre noen lykkelige.

Hva vil endres hvis retningslinjer tillater at bilder ikke slettes? i henhold til et gitt tidsintervall / antall siste commits?

Problemet med "smart" rengjøring av beholderbilder og løsningen på det i werf

Resultatet er blitt mye bedre, men er fortsatt langt fra ideelt. Tross alt har vi fortsatt utviklere som trenger bilder i registret (eller til og med distribuert i K8s) for å feilsøke feil ...

For å oppsummere den nåværende markedssituasjonen: funksjonene som er tilgjengelige i containerregistrene tilbyr ikke nok fleksibilitet ved rengjøring, og hovedårsaken til dette er ingen måte å samhandle med omverdenen på. Det viser seg at team som krever slik fleksibilitet, blir tvunget til å implementere bildesletting uavhengig "fra utsiden", ved å bruke Docker Registry API (eller den opprinnelige APIen til den tilsvarende implementeringen).

Vi var imidlertid på utkikk etter en universell løsning som ville automatisere bildeopprydding for forskjellige team ved å bruke forskjellige registre...

Vår vei til universell bilderens

Hvor kommer dette behovet fra? Faktum er at vi ikke er en egen gruppe utviklere, men et team som betjener mange av dem på en gang, og hjelper til med å løse CI/CD-problemer. Og det viktigste tekniske verktøyet for dette er Open Source-verktøyet werf. Dens særegenhet er at den ikke utfører en enkelt funksjon, men følger med kontinuerlige leveringsprosesser på alle stadier: fra montering til utplassering.

Å publisere bilder til registret* (umiddelbart etter at de er bygget) er en åpenbar funksjon av et slikt verktøy. Og siden bildene er plassert der for lagring, så - hvis lagringen din ikke er ubegrenset - må du være ansvarlig for deres påfølgende rengjøring. Hvordan vi oppnådde suksess med dette, og tilfredsstilte alle de spesifiserte kriteriene, vil bli diskutert videre.

* Selv om registrene i seg selv kan være forskjellige (Docker Registry, GitLab Container Registry, Harbor, etc.), møter brukerne deres de samme problemene. Den universelle løsningen i vårt tilfelle er ikke avhengig av implementeringen av registeret, fordi kjører utenfor registrene selv og tilbyr samme oppførsel for alle.

Selv om vi bruker werf som et eksempel på implementering, håper vi at tilnærmingene som brukes vil være nyttige for andre team som står overfor lignende vanskeligheter.

Så vi ble opptatt utvendig implementering av en mekanisme for å rense bilder - i stedet for de egenskapene som allerede er innebygd i registre for containere. Det første trinnet var å bruke Docker Registry API for å lage de samme primitive retningslinjene for antall tagger og tidspunktet for opprettelsen av dem (nevnt ovenfor). Lagt til dem tillatelsesliste basert på bilder brukt i utplassert infrastruktur, dvs. Kubernetes. For sistnevnte var det nok å bruke Kubernetes API for å iterere gjennom alle distribuerte ressurser og få en liste over verdier image.

Denne trivielle løsningen løste det mest kritiske problemet (kriterium nr. 1), men var bare begynnelsen på vår reise for å forbedre rensemekanismen. Det neste – og mye mer interessante – trinnet var avgjørelsen knytte publiserte bilder til Git-historien.

Merkeordninger

Til å begynne med valgte vi en tilnærming der det endelige bildet skulle lagre nødvendig informasjon for rengjøring, og bygde prosessen på merkeordninger. Ved publisering av et bilde valgte brukeren et spesifikt merkealternativ (git-branch, git-commit eller git-tag) og brukte den tilsvarende verdien. I CI-systemer ble disse verdiene satt automatisk basert på miljøvariabler. Faktisk det endelige bildet ble assosiert med en spesifikk Git-primitiv, lagring av nødvendige data for rengjøring i etiketter.

Denne tilnærmingen resulterte i et sett med retningslinjer som tillot Git å bli brukt som den eneste kilden til sannhet:

  • Ved sletting av en gren/tag i Git ble de tilknyttede bildene i registeret automatisk slettet.
  • Antall bilder assosiert med Git-tagger og forpliktelser kan kontrolleres av antall tagger brukt i det valgte skjemaet og tidspunktet da den tilknyttede forpliktelsen ble opprettet.

Totalt sett tilfredsstilte den resulterende implementeringen våre behov, men en ny utfordring ventet oss snart. Faktum er at mens vi brukte tagging-opplegg basert på Git-primitiver, møtte vi en rekke mangler. (Siden beskrivelsen deres er utenfor rammen av denne artikkelen, kan alle gjøre seg kjent med detaljene her.) Etter å ha bestemt oss for å bytte til en mer effektiv tilnærming til tagging (innholdsbasert tagging), måtte vi revurdere implementeringen av bilderensing.

Ny algoritme

Hvorfor? Med innholdsbasert tagging kan hver tag tilfredsstille flere forpliktelser i Git. Når du renser bilder, kan du ikke lenger anta bare fra commit der den nye taggen ble lagt til i registeret.

For den nye rensealgoritmen ble det besluttet å gå bort fra merkeordninger og bygge meta-image prosess, som hver lagrer en haug med:

  • forpliktelsen som publiseringen ble utført på (det spiller ingen rolle om bildet ble lagt til, endret eller forble det samme i containerregisteret);
  • og vår interne identifikator som tilsvarer det sammensatte bildet.

Det ble med andre ord gitt koble publiserte tagger med commits i Git.

Endelig konfigurasjon og generell algoritme

Når du konfigurerer rengjøring, har brukere nå tilgang til policyer som velger gjeldende bilder. Hver slik policy er definert:

  • mange referanser, dvs. Git-tagger eller Git-grener som brukes under skanning;
  • og grensen for søkte bilder for hver referanse fra settet.

For å illustrere, dette er hvordan standard policykonfigurasjon begynte å se ut:

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

Denne konfigurasjonen inneholder tre retningslinjer som overholder følgende regler:

  1. Lagre bildet for de siste 10 Git-taggene (etter opprettelsesdato).
  2. Lagre ikke mer enn 2 bilder publisert den siste uken for ikke mer enn 10 tråder med aktivitet den siste uken.
  3. Lagre 10 bilder for grener main, staging и production.

Den endelige algoritmen koker ned til følgende trinn:

  • Henter manifester fra containerregisteret.
  • Ekskluderer bilder brukt i Kubernetes, fordi Vi har allerede forhåndsvalgt dem ved å spørre K8s API.
  • Skanner Git-historikk og ekskluderer bilder basert på spesifiserte retningslinjer.
  • Fjerner gjenværende bilder.

Tilbake til illustrasjonen vår, dette er hva som skjer med werf:

Problemet med "smart" rengjøring av beholderbilder og løsningen på det i werf

Men selv om du ikke bruker werf, kan en lignende tilnærming til avansert bilderensing - i en eller annen implementering (i henhold til den foretrukne tilnærmingen til bildemerking) - brukes på andre systemer/verktøy. For å gjøre dette er det nok å huske problemene som oppstår og finne de mulighetene i stabelen din som lar deg integrere løsningen deres så jevnt som mulig. Vi håper at veien vi har gått vil hjelpe deg å se på akkurat din sak med nye detaljer og tanker.

Konklusjon

  • Før eller siden støter de fleste team på problemet med registeroverflyt.
  • Når du søker etter løsninger, er det først nødvendig å bestemme kriteriene for relevansen til bildet.
  • Verktøyene som tilbys av populære beholderregistertjenester lar deg organisere en veldig enkel opprydding som ikke tar hensyn til "verden utenfor": bildene som brukes i Kubernetes og særegenhetene ved teamets arbeidsflyter.
  • En fleksibel og effektiv algoritme må ha forståelse for CI/CD-prosesser og operere ikke bare med Docker-bildedata.

PS

Les også på bloggen vår:

Kilde: www.habr.com

Legg til en kommentar