
Článok sa zaoberá problematikou čistenia obrazov, ktoré sa hromadia v registroch kontajnerov (Docker Registry a jeho analógy) v reáliách moderných CI/CD pipeline pre cloud native aplikácie doručované v Kubernetes. Uvedené sú hlavné kritériá aktuálnosti obrazov a vyplývajúce ťažkosti pri automatizácii čistenia, zachovaní miesta a uspokojovaní potrieb tímov. Nakoniec na príklade konkrétneho Open Source projektu ukážeme, ako je možné tieto ťažkosti prekonávať.
Úvod
Počet obrazov v registri kontajnerov môže rýchlo narastať, zaberajúc viac miesta v úložisku a tým výrazne zvyšovať jeho náklady. Na kontrolu, obmedzenie alebo udržanie prijateľného rastu miesta, ktoré zaberá registry, sa prijíma:
- používať pevný počet tagov pre obrazy;
- nejakým spôsobom čistiť obrazy.
Prvé obmedzenie je niekedy prijateľné pre malé tímy. Ak vývojárom stačia stále tagy (latest, main, test, boris a pod.), registry nebude zväčšovať objem a dlhý čas sa vôbec nebude treba zaoberať čistením. Veď všetky neaktuálne obrazy sú prepisované a na čistenie jednoducho nezostáva práca (všetko zabezpečuje bežný zberač odpadu).
Napriek tomu, takýto prístup značne obmedzuje vývoj a zriedka sa aplikuje na moderné CI/CD projekty. Neoddeliteľnou súčasťou vývoja sa stala automatizáciu, ktorá umožňuje oveľa rýchlejšie testovať, nasadzovať a doručovať novú funkcionalitu používateľom. Napríklad, vo všetkých našich projektoch sa pri každom commite automaticky vytvára CI pipeline. V nej sa zostavuje obraz, testuje, nasadzuje v rôznych Kubernetes kontúrach na ladenie a zostávajúce kontroly, a ak je všetko v poriadku — zmeny sa dostanú k konečnému používateľovi. A to už dávno nie je rocket science, ale bežná rutina pre mnohých — pravdepodobne aj pre vás, ak čítate tento článok.
Keďže odstránenie chýb a vývoj novej funkcionality prebieha paralelne, a vydania môžu prebiehať niekoľkokrát denne, je jasné, že proces vývoja je sprevádzaný značným počtom commitov, a teda — veľkým počtom obrazov v registry. V dôsledku toho sa ostro stáva otázka organizácie efektívneho čistenia registry, t.j. odstránenia neaktuálnych obrazov.
Ale ako vôbec určiť, či je obraz aktuálny?
Kritériá aktuálnosti obrazov
V prevažnej väčšine prípadov budú hlavné kritériá nasledovné:
1. Prvé (najte obvious a najkritickejšie zo všetkých) — sú to obrazy, ktoré sa aktuálne používajú v Kubernetes. Odstránenie týchto obrazov môže viesť k vážnym nákladom v súvislosti so zdržaním produkcie (napríklad, obrazy môžu byť potrebné pri replikácii) alebo môžu zmarit úsilie tímu, ktorý sa zaoberá ladením na nejakých zretiach. (Z tohto dôvodu sme dokonca vytvorili špeciálny , ktorý sleduje absenciu takýchto obrazov v akomkoľvek Kubernetes klastri.)
2. Druhé (menej očividné, ale tiež veľmi dôležité a opäť týkajúce sa prevádzky) — sú to obrazy, ktoré sú potrebné na návrat v prípade zistenia vážnych problémov v aktuálnej verzii. Napríklad, v prípade Helm to sú obrazy, ktoré sa používajú v uložených verziách vydania. (Mimochodom, predvolený limit v Helmu je 256 revízií, ale ťažko povedať, či naozaj niekto má potrebu uchovávať takého veľké množstvo verzií?..) Nakoniec, uchovávame verzie, aby sme ich mohli neskôr použiť, teda "návrat" na ne v prípade potreby.
3. Tretie — potreby vývojárov: všetky obrazy, ktoré súvisia s ich aktuálnou prácou. Napríklad, ak posudzujeme PR, má zmysel ponechať obraz, ktorý zodpovedá poslednému commitu a, povedzme, predchádzajúcemu commitu: takto sa vývojár môže rýchlo vrátiť k akémukoľvek úlohe a pracovať s poslednými zmenami.
4. Štvrté — obrazy, ktoré zodpovedajú verziám našej aplikácie, t.j. sú konečným produktom: v1.0.0, 20.04.01, sierra a pod.
NB: Určité kritériá tu boli formulované na základe skúseností s interakciou desiatok tímov vývojárov z rôznych spoločností. Samozrejme, v závislosti od špecifík v procesoch vývoja a používané infraštruktúry (napríklad, ak sa Kubernetes nepoužíva), sa tieto kritériá môžu líšiť.
Zhodnosť s kritériami a existujúce riešenia
Populárne služby s container registry zvyčajne ponúkajú svoje politiky čistenia obrazov: môžete určovať podmienky, za ktorých sa značka odstráni z registry. Možnosti týchto podmienok sú však obmedzené takými parametrami, ako sú názvy, dátum vytvorenia a počet značiek*.
* Závisí od konkrétnych realizácií container registry. Zvažovali sme možnosti nasledujúcich riešení: Azure CR, Docker Hub, ECR, GCR, GitHub Packages, GitLab Container Registry, Harbor Registry, JFrog Artifactory, Quay.io — k septembru 2020.
Takáto sústava parametrov je celkom dostatočná na splnenie štvrtého kritéria — to znamená vyberať obrazy, ktoré zodpovedajú verziám. Avšak na splnenie ostatných kritérií je potrebné zvoliť nejaké kompromisné riešenie (buď prísnejšiu alebo, naopak, jemnejšiu politiku) — v závislosti od očakávaní a finančných možností.
Napríklad tretie kritérium — súvisiace s potrebami vývojárov — môže byť riešené organizovaním procesov vo vnútri tímov: špecifickým pomenúvaním obrazov, vedením špeciálnych allow lists a vnútorných dohod. Ale nakoniec je to aj tak potrebné automatizovať. A ak možnosti hotových riešení nestačia, treba robiť niečo vlastné.
Podobná situácia je aj s dvomi prvými kritériami: nemožno ich splniť bez získavania údajov z vonkajšieho systému — toho, v ktorom prebieha nasadzovanie aplikácií (v našom prípade je to Kubernetes).
Ilustrácia workflow v Gite
Predpokladajme, že pracujete približne podľa tejto schémy v Gite:

