El problema de la neteja "intel·ligent" d'imatges de contenidors i la seva solució en werf

El problema de la neteja "intel·ligent" d'imatges de contenidors i la seva solució en werf

L'article analitza els problemes de neteja d'imatges que s'acumulen als registres de contenidors (Docker Registry i els seus anàlegs) en les realitats dels pipelines CI/CD moderns per a aplicacions natives del núvol lliurades a Kubernetes. Es donen els principals criteris de rellevància de les imatges i les dificultats derivades per automatitzar la neteja, estalviar espai i satisfer les necessitats dels equips. Finalment, fent servir l'exemple d'un projecte de codi obert concret, us explicarem com es poden superar aquestes dificultats.

Introducció

El nombre d'imatges d'un registre de contenidors pot créixer ràpidament, ocupant més espai d'emmagatzematge i augmentant així significativament el seu cost. Per controlar, limitar o mantenir un creixement acceptable de l'espai ocupat en el registre, s'accepta:

  1. utilitzar un nombre fix d'etiquetes per a les imatges;
  2. netejar les imatges d'alguna manera.


La primera limitació de vegades és acceptable per a equips petits. Si els desenvolupadors tenen prou etiquetes permanents (latest, main, test, boris etc.), el registre no augmentarà de mida i durant molt de temps no haureu de pensar en netejar-lo. Al cap i a la fi, s'esborren totes les imatges irrellevants i simplement no queda feina per netejar (tot ho fa un recol·lector d'escombraries normal).

Tanmateix, aquest enfocament limita molt el desenvolupament i rarament s'aplica als projectes moderns de CI/CD. Una part integral del desenvolupament va ser automatització, que us permet provar, desplegar i oferir noves funcionalitats als usuaris molt més ràpidament. Per exemple, en tots els nostres projectes, es crea automàticament un pipeline CI amb cada commit. En ella, la imatge s'assembla, es prova, es desplega a diversos circuits de Kubernetes per a la depuració i les comprovacions restants i, si tot va bé, els canvis arriben a l'usuari final. I això ja no és ciència de coets, sinó un fet quotidià per a molts, molt probablement per a vosaltres, ja que esteu llegint aquest article.

Atès que la correcció d'errors i el desenvolupament de noves funcionalitats es duen a terme en paral·lel, i els llançaments es poden realitzar diverses vegades al dia, és obvi que el procés de desenvolupament va acompanyat d'un nombre important de commits, el que significa un gran nombre d'imatges al registre. Com a resultat, sorgeix la qüestió d'organitzar una neteja efectiva del registre, és a dir. eliminant imatges irrellevants.

Però, com es pot determinar si una imatge és rellevant?

Criteris per a la rellevància de la imatge

En la gran majoria dels casos, els criteris principals seran:

1. La primera (la més evident i la més crítica de totes) són les imatges que s'utilitza actualment a Kubernetes. L'eliminació d'aquestes imatges pot comportar costos significatius de temps d'inactivitat de producció (per exemple, les imatges poden ser necessàries per a la replicació) o anul·lar els esforços de l'equip depurant qualsevol dels bucles. (Per aquest motiu fins i tot vam fer un especial Exportador de Prometeu, que fa un seguiment de l'absència d'aquestes imatges a qualsevol clúster de Kubernetes.)

2. Segon (menys evident, però també molt important i de nou es refereix a l'explotació) - imatges que requerit per a la reversión en cas de detecció de problemes greus en la versió actual. Per exemple, en el cas de Helm, es tracta d'imatges que s'utilitzen en versions desades de la versió. (Per cert, per defecte a Helm el límit és de 256 revisions, però és poc probable que algú realment necessiti desar tal un gran nombre de versions?..) Al cap i a la fi, nosaltres, en particular, emmagatzemem versions per poder-les utilitzar més endavant, és a dir. "retorn" a ells si cal.

3. Tercer - necessitats del desenvolupador: Totes les imatges relacionades amb el seu treball actual. Per exemple, si estem considerant un PR, llavors té sentit deixar una imatge corresponent a l'últim commit i, per exemple, al commit anterior: d'aquesta manera el desenvolupador pot tornar ràpidament a qualsevol tasca i treballar amb els darrers canvis.

4. Quart - imatges que corresponen a les versions de la nostra aplicació, és a dir són el producte final: v1.0.0, 20.04.01/XNUMX/XNUMX, serra, etc.

Nota: Els criteris aquí definits es van formular a partir de l'experiència d'interaccionar amb desenes d'equips de desenvolupament de diferents empreses. Tanmateix, per descomptat, depenent de les especificitats dels processos de desenvolupament i de la infraestructura utilitzada (per exemple, no s'utilitza Kubernetes), aquests criteris poden diferir.

Elegibilitat i solucions existents

Els serveis populars amb registres de contenidors, per regla general, ofereixen les seves pròpies polítiques de neteja d'imatges: en elles podeu definir les condicions en què s'elimina una etiqueta del registre. Tanmateix, aquestes condicions estan limitades per paràmetres com ara noms, temps de creació i nombre d'etiquetes*.

