Das Problem der "intelligenten" Reinigung von Containerbildern und deren Lösung in werf





Der Artikel beschreibt das Problem der Bereinigung von Bildern, die sich in Containerregistern (Docker Registry und seine Analoga) in der Realität moderner CI / CD-Pipelines für an Kubernetes gelieferte native Cloud-Anwendungen ansammeln. Die Hauptkriterien für die Relevanz von Bildern und die daraus resultierenden Schwierigkeiten bei der Automatisierung der Reinigung, der Platzersparnis und der Erfüllung der Anforderungen von Teams werden angegeben. Abschließend zeigen wir Ihnen anhand eines Beispiels eines bestimmten Open Source-Projekts, wie diese Schwierigkeiten überwunden werden können.



Einführung



Die Anzahl der Bilder in der Containerregistrierung kann schnell zunehmen, mehr Speicherplatz beanspruchen und dementsprechend die Kosten erheblich erhöhen. Um ein akzeptables Wachstum des in der Registrierung belegten Speicherplatzes zu kontrollieren, zu begrenzen oder aufrechtzuerhalten, wird Folgendes akzeptiert:



  1. Verwenden Sie eine feste Anzahl von Tags für Bilder.
  2. Bereinigen Sie die Bilder in irgendeiner Weise.


Die erste Einschränkung gilt manchmal für kleine Teams. Wenn Entwickler genug permanent - Tag ( latest, main, test, borisusw.), wird die Registrierung nicht in der Größe anschwellen und eine lange Zeit nicht über die Reinigung zu denken sein kann. Schließlich sind alle irrelevanten Bilder ausgefranst und es bleibt einfach keine Arbeit zum Reinigen übrig (alles wird von einem normalen Müllsammler erledigt).



Dieser Ansatz schränkt die Entwicklung jedoch stark ein und ist heutzutage nur noch selten auf CI / CD-Projekte anwendbar. Die Automatisierung ist ein wesentlicher Bestandteil der Entwicklung gewordenAuf diese Weise können Sie Benutzer viel schneller testen, bereitstellen und neue Funktionen bereitstellen. Beispielsweise wird in allen unseren Projekten bei jedem Commit automatisch eine CI-Pipeline erstellt. Es erstellt ein Image, testet es, rollt es zum Debuggen und für verbleibende Überprüfungen in verschiedene Kubernetes-Schaltkreise aus, und wenn alles gut geht, erreichen die Änderungen den Endbenutzer. Und dies ist lange Zeit keine Raketenwissenschaft, sondern für viele der Alltag - höchstwahrscheinlich für Sie, da Sie diesen Artikel lesen.



Da Fehler behoben werden und neue Funktionen parallel entwickelt werden und Releases mehrmals täglich ausgeführt werden können, ist es offensichtlich, dass der Entwicklungsprozess von einer erheblichen Anzahl von Commits begleitet wird, was eine große Anzahl von Bildern in der Registrierung bedeutet... Infolgedessen wird das Problem der Organisation einer wirksamen Registerbereinigung akut, d.h. Entfernen irrelevanter Bilder.



Aber wie können Sie überhaupt feststellen, ob ein Bild relevant ist?



Bildrelevanzkriterien



In den allermeisten Fällen lauten die Hauptkriterien wie folgt:



1. Das erste (das offensichtlichste und kritischste von allen) sind die Bilder, die derzeit in Kubernetes verwendet werden . Das Entfernen dieser Images kann zu erheblichen Ausfallkosten für die Produktion führen (z. B. können Images während der Replikation erforderlich sein) oder die Bemühungen des Teams zunichte machen, das mit dem Debuggen auf einem der Schaltkreise beschäftigt ist. (Aus diesem Grund haben wir sogar einen speziellen Prometheus-Exporteur erstellt , der das Fehlen solcher Bilder in einem Kubernetes-Cluster überwacht.)



2. Das zweite (weniger offensichtlich, aber auch sehr wichtig und wiederum betriebsbedingt) - Bilder, die im Ernstfall zurückgesetzt werden müssen Problemein der aktuellen Version. Im Fall von Helm sind dies beispielsweise die Bilder, die in den gespeicherten Versionen der Version verwendet werden. (Das Standardlimit in Helm liegt übrigens bei 256 Revisionen, aber kaum jemand muss wirklich so viele Versionen speichern ? ..) Schließlich speichern wir insbesondere hierfür Versionen, damit Sie später darauf zugreifen können verwenden, d.h. Bei Bedarf "zurückrollen".