Ikonka hlavy na schéme označuje obrazy kontajnerov, ktoré sú v súčasnosti nasadené v Kubernetes pre nejakých používateľov (koncových používateľov, testovačov, manažérov atď.) alebo sú používané vývojármi na ladenie a podobné účely.
Čo sa stane, ak politiky čistenia umožňujú ponechať (neodstrániť) obrazy len podľa zadaných názvov tagov?

Zjavne, takýto scenár nikoho nepoteší.
Čo sa zmení, ak politiky umožnia neodstraňovať obrazy podľa zadaného časového intervalu / počtu posledných commitov?

Výsledok sa výrazne zlepšil, avšak stále je ďaleko od ideálu. Predsa len máme stále vývojárov, ktorí potrebujú obrazy v registri (alebo dokonca nasadené v K8s) na ladenie chýb...
Zhrnúť situáciu na trhu: dostupné funkcie v registroch kontajnerov neponúkajú dostatočnú flexibilitu pri čistení, a hlavná príčina je — nedostatok možnosti interakcie s vonkajším svetomTak sa zdá, že tímy, ktoré potrebujú takúto flexibilitu, sú nútené implementovať odstránenie obrazov "z vonku" pomocou Docker Registry API (alebo nativného API príslušnej implementácie).
Hľadali sme však univerzálne riešenie, ktoré by automatizovalo čistenie obrazov pre rôzne tímy využívajúce rôzne registry…
Naša cesta k univerzálnemu čisteníu obrazov
Odkiaľ sa berie taká potreba? Je to tým, že nie sme samostatná skupina vývojárov, ale tím, ktorý obsluhuje viaceré takéto skupiny, pomáhajúci komplexne riešiť otázky CI/CD. A hlavným technickým nástrojom na to je Open Source utilita. Jej osobitosť spočíva v tom, že nevykonáva jedinú funkciu, ale sprevádza procesy nepretržitej dodávky na všetkých etapách: od zostavenia až po nasadenie.
Publikovanie v registry* obrazov (ihneď po ich zostavení) je zjavná funkcia takejto utilitky. A keďže sa obrazy ukladajú na uchovávanie, ak vaše úložisko nie je bezhraničné, musíte sa postarať aj o ich následné čistenie. O tom, ako sme v tom uspel, spĺňajúc všetky dané kritériá, sa bude hovoriť ďalej.
* Hoci samotné registry môžu byť rôzne (Docker Registry, GitLab Container Registry, Harbor a pod.), ich používatelia sa stretávajú s tými istými problémami. Univerzálne riešenie v našom prípade nezávisí od implementácie registry, keďže sa vykonáva mimo samotných registry a ponúka rovnaké správanie pre všetkých.
Napriek tomu, že používame werf ako príklad implementácie, dúfame, že použité prístupy budú užitočné aj iným tímom, ktoré sa stretli s podobnými ťažkosťami.
Tak sme sa pustili do externého realizovania mechanizmu na čistenie obrazov — namiesto tých možností, ktoré už sú zabudované v registroch pre kontajnery. Prvým krokom bolo využitie Docker Registry API na vytvorenie tých istých primitívnych politík počtu značiek a času ich vytvorenia (spomínaných vyššie). K nim bol pridaný allow list na základe obrazov používaných v nasadenej infraštruktúre, t.j. Kubernetes. Pre to posledné stačilo cez Kubernetes API prechádzať všetky nasadené zdroje a získať zoznam hodnôt. obrázok.
Takéto triviálne riešenie uzatvorilo najkritickejší problém (kritérium č. 1), ale bolo len začiatkom našej cesty k zlepšeniu mechanizmu čistenia. Nasledujúcim — a oveľa zaujímavejším — krokom bolo riešenie prepojiť publikované obrazy s históriou Git.
Schémy značkovania
Na začiatok sme zvolili prístup, pri ktorom konečný obraz musí uchovávať potrebné informácie na čistenie, a vybudovali sme proces na základe schém značkovania. Pri publikovaní obrazu si používateľ vyberal určité označenie (git-branch, git-commit alebo git-tag) a používal zodpovedajúcu hodnotu. V CI systémoch sa nastavenie týchto hodnôt vykonávalo automaticky na základe premenných prostredia. V podstate konečný obraz bol prepojený s konkrétnym Git primitívom, uchovávajúce potrebné údaje na čistenie v štítkoch.
V rámci takého prístupu vznikla sada politík, ktorá umožňovala používať Git ako jediný zdroj pravdy:
- Pri odstránení vetvy/tagu v Gite sa automaticky odstránili aj súvisiace obrazy v registry.
- Počet obrazov súvisiacich s Git tagmi a commitmi bolo možné regulovať počtom tagov použitých v zvolenej schéme a časom vytvorenia súvisiaceho commitu.
V zásade, výsledná implementácia uspokojovala naše potreby, ale čoskoro nás čakal nový výzva. Ide o to, že počas používania schém značkovania na Git primitívoch sme narazili na niekoľko nedostatkov. (Keďže ich opis presahuje rámec tohto článku, všetkých zaujímajúcich sa pozývame na podrobnosti .) Preto, po rozhodnutí prechod na efektívnejší prístup k značkovaniu (označkovanie na základe obsahu), sme museli prehodnotiť aj implementáciu čistenia obrazov.
Nový algoritmus
Prečo? Pri označovaní na základe obsahu každý tag môže predstavovať množstvo commitov v Gite. Pri čistení obrazov už nemožno vychádzať iba z commitu, na ktorom bol nový tag pridaný do rejestru.
Pre nový algoritmus čistenia bolo rozhodnuté opustiť schémy značkovania a vybudovať proces na meta-obrázkoch, z ktorých každý uchováva spojenie z:
- commitu, na ktorom sa vykonala publikácia (pričom nezáleží, či bol pridaný, zmenený alebo zostal rovnaký obraz v registri kontajnerov);
- a nášho vnútorného identifikátora, zodpovedajúceho zostavenému obrazu.
Inými slovami, bola zabezpečená väzba publikovaných tagov na commit v Git.
Koncová konfigurácia a všeobecný algoritmus
Používateľom pri konfigurácii čistenia sa sprístupnili politiky, na základe ktorých sa vykonáva výber aktuálnych obrazov. Každá taká politika sa definuje:
- množstvom referencií, teda Git-tagmi alebo Git-branchami, ktoré sa používajú pri skenovaní;
- a limitom hľadaných obrazov pre každú referenciu z množstva.
Na ilustráciu — takto vypadá konfigurácia politík podľa predvolených nastavení:
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
Takáto konfigurácia obsahuje tri politiky, ktoré zodpovedajú nasledujúcim pravidlám:
- Uchovať obraz pre 10 posledných Git-tagov (podľa dátumu vytvorenia tagu).
- Uchovať nie viac ako 2 obrazy, publikované za posledný týždeň, pre nie viac ako 10 vetiev s aktivitou za posledný týždeň.
- Uchovať po 10 obrazov pre vetvy
main,stagingaprodukciu.
Koncový algoritmus spočíva v nasledujúcich krokoch:
- Získanie manifestov z container registry.
- Vylúčenie obrazov, ktoré sa používajú v Kubernetes, pretože tie už boli vopred vybrané, dotazom na K8s API.
- Skenovanie Git-historie a vylúčenie obrazov podľa zadaných politík.
- Odstránenie zostávajúcich obrazov.
Vrátiac sa k našej ilustrácii, tu je, čo dostaneme s werf:

Avšak, aj keď nevyužívate werf, podobný prístup k pokročilému čistenia obrazov — v jednej alebo druhej implementácii (podľa preferovaného prístupu k tagovaniu obrazov) — môže byť aplikovaný aj v iných systémoch/nástrojoch. Stačí si pamätať na tie problémy, ktoré sa objavujú, a nájsť tie možnosti vo vašom stacku, ktoré umožňujú integrovať ich riešenie najhladšie. Dúfame, že cesta, ktorou sme prešli, pomôže nahliadnuť aj na váš konkrétny prípad s novými detailmi a myšlienkami.
Záver
- Skôr či neskôr sa s problémom preplnenia registry stretáva väčšina tímov.
- Pri hľadaní riešení je najprv potrebné určiť kritériá aktuálnosti obrazu.
- Nástroje ponúkané populárnymi službami container registry umožňujú veľmi jednoduché čistenie, ktoré nezohľadňuje "vonkajší svet": obrazy používané v Kubernetes a osobitosti pracovných procesov v tíme.
- Flexibilný a efektívny algoritmus by mal mať predstavu o CI/CD procesoch a operovať nie len s údajmi Docker obrazov.
P.S.
Prečítajte si tiež na našom blogu:
- «»;
- «»;
- «»;
- «».
Zdroj: habr.com
