Besser spät als nie. Oder wie wir fast einen ernsthaften Fehler gemacht hätten, weil wir keine Unterstützung für gängige Dockerfiles zum Erstellen von Anwendungsimages hatten.

Es geht um — ein GitOps-Tool, das sich in jedes CI/CD-System integriert und die gesamte Lebenszyklusverwaltung von Anwendungen ermöglicht, indem es:
- Images erstellt und veröffentlicht,
- Anwendungen in Kubernetes bereitstellt,
- nicht mehr benötigte Images durch spezielle Richtlinien entfernt.
Die Philosophie des Projekts besteht darin, grundlegende Werkzeuge in ein einheitliches System zu integrieren, das DevOps-Ingenieuren die Kontrolle über Anwendungen gibt. Wo möglich, sollten bereits bestehende Tools (wie Helm und Docker) verwendet werden. Wenn jedoch keine Lösung für eine bestimmte Aufgabe existiert, können wir alles Notwendige dafür schaffen und unterstützen.
Vorgeschichte: unser Image-Builder
So kam es, dass wir für den Image-Builder in werf einen gewohnten Dockerfile vermissten. Wenn wir kurz auf die Geschichte des Projekts zurückblicken, wird sichtbar, dass dieses Problem bereits in den ersten Versionen von werf (damals noch ).
auftrat. Als wir ein Tool zur Erstellung von Anwendungen in Docker-Images entwickelten, merkten wir schnell, dass Dockerfile für einige spezifische Aufgaben nicht geeignet war:
- Die Notwendigkeit, typische kleine Webanwendungen nach folgendem Standard-Schema zu erstellen:
- Systemabhängigkeiten der Anwendung zu installieren,
- Bündel von Abhängigkeiten der Anwendung zu installieren,
- Assets zu sammeln,
- und das Wichtigste — den Code im Image schnell und effizient zu aktualisieren.
- Bei Änderungen in den Projektdateien muss der Builder schnell eine neue Schicht erstellen, indem er einen Patch auf die geänderten Dateien anwendet.
- Wenn bestimmte Dateien geändert werden, muss die entsprechende abhängige Phase neu erstellt werden.
Heute bietet unser Builder viele weitere Funktionen, aber die ursprünglichen Wünsche und Impulse waren so.
Insgesamt haben wir kurzerhand die verwendete Programmiersprache gewählt (siehe unten) und sind losgezogen — um umzusetzen unseren eigenen DSL! Entsprechend den Anforderungen war es vorgesehen, den Prozess der schrittweisen Erstellung und die Abhängigkeiten dieser Phasen von Dateien zu beschreiben. Ergänzt wurde es durch unseren eigenen Builder, der DSL in das Endziel — das erstellte Image — umwandelte. Zunächst war DSL in Ruby, und im Zuge des wurde die Konfiguration unseres Builders in einer YAML-Datei beschrieben.

Alterer Konfigurationsdatei für dapp in Ruby