3. Drittens - die Bedürfnisse der Entwickler : alle Bilder, die mit ihrer aktuellen Arbeit verbunden sind. Wenn wir beispielsweise PR in Betracht ziehen, ist es sinnvoll, das Image zu belassen, das dem letzten Commit und beispielsweise dem vorherigen Commit entspricht. Auf diese Weise kann der Entwickler schnell zu jeder Aufgabe zurückkehren und mit den neuesten Änderungen arbeiten.



4. Viertens - Bilder, dieentsprechen den Versionen unserer Anwendung , d.h. sind das Endprodukt: v1.0.0, 20.04.01, sierra usw.



NB: Die hier definierten Kriterien wurden basierend auf der Erfahrung der Interaktion mit Dutzenden von Entwicklungsteams aus verschiedenen Unternehmen formuliert. Abhängig von den Besonderheiten der Entwicklungsprozesse und der verwendeten Infrastruktur (z. B. wird Kubernetes nicht verwendet) können diese Kriterien jedoch unterschiedlich sein.



Berechtigung und vorhandene Lösungen



Beliebte Dienste mit Containerregistrierung bieten in der Regel ihre eigenen Richtlinien zur Bildbereinigung an: In diesen können Sie die Bedingungen definieren, unter denen ein Tag aus der Registrierung entfernt wird. Diese Bedingungen sind jedoch durch Parameter wie Namen, Erstellungszeit und Anzahl der Tags * begrenzt.



* Hängt von bestimmten Implementierungen der Containerregistrierung ab. Wir haben die Möglichkeiten der folgenden Lösungen geprüft: Azure CR, Docker Hub, ECR, GCR, GitHub-Pakete, GitLab-Containerregistrierung, Hafenregistrierung, JFrog Artifactory, Quay.io - Stand September 2020.



Dieser Parametersatz reicht völlig aus, um das vierte Kriterium zu erfüllen, dh Bilder auszuwählen, die den Versionen entsprechen. Für alle anderen Kriterien muss jedoch eine Kompromisslösung gewählt werden (eine strengere oder umgekehrt eine sparsame Politik) - abhängig von den Erwartungen und den finanziellen Möglichkeiten.



Zum Beispiel kann das dritte Kriterium - bezogen auf die Bedürfnisse von Entwicklern - gelöst werden, indem Prozesse innerhalb von Teams organisiert werden: spezifische Benennung von Bildern, Pflege spezieller Zulassungslisten und interner Vereinbarungen. Aber letztendlich muss es noch automatisiert werden. Und wenn die Möglichkeiten vorgefertigter Lösungen nicht ausreichen, müssen Sie etwas Eigenes tun.



Ähnlich verhält es sich mit den ersten beiden Kriterien: Sie können nicht erfüllt werden, ohne Daten von einem externen System zu erhalten - dem System, auf dem die Anwendungen bereitgestellt werden (in unserem Fall Kubernetes).



Illustration eines Workflows in Git



Angenommen, Sie arbeiten in Git ungefähr so: Das







Symbol mit einem Kopf im Diagramm markiert Container-Images, die derzeit für alle Benutzer (Endbenutzer, Tester, Manager usw.) in Kubernetes bereitgestellt werden oder von Entwicklern zum Debuggen verwendet werden und ähnliche Ziele.



Was passiert, wenn Sie mit den Bereinigungsrichtlinien Bilder nur für die angegebenen Tag-Namen behalten (nicht löschen) können ?







Offensichtlich wird dieses Szenario niemandem gefallen.



Was ändert sich, wenn die Richtlinien es Ihnen ermöglichen, Bilder für ein bestimmtes Zeitintervall / eine bestimmte Anzahl der letzten Commits nicht zu löschen ?







Das Ergebnis ist viel besser geworden, aber alles andere als ideal. Immerhin haben wir immer noch Entwickler, die Images in der Registrierung benötigen (oder sogar in K8s bereitgestellt werden), um Fehler zu beheben ...



Zusammenfassend die aktuelle Marktsituation: Die in den Containerregistern verfügbaren Funktionen bieten keine ausreichende Flexibilität bei der Reinigung, und der Hauptgrund ist, dass es keine Möglichkeit gibt mit der Außenwelt interagieren . Es stellt sich heraus, dass Teams, die diese Flexibilität benötigen, gezwungen sind, die Image-Entfernung "außerhalb" mithilfe der Docker-Registrierungs-API (oder der nativen API der entsprechenden Implementierung) unabhängig zu implementieren.