* Depèn de les implementacions específiques del registre de contenidors. Hem considerat les possibilitats de les solucions següents: Azure CR, Docker Hub, ECR, GCR, GitHub Packages, GitLab Container Registry, Harbour Registry, JFrog Artifactory, Quay.io - a partir de setembre de 2020.

Aquest conjunt de paràmetres és suficient per satisfer el quart criteri, és a dir, seleccionar imatges que corresponguin a les versions. Tanmateix, per a tots els altres criteris, cal triar algun tipus de solució de compromís (una política més dura o, per contra, més indulgent), en funció de les expectatives i les capacitats financeres.

Per exemple, el tercer criteri -relacionat amb les necessitats dels desenvolupadors- es pot resoldre mitjançant l'organització de processos dins dels equips: denominació específica de les imatges, manteniment de llistes de permisos especials i acords interns. Però finalment encara s'ha d'automatitzar. I si les capacitats de les solucions ja fetes no són suficients, heu de fer alguna cosa pel vostre compte.

La situació amb els dos primers criteris és similar: no es poden satisfer sense rebre dades d'un sistema extern, aquell on es despleguen les aplicacions (en el nostre cas, Kubernetes).

Il·lustració del flux de treball a Git

Suposem que esteu treballant alguna cosa com això a Git:

El problema de la neteja "intel·ligent" d'imatges de contenidors i la seva solució en werf

La icona amb un cap al diagrama indica imatges de contenidors que actualment estan desplegades a Kubernetes per a qualsevol usuari (usuaris finals, provadors, gestors, etc.) o que els desenvolupadors utilitzen per a la depuració i finalitats similars.

Què passa si les polítiques de neteja només permeten conservar les imatges (no esborrar) per noms d'etiquetes donats?

El problema de la neteja "intel·ligent" d'imatges de contenidors i la seva solució en werf

Evidentment, un escenari així no farà feliç a ningú.

Què canviarà si les polítiques permeten que les imatges no s'eliminin? segons un interval de temps determinat / nombre de darrers commits?

El problema de la neteja "intel·ligent" d'imatges de contenidors i la seva solució en werf

El resultat ha millorat molt, però encara està lluny de ser ideal. Després de tot, encara tenim desenvolupadors que necessiten imatges al registre (o fins i tot desplegades a K8s) per depurar errors...

Per resumir la situació actual del mercat: les funcions disponibles als registres de contenidors no ofereixen prou flexibilitat a l'hora de netejar, i el motiu principal és no hi ha manera d'interactuar amb el món exterior. Resulta que els equips que requereixen aquesta flexibilitat es veuen obligats a implementar de manera independent l'eliminació d'imatges "des de l'exterior", mitjançant l'API Docker Registry (o l'API nativa de la implementació corresponent).

Tanmateix, estàvem buscant una solució universal que automatitzés la neteja d'imatges per a diferents equips mitjançant registres diferents...

El nostre camí cap a la neteja universal d'imatges

D'on ve aquesta necessitat? El fet és que no som un grup separat de desenvolupadors, sinó un equip que serveix a molts d'ells alhora, ajudant a resoldre de manera integral els problemes de CI/CD. I la principal eina tècnica per a això és la utilitat de codi obert werf. La seva particularitat és que no realitza una única funció, sinó que acompanya processos de lliurament continus en totes les etapes: des del muntatge fins al desplegament.

Publicar imatges al registre* (immediatament després de crear-les) és una funció òbvia d'aquesta utilitat. I com que les imatges es col·loquen allà per a l'emmagatzematge, aleshores, si el vostre emmagatzematge no és il·limitat, heu de ser responsable de la seva neteja posterior. Com hem aconseguit l'èxit en això, complint tots els criteris especificats, s'explicarà més endavant.

* Encara que els propis registres poden ser diferents (Registre Docker, Registre de contenidors GitLab, Harbour, etc.), els seus usuaris s'enfronten als mateixos problemes. La solució universal en el nostre cas no depèn de la implementació del registre, perquè s'executa fora dels propis registres i ofereix el mateix comportament per a tothom.

Tot i que estem utilitzant werf com a exemple d'implementació, esperem que els enfocaments utilitzats siguin útils per a altres equips amb dificultats similars.

Així que ens vam ocupar extern implementació d'un mecanisme de neteja d'imatges, en lloc d'aquelles capacitats que ja estan integrades als registres dels contenidors. El primer pas va ser utilitzar l'API Docker Registry per crear les mateixes polítiques primitives per al nombre d'etiquetes i el moment de la seva creació (esmentat anteriorment). S'hi ha afegit llista de permetre basada en imatges utilitzades a la infraestructura desplegada, és a dir Kubernetes. Per a aquest últim, n'hi havia prou amb utilitzar l'API de Kubernetes per iterar tots els recursos desplegats i obtenir una llista de valors image.