Aktuelle Konfigurationsdatei für werf in YAML
Der Arbeitsmechanismus des Builders hat sich im Laufe der Zeit ebenfalls verändert. Zunächst haben wir einfach eine temporäre Dockerfile aus unserer Konfiguration zur Laufzeit generiert. Anschließend begannen wir, Buildanweisungen in temporären Containern auszuführen und sie zu committen.
NB: Derzeit ist unser Builder, der mit seiner Konfiguration (in YAML) arbeitet und Stapel-Builder genannt wird, zu einem leistungsstarken Werkzeug gereift. Eine ausführliche Beschreibung verdient eigene Artikel, während die wichtigsten Details aus .
Das Bewusstsein für das Problem
Aber wir haben, was nicht sofort klar wurde, einen Fehler gemacht: Wir haben die Möglichkeit nicht hinzugefügt, Images über die Standard-Dockerfile zu bauen und sie in die gleiche Infrastruktur des umfassenden Anwendungsmanagements zu integrieren (d.h. Images zu bauen, sie zu deployen und sie zu bereinigen). Wie konnte man ein Deployment-Tool für Kubernetes entwickeln und dabei den Support für Dockerfile, das heißt die standardisierte Art der Beschreibung von Images für die meisten Projekte, nicht implementieren?
Anstatt auf diese Frage zu antworten, bieten wir eine Lösung. Was tun, wenn Sie bereits ein Dockerfile (oder eine Reihe von Dockerfiles) haben und werf verwenden möchten?
NB: Übrigens, warum sollten Sie überhaupt werf verwenden wollen? Die Hauptmerkmale lassen sich wie folgt zusammenfassen:
- vollständiger Lebenszyklus des Anwendungsmanagements einschließlich der Bereinigung von Images;
- Möglichkeit, den Build mehrerer Images aus einer einzigen Konfiguration zu steuern;
- verbesserten Deployment-Prozess für Helm-kompatible Charts.
Eine vollständige Liste der Funktionen finden Sie auf .
Also, wenn wir früher vorgeschlagen hätten, das Dockerfile in unsere Konfiguration umzuschreiben, sagen wir jetzt gerne: „Lassen Sie werf Ihre Dockerfiles bauen!“
Wie verwendet man das?
Die vollständige Implementierung dieses Features wurde in der Version . Das Grundprinzip ist einfach: Der Benutzer gibt den Pfad zur bestehenden Dockerfile in der werf-Konfiguration an und führt dann den Befehl aus werf build… und das war's — werf wird das Image bauen. Lassen Sie uns ein abstraktes Beispiel betrachten.
Lassen Sie uns den nächsten Dockerfile im Stammverzeichnis des Projekts deklarieren:
FROM ubuntu:18.04
RUN echo Bau ... Und erklären wir werf.yaml, der dieses nutzt Dockerfile:
configVersion: 1
project: dockerfile-example
---
image: ~
dockerfile: .\/Dockerfile Das ist alles! Jetzt bleibt es gestart werden werf build:

Darüber hinaus kann der nächste werf.yaml für den gleichzeitigen Bau mehrerer Images aus verschiedenen Dockerfiles deklariert werden:
configVersion: 1
project: dockerfile-example
---
image: backend
dockerfile: .\/dockerfiles\/Dockerfile-backend
---
image: frontend
dockerfile: .\/dockerfiles\/Dockerfile-frontend Endlich wird auch die Übertragung zusätzlicher Build-Parameter unterstützt, wie z. B. --build-arg und --add-host — über die werf-Konfiguration. Eine vollständige Beschreibung der Dockerfile-Image-Konfiguration ist verfügbar auf .
Wie funktioniert das?
Während des Build-Vorgangs funktioniert der Standard-Cache der 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 einer Phase, die genannt wird
dockerfile(weiterführende Informationen zu Phasen in werf können gelesen werden ). - Für die Phase
dockerfileberechnet werf eine Signatur, die von dem Inhalt der Dockerfile-Konfiguration abhängt. Wenn die Dockerfile-Konfiguration geändert wird, ändert sich die Signatur der Phasedockerfileund werf initiiert die Neubau dieser Phase mit der neuen Dockerfile-Konfiguration. Wenn sich die Signatur jedoch nicht ändert, verwendet werf das Image aus dem Cache (nähere Informationen zur Verwendung von Signaturen in werf wurden in ). - Die erstellten Images können dann mit dem Befehl
werf publish(oderwerf build-and-publish) veröffentlicht und zur Bereitstellung in Kubernetes verwendet werden. Die veröffentlichten Images im Docker-Registry werden mit den Standardbereinigungsmethoden von werf bereinigt, das heißt, es erfolgt eine automatische Bereinigung alter Images (älter als N Tage), von Images, die mit nicht existierenden Git-Zweigen verbunden sind, und gemäß anderen Richtlinien.
Weitere Informationen zu den hier beschriebenen Punkten finden Sie in der Dokumentation:
- ;
- ;
- .
Anmerkungen und Vorsichtsmaßnahmen
1. Externe URLs in ADD werden nicht unterstützt
Derzeit wird die Verwendung externer URLs in der Direktive ADD. Werf wird bei einer Änderung der Ressource unter der angegebenen URL keine Neubau initiieren. Diese Funktion wird in naher Zukunft hinzugefügt.
2. .git darf nicht in das Image hinzugefügt werden
Im Allgemeinen ist das Hinzufügen des Verzeichnisses .git zum Image eine schlechte Praxis, und das sind die Gründe:
- Wenn
.gitbleibt im finalen Image, was die Prinzipien von : da das finale Image mit einem Commit verknüpft sein sollte, darf es keine Möglichkeit geben, einengit checkoutwillkürlichen Commit zu machen. -
.giterhöht die Größe des Images (das Repository könnte groß sein, weil irgendwann große Dateien hinzugefügt wurden und später gelöscht wurden). Die Größe des Arbeitsbaums, der nur mit einem bestimmten Commit verbunden ist, hängt nicht von der Historie der Operationen in Git ab. Dabei führt das Hinzufügen und anschließende Löschen.gitDas finale Image wird nicht funktionieren: Das Image wird dennoch eine zusätzliche Schicht erhalten – so funktioniert Docker. - Docker kann eine unnötige Neuaufbau-Aktion 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]/yourprojectaktiviertem Parallelaufbau. Die unnötige Neuaufbau-Aktion wird damit zusammenhängen, dass das Verzeichnis.gitin den verschiedenen geklonnten Versionen des gleichen Repositories unterschiedlich ist, auch wenn derselbe Commit gebaut wird.
Der letzte Punkt hat auch eine Konsequenz bei der Verwendung von werf. Werf erfordert, dass der gebaute Cache bei der Ausführung bestimmter Befehle vorhanden ist (z. B. werf deploy). Während der Ausführung solcher Befehle berechnet werf die Signaturen der Stufen für die angegebenen Images, werf.yaml, und diese müssen sich im Build-Cache befinden – andernfalls kann der Befehl nicht fortgesetzt werden. Wenn jedoch die Signatur der Stufen von den Inhalten .gitabhängt, erhalten wir einen instabilen Cache, der nicht gegen Änderungen in irrelevanten Dateien resistent ist, und werf kann einen solchen Fehler nicht verzeihen (siehe dazu ).
Im Allgemeinen das Hinzufügen nur bestimmter notwendiger Dateien über die Anweisung ADD in jedem Fall erhöht die Effizienz und Zuverlässigkeit des Geschriebenen Dockerfile, sowie die Resistenz des in Bezug auf das Build-Cache gegen irrelevante Änderungen in Git. DockerfileUnser ursprünglicher Weg, einen eigenen Builder für spezifische Bedürfnisse zu schreiben, war mühsam, ehrlich und geradlinig: Anstatt Notlösungen über dem Standard-Dockerfile zu verwenden, haben wir unsere eigene Lösung mit benutzerdefinierter Syntax geschrieben. Und das brachte seine Vorteile: Der Stapel-Builder erfüllt seine Aufgabe hervorragend.
Fazit
Allerdings haben wir bei der Erstellung unseres eigenen Builders die Unterstützung bereits vorhandener Dockerfiles außer Acht gelassen. Dieser Mangel ist jetzt behoben, und in Zukunft planen wir, die Unterstützung von Dockerfiles parallel zu unserem benutzerdefinierten Stapel-Builder für verteilte Builds und für Builds mit Kubernetes weiterzuentwickeln (d. h. Builds auf Runnern innerhalb von Kubernetes, wie es in kaniko gemacht wird).
Also, falls Sie zufällig ein paar Dockerfiles herumliegen haben...
P.S. Eine Liste von Dokumentationen zu diesem Thema versuchen Sie es !
Leitfäden für einen schnellen Einstieg
- ;
- ;
- ;
- ;
- ;
- ;
- .
Besser spät als nie.».
Quelle: habr.com