Wir suchten jedoch nach einer universellen Lösung, die die Bildbereinigung für verschiedene Teams mithilfe verschiedener Register automatisiert ...



Unser Weg zur universellen Bildreinigung



Woher kommt dieses Bedürfnis? Tatsache ist, dass wir keine separate Gruppe von Entwicklern sind, sondern ein Team, das viele von ihnen gleichzeitig bedient und dabei hilft, CI / CD-Probleme umfassend zu lösen. Und das wichtigste technische Werkzeug dafür ist das Open-Source-Dienstprogramm werf . Seine Besonderheit ist, dass es keine einzige Funktion ausführt, sondern kontinuierliche Lieferprozesse in allen Phasen begleitet: von der Montage bis zur Bereitstellung.



Das Veröffentlichen von Bildern in der Registrierung * (unmittelbar nach ihrer Erstellung) ist eine offensichtliche Funktion eines solchen Dienstprogramms. Und da die Bilder dort zur Aufbewahrung abgelegt werden, müssen Sie - wenn Ihre Aufbewahrung nicht unbegrenzt ist - für die anschließende Reinigung verantwortlich sein. Wie wir dabei erfolgreich waren und alle festgelegten Kriterien erfüllten, wird weiter diskutiert.



* Obwohl die Registrierungen selbst unterschiedlich sein können (Docker-Registrierung, GitLab-Container-Registrierung, Hafen usw.), haben ihre Benutzer dieselben Probleme. Die universelle Lösung hängt in unserem Fall nicht von der Implementierung der Registrierung ab, da läuft außerhalb der Register selbst und bietet für alle das gleiche Verhalten.



Trotz der Tatsache, dass wir werf als Beispiel für die Implementierung verwenden, hoffen wir, dass die verwendeten Ansätze für andere Teams mit ähnlichen Schwierigkeiten nützlich sind.



Also haben wir das Äußere aufgenommenImplementierung eines Mechanismus zum Bereinigen von Bildern - anstelle der Funktionen, die bereits in den Registern für Container integriert sind. Der erste Schritt bestand darin, die Docker-Registrierungs-API zu verwenden, um dieselben primitiven Richtlinien anhand der Anzahl der Tags und des Zeitpunkts ihrer Erstellung (siehe oben) zu erstellen. Diesen wurde eine Zulassungsliste hinzugefügt , die auf den in der bereitgestellten Infrastruktur verwendeten Bildern basiert , d. H. Kubernetes. Für letztere reichte es aus, alle bereitgestellten Ressourcen über die Kubernetes-API zu durchsuchen und eine Liste mit Werten abzurufen image.



Diese triviale Lösung schloss das kritischste Problem (Kriterium 1), aber es war erst der Beginn unserer Reise zur Verbesserung des Reinigungsmechanismus. Der nächste - und viel interessantere - Schritt war die Entscheidung, die veröffentlichten Bilder mit der Git-Geschichte zu verknüpfen .



Markierungsschemata



Zunächst haben wir einen Ansatz gewählt, bei dem das endgültige Bild die für die Reinigung erforderlichen Informationen speichern muss, und den Prozess auf Tagging-Schemata aufgebaut. Wenn ein Bild veröffentlicht, ausgewählt der Benutzer eine bestimmte Tagging - Option ( git-branch, git-commitoder git-tag) und verwendet , um den entsprechenden Wert. In CI-Systemen wurden diese Werte automatisch basierend auf Umgebungsvariablen festgelegt. Grundsätzlich wurde das endgültige Bild einem bestimmten Git-Grundelement zugeordnet , in dem die für die Reinigung erforderlichen Daten in Etiketten gespeichert wurden.



Dieser Ansatz führte zu einer Reihe von Richtlinien, mit denen Git als einzige Quelle der Wahrheit verwendet werden konnte:



  • Beim Löschen eines Zweigs / Tags in Git wurden auch die zugehörigen Bilder in der Registrierung automatisch gelöscht.
  • Die Anzahl der mit Git-Tags und Commits verknüpften Bilder kann durch die Anzahl der im ausgewählten Schema verwendeten Tags und den Zeitpunkt der Erstellung des zugeordneten Commits gesteuert werden.