Aquesta solució trivial va resoldre el problema més crític (criteri núm. 1), però només va ser l'inici del nostre viatge per millorar el mecanisme de neteja. El següent pas -i molt més interessant- va ser la decisió associar imatges publicades amb l'historial de Git.

Esquemes d'etiquetatge

Per començar, vam triar un enfocament en què la imatge final hauria d'emmagatzemar la informació necessària per a la neteja i vam construir el procés a partir d'esquemes d'etiquetatge. En publicar una imatge, l'usuari seleccionava una opció d'etiquetatge específica (git-branch, git-commit o git-tag) i va utilitzar el valor corresponent. Als sistemes CI, aquests valors es van establir automàticament en funció de variables d'entorn. De fet la imatge final estava associada amb una primitiva Git específica, emmagatzemant les dades necessàries per a la neteja en etiquetes.

Aquest enfocament va donar lloc a un conjunt de polítiques que van permetre utilitzar Git com a font única de veritat:

  • En eliminar una branca/etiqueta a Git, les imatges associades al registre s'eliminaven automàticament.
  • El nombre d'imatges associades amb les etiquetes i les confirmacions de Git es podria controlar pel nombre d'etiquetes utilitzades a l'esquema seleccionat i el moment en què es va crear la confirmació associada.

En general, la implementació resultant va satisfer les nostres necessitats, però aviat ens esperava un nou repte. El fet és que mentre utilitzem esquemes d'etiquetatge basats en primitives de Git, ens hem trobat amb una sèrie de deficiències. (Com que la seva descripció està fora de l'abast d'aquest article, tothom pot familiaritzar-se amb els detalls aquí.) Per tant, després d'haver decidit canviar a un enfocament més eficient de l'etiquetatge (etiquetatge basat en contingut), hem hagut de reconsiderar la implementació de la neteja d'imatges.

Nou algorisme

Per què? Amb l'etiquetatge basat en contingut, cada etiqueta pot satisfer múltiples commits a Git. Quan netegeu imatges, ja no podeu assumir només des de la confirmació on es va afegir la nova etiqueta al registre.

Per al nou algorisme de neteja, es va decidir allunyar-se dels esquemes d'etiquetatge i construir-los procés de metaimatge, cadascun dels quals emmagatzema un munt de:

  • el commit sobre el qual s'ha realitzat la publicació (no importa si la imatge s'ha afegit, ha canviat o ha estat igual al registre de contenidors);
  • i el nostre identificador intern corresponent a la imatge muntada.

En altres paraules, es va proporcionar enllaçar etiquetes publicades amb commits a Git.

Configuració final i algorisme general

En configurar la neteja, els usuaris ara tenen accés a polítiques que seleccionen les imatges actuals. Cada una d'aquestes polítiques es defineix:

  • moltes referències, és a dir. Etiquetes Git o branques de Git que s'utilitzen durant l'escaneig;
  • i el límit d'imatges cercades per a cada referència del conjunt.

Per il·lustrar-ho, així va començar a semblar la configuració de la política predeterminada:

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

Aquesta configuració conté tres polítiques que compleixen les regles següents:

  1. Deseu la imatge de les 10 darreres etiquetes Git (per data de creació de l'etiqueta).
  2. No deseu més de 2 imatges publicades la darrera setmana per a no més de 10 fils amb activitat durant la darrera setmana.
  3. Desa 10 imatges per a les branques main, staging и production.

L'algorisme final es resumeix en els següents passos:

  • Recuperació de manifests del registre de contenidors.
  • S'exclouen les imatges utilitzades a Kubernetes, perquè Ja els hem preseleccionat consultant l'API K8s.
  • Escanejar l'historial de Git i excloure imatges en funció de polítiques especificades.
  • Eliminació de les imatges restants.

Tornant a la nostra il·lustració, això és el que passa amb werf:

El problema de la neteja "intel·ligent" d'imatges de contenidors i la seva solució en werf

Tanmateix, fins i tot si no feu servir werf, un enfocament similar a la neteja avançada d'imatges -en una implementació o una altra (segons l'enfocament preferit per a l'etiquetatge d'imatges)- es pot aplicar a altres sistemes/utilitats. Per fer-ho, n'hi ha prou amb recordar els problemes que sorgeixen i trobar aquelles oportunitats a la vostra pila que us permetin integrar la seva solució de la manera més fluida possible. Esperem que el camí que hem recorregut us ajudi a mirar el vostre cas particular amb nous detalls i reflexions.

Conclusió

  • Tard o d'hora, la majoria dels equips es troben amb el problema del desbordament del registre.
  • Quan es busquen solucions, primer cal determinar els criteris per a la rellevància de la imatge.
  • Les eines que ofereixen els populars serveis de registre de contenidors permeten organitzar una neteja molt senzilla que no té en compte el “món exterior”: les imatges utilitzades a Kubernetes i les peculiaritats dels fluxos de treball de l'equip.
  • Un algorisme flexible i eficient ha de tenir una comprensió dels processos CI/CD i no només funcionar amb les dades d'imatge de Docker.

PS

Llegeix també al nostre blog:

Font: www.habr.com

Afegeix comentari