Besser spät als nie. Oder wie wir fast einen schwerwiegenden Fehler gemacht hätten, weil wir keine Unterstützung für normale Dockerfiles zur Erstellung von Anwendungsbildern hatten.

Es geht um — ein GitOps-Tool, das sich in jede CI/CD-System integrieren lässt und das gesamte Anwendungslebenszyklusmanagement ermöglicht, einschließlich:
- Erstellung und Veröffentlichung von Bildern,
- Bereitstellung von Anwendungen in Kubernetes,
- Löschung ungenutzter Bilder gemäß speziellen Richtlinien.
Die Philosophie des Projekts besteht darin, Low-Level-Tools in ein einheitliches System zu integrieren, das DevOps-Ingenieuren die Kontrolle über Anwendungen gibt. So weit wie möglich sollen bereits vorhandene Tools (wie Helm und Docker) verwendet werden. Falls jedoch keine Lösung für ein bestimmtes Problem existiert, können wir alles Notwendige dafür erstellen und pflegen.
Hintergrund: unser Bildgenerator
So kam es zu dem Bildgenerator in werf: uns fehlte das vertraute Dockerfile. Wenn wir einen schnellen Blick auf die Geschichte des Projekts werfen, wurde dieses Problem bereits in den ersten Versionen von werf (damals noch ).
Bei der Entwicklung eines Tools zur Erstellung von Anwendungen in Docker-Images haben wir schnell festgestellt, dass ein Dockerfile für einige spezifische Aufgaben nicht geeignet ist:
- Die Notwendigkeit, typische kleine Webanwendungen nach einem standardisierten Schema zu erstellen:
- Systemabhängigkeiten der Anwendung zu installieren,
- die Bundle-Bibliotheken der Anwendung zu installieren,
- Assets zu sammeln,
- und das Wichtigste – den Code im Image schnell und effizient zu aktualisieren.
- Bei Änderungen an den Projektdateien sollte der Builder schnell eine neue Schicht erstellen, indem er einen Patch auf die geänderten Dateien anwendet.
- Wenn bestimmte Dateien geändert wurden, muss die entsprechende abhängige Phase neu zusammengestellt werden.
Heute verfügt unser Builder über viele weitere Möglichkeiten, aber die ursprünglichen Wünsche und Impulse waren solche.
Kurz gesagt, wir haben uns mit der Programmiersprache bewaffnet, die wir verwenden, (siehe unten) und sind auf den Weg gegangen – unser eigenes DSL! Entsprechend den gestellten Anforderungen wurde es entwickelt, um den Aufbauprozess in Phasen zu beschreiben und die Abhängigkeiten dieser Phasen von Dateien zu definieren. Darüber hinaus ergänzte es unseren eigenen Builder, der DSL in das endgültige Ziel — ein erstelltes Abbild — verwandelte. Ursprünglich war DSL in Ruby geschrieben, und im Laufe der Zeit — die Konfiguration unseres Builders wird nun in einer YAML-Datei beschrieben.

Die alte Konfiguration für dapp in Ruby

Die aktuelle Konfiguration für werf in YAML
Der Mechanismus des Builders hat sich ebenfalls im Laufe der Zeit geändert. Zunächst generierten wir einfach zur Laufzeit ein temporäres Dockerfile aus unserer Konfiguration, und später begannen wir, Build-Anweisungen in temporären Containern auszuführen und zu committen.
NB: Gegenwärtig hat sich unser Builder, der mit seiner eigenen Konfiguration (in YAML) arbeitet und Stapel-Builder genannt wird, bereits zu einem leistungsstarken Werkzeug entwickelt. Eine ausführliche Beschreibung verdient eigene Artikel, während die wichtigsten Details aus dem .
Bewusstsein für das Problem
Aber wir haben, allerdings nicht sofort, verstanden, dass wir einen Fehler gemacht haben: Wir haben die Möglichkeit nicht hinzugefügt, Abbilder über ein Standard-Dockerfile zu erstellen. und diese in die gleiche Infrastruktur für das umfassende Anwendungsmanagement zu integrieren (d.h. Images zu erstellen, bereitzustellen und zu bereinigen). Wie könnte man ein Bereitstellungstool für Kubernetes entwickeln, ohne die Unterstützung von Dockerfile zu implementieren, dem standardisierten Weg, um Images für die meisten Projekte zu beschreiben?
Anstelle einer Antwort auf diese Frage bieten wir eine Lösung dafür an. Was tun, wenn Sie bereits ein Dockerfile (oder eine Reihe von Dockerfiles) haben und werf verwenden möchten?
NB: Übrigens, warum sollten Sie überhaupt daran interessiert sein, werf zu verwenden? Die Hauptfunktionen lassen sich wie folgt zusammenfassen:
- vollständiger Anwendungsmanagement-Zyklus einschließlich der Bereinigung von Images;
- die Möglichkeit, mehrere Images aus einer einzigen Konfiguration gleichzeitig zu verwalten;
- ein verbesserter Bereitstellungsprozess für mit Helm kompatible Charts.
Eine vollständige Liste finden Sie auf .
Wenn wir früher vorgeschlagen hätten, das Dockerfile in unsere Konfiguration umzuschreiben, können wir jetzt mit Freude sagen: „Lassen Sie werf Ihre Dockerfiles erstellen!“
Wie verwendet man das?
Die vollständige Umsetzung dieser Möglichkeit erschien in der Version . Das allgemeine Prinzip ist einfach: Der Benutzer gibt den Pfad zur bestehenden Dockerfile in der werf-Konfiguration an und startet dann den Befehl. werf build… und das ist alles – werf wird das Image erstellen. Schauen wir uns ein abstraktes Beispiel an.
Wir deklarieren den nächsten Dockerfile im Projektstamm:
FROM ubuntu:18.04
RUN echo Baue ... Und wir deklarieren werf.yaml, das dies verwendet Dockerfile:
configVersion: 1
project: dockerfile-example
---
image: ~
dockerfile: ./Dockerfile Fertig! Es bleibt nur noch seinen eigenen Server starten. werf build:

Außerdem kann der nächste deklariert werden werf.yaml um mehrere Images gleichzeitig aus verschiedenen Dockerfiles zu erstellen:
configVersion: 1
project: dockerfile-example
---
image: backend
dockerfile: ./dockerfiles/Dockerfile-backend
---
image: frontend
dockerfile: ./dockerfiles/Dockerfile-frontend Schließlich wird auch die Übertragung zusätzlicher Build-Parameter unterstützt – wie etwa --build-arg und --add-host — durch die werf-Konfiguration. Eine vollständige Beschreibung der Dockerfile-Image-Konfiguration ist verfügbar auf .
Wie funktioniert das?
Während des Builds funktioniert der Standard-Cache von lokalen Schichten in Docker. Wichtig ist jedoch, dass werf auch die Dockerfile-Konfiguration in seine Infrastruktur integriert. Was bedeutet das?
- Jedes Image, das aus einem Dockerfile erstellt wird, besteht aus einem Stage mit dem Namen
dockerfile(mehr dazu, was Stages in werf sind, kann man nachlesen ). - Für das Stage
dockerfileberechnet werf die Signatur, die von den Inhalten der Dockerfile-Konfiguration abhängt. Wenn die Dockerfile-Konfiguration geändert wird, ändert sich die Signatur des Stages.dockerfileund werf initiiert einen Neuaufbau dieser Phase mit der neuen Dockerfile-Konfiguration. Wenn sich die Signatur nicht ändert, nimmt werf das Image aus dem Cache. (mehr über die Verwendung von Signaturen in werf wurde in ). - erläutert. Die gesammelten Images können dann mit dem Befehl
werf publish(oderwerf build-and-publish) veröffentlicht und für das Deployment in Kubernetes verwendet werden. Die veröffentlichten Images im Docker Registry werden mit den Standardbereinigungswerkzeugen von werf gereinigt, d.h. es erfolgt eine automatische Bereinigung alter Images (älter als N Tage), Images, die mit nicht existierenden Git-Zweigen verknüpft sind, und nach anderen Richtlinien.
Weitere Informationen zu den hier genannten Punkten finden Sie in der Dokumentation:
- ;
- ;
- .
Hinweise und Vorsichtsmaßnahmen
1. Externe URLs in ADD werden nicht unterstützt.
Derzeit wird die Verwendung einer externen URL in der Direktive ADDnicht unterstützt. Werf wird beim Ändern der Ressource unter der angegebenen URL keinen Neuaufbau initiieren. Diese Möglichkeit ist in Kürze geplant.
2. .git kann nicht in das Image hinzugefügt werden.
Im Allgemeinen ist das Hinzufügen des Verzeichnisses .git zum Image eine unzulässige schlechte Praxis, und das sind die Gründe dafür:
- Wenn
.gitbleibt im finalen Image, was gegen die Prinzipien verstößt : da das endgültige Image mit einem einzelnen Commit verknüpft sein muss, sollte es keine Möglichkeit geben,git checkouteines beliebigen Commits zu machen. -
.gitvergrößert die Größe des Images (das Repository kann groß sein, weil einmal große Dateien hinzugefügt und dann gelöscht wurden). Die Größe des Work-Trees, das nur mit einem bestimmten Commit verbunden ist, hängt jedoch nicht von der Operationshistorie in Git ab. Das Hinzufügen und anschließende Löschen.gitaus dem finalen Bild funktioniert nicht: das Image wird trotzdem eine unnötige Schicht erwerben – so funktioniert Docker. - Docker kann unnötige Neubauten initiieren, selbst wenn der gleiche Commit aus verschiedenen Work-Trees gebaut wird. Zum Beispiel erstellt GitLab separate geklonte Verzeichnisse in
/home/gitlab-runner/builds/HASH/[0-N]/yourprojectbei aktivierter paralleler Erstellung. Die unnötige Neubauten sind darauf zurückzuführen, dass das Verzeichnis.gitin verschiedenen geklonnten Versionen des gleichen Repositories unterschiedlich ist, selbst wenn der gleiche Commit kompiliert wird.
Der letzte Punkt hat auch Auswirkungen bei der Verwendung von werf. Werf verlangt, dass der gebaute Cache bei der Ausführung bestimmter Befehle vorhanden ist (zum Beispiel, werf deploy). Während der Arbeit solcher Kommandos berechnet werf die Signaturen der Phasen für die angegebenen Images, werf.yaml, und diese müssen im Build-Cache sein – andernfalls kann das Kommando die Arbeit nicht fortsetzen. Sollte jedoch die Signatur der Phasen vom Inhalt abhängen, .git, erhalten wir einen Cache, der unbeständig gegenüber Änderungen in irrelevanten Dateien ist, und werf kann einen solchen Fehler nicht verzeihen (siehe dazu ).
Insgesamt Hinzufügen nur bestimmter notwendiger Dateien durch die Anweisung ADD steigert in jedem Fall die Effizienz und Zuverlässigkeit des geschriebenen Dockerfile, sowie verbessert die Stabilität des Caches, der auf diesem Dockerfile, gegenüber irrelevanten Änderungen in Git.
Zusammenfassung
Unser ursprünglicher Weg, einen eigenen Builder für bestimmte Bedürfnisse zu schreiben, war mühsam, ehrlich und direkt: anstatt auf Standard-Dockerfiles mit Workarounds zurückzugreifen, haben wir unsere eigene Lösung mit einer angepassten Syntax erstellt. Und das hat sich ausgezahlt: Der Stapel-Builder erfüllt seine Aufgabe hervorragend.
Beim Schreiben unseres eigenen Builders haben wir jedoch die Unterstützung bestehender Dockerfiles übersehen. Dieser Mangel wurde jetzt behoben, und wir planen, die Unterstützung von Dockerfiles zusammen mit unserem benutzerdefinierten Stapel-Builder für verteilte Builds und Builds mit Kubernetes weiterzuentwickeln (d.h. Builds auf Runnern innerhalb von Kubernetes, ähnlich wie bei kaniko).
Wenn Sie also noch ein paar Dockerfiles haben... probieren Sie es aus. !
P.S. Dokumentationsliste zu diesem Thema
- ;
- ;
- ;
- ;
- ;
- ;
- .
Lesen Sie auch in unserem Blog: „».
Quelle: habr.com