Im Allgemeinen entsprach die resultierende Implementierung unseren Anforderungen, aber bald erwartete uns eine neue Herausforderung. Tatsache ist, dass wir bei der Verwendung von Tagging-Schemata für Git-Grundelemente auf eine Reihe von Mängeln gestoßen sind. (Da ihre Beschreibung außerhalb des Geltungsbereichs dieses Artikels liegt, kann jeder die Details hier lesen .) Nachdem wir uns für einen effizienteren Tagging-Ansatz (inhaltsbasiertes Tagging) entschieden hatten, mussten wir die Implementierung der Bildbereinigung überarbeiten.



Neuer Algorithmus



Warum? Wenn es als inhaltsbasiert markiert ist, kann jedes Tag mehrere Commits in Git aufnehmen. Beim Bereinigen von Bildern können Sie sich nicht mehr nur auf das Commit verlassen, bei dem das neue Tag zur Registrierung hinzugefügt wurde.



Für den neuen Reinigungsalgorithmus wurde beschlossen, sich von Tagging-Schemata zu entfernen und den Prozess auf Metabildern aufzubauen , in denen jeweils eine Reihe von:



  • das Commit, für das die Veröffentlichung durchgeführt wurde (es spielt keine Rolle, ob das Bild hinzugefügt, geändert oder in der Containerregistrierung gleich geblieben ist);
  • und unsere interne Kennung, die dem erstellten Image entspricht.


Mit anderen Worten, die veröffentlichten Tags wurden mit den Commits in Git verknüpft .



Endgültige Konfiguration und allgemeiner Algorithmus



Bei der Konfiguration der Bereinigung haben Benutzer jetzt Zugriff auf Richtlinien, mit denen die Auswahl der tatsächlichen Bilder ausgeführt wird. Jede solche Richtlinie ist definiert:



  • mehrere Referenzen, d.h. Git-Tags oder Git-Zweige, die beim Crawlen verwendet werden;
  • und die Grenze der erforderlichen Bilder für jede Referenz aus dem Satz.


Zur Veranschaulichung sah die Standardrichtlinienkonfiguration folgendermaßen aus:



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


Diese Konfiguration enthält drei Richtlinien, die den folgenden Regeln entsprechen:



  1. Speichern Sie ein Bild für die letzten 10 Git-Tags (bis zu dem Datum, an dem das Tag erstellt wurde).
  2. Speichern Sie nicht mehr als 2 Bilder, die in der letzten Woche veröffentlicht wurden, für nicht mehr als 10 Filialen mit Aktivität in der letzten Woche.
  3. Sparen Sie 10 Bilder für jeden Zweig main, stagingund production.


Der endgültige Algorithmus wird auf die folgenden Schritte reduziert:



  • Manifeste aus der Containerregistrierung abrufen.
  • Ausgenommen Bilder, die in Kubernetes verwendet werden, weil Wir haben sie bereits durch Abfragen der K8s-API vorab ausgewählt.
  • Scannen des Git-Verlaufs und Ausschließen von Bildern für bestimmte Richtlinien.
  • Entfernen der verbleibenden Bilder.


Zurück zu unserer Abbildung:







Mit werf geschieht Folgendes: Selbst wenn Sie werf nicht verwenden, kann ein ähnlicher Ansatz für die erweiterte Bereinigung von Bildern - in der einen oder anderen Implementierung (gemäß dem bevorzugten Ansatz zum Markieren von Bildern) - auch in anderen Systemen angewendet werden. / Dienstprogramme. Um dies zu tun, reicht es aus, sich an die auftretenden Probleme zu erinnern und die Möglichkeiten in Ihrem Stapel zu finden, die es Ihnen ermöglichen, ihre Lösung auf die reibungsloseste Weise zu erstellen. Wir hoffen, dass der Weg, den wir gegangen sind, dazu beiträgt, Ihren speziellen Fall mit neuen Details und Gedanken zu betrachten.



Fazit



  • Früher oder später sind die meisten Teams mit dem Problem des Registrierungsüberlaufs konfrontiert.
  • Bei der Suche nach Lösungen müssen zunächst die Kriterien für die Relevanz des Bildes festgelegt werden.
  • Die von den beliebten Containerregistrierungsdiensten angebotenen Tools ermöglichen eine sehr einfache Bereinigung, bei der die "Außenwelt" nicht berücksichtigt wird: die in Kubernetes verwendeten Bilder und die Besonderheiten der Teamworkflows.
  • Ein flexibler und effizienter Algorithmus muss ein Verständnis für CI / CD-Prozesse haben und nicht nur mit Docker-Bilddaten arbeiten.


PS



Lesen Sie auch in unserem Blog:






All Articles