Docker-Images können jetzt auch in werf aus einer normalen Dockerfile gesammelt werden

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.

Docker-Images können jetzt auch in werf aus einer normalen Dockerfile gesammelt werden

Es geht um werf — 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 als dapp bekannt).

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:

  1. 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.
  2. Bei Änderungen an den Projektdateien sollte der Builder schnell eine neue Schicht erstellen, indem er einen Patch auf die geänderten Dateien anwendet.
  3. 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 wechselten wir zu Golang. — die Konfiguration unseres Builders wird nun in einer YAML-Datei beschrieben.

Docker-Images können jetzt auch in werf aus einer normalen Dockerfile gesammelt werden
Die alte Konfiguration für dapp in Ruby

Docker-Images können jetzt auch in werf aus einer normalen Dockerfile gesammelt werden
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 Dokumentation..

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 der Projektseite.

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 werf v1.0.3-beta.1. 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:

Docker-Images können jetzt auch in werf aus einer normalen Dockerfile gesammelt werden

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 der Dokumentationsseite.

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?

  1. 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 hier).
  2. Für das Stage dockerfile berechnet 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. dockerfile und 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 diesem Bericht).
  3. erläutert. Die gesammelten Images können dann mit dem Befehl werf publish (oder werf 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:

  1. Wenn .git bleibt im finalen Image, was gegen die Prinzipien verstößt 12-Factor-App: da das endgültige Image mit einem einzelnen Commit verknüpft sein muss, sollte es keine Möglichkeit geben, git checkout eines beliebigen Commits zu machen.
  2. .git vergröß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 .git aus dem finalen Bild funktioniert nicht: das Image wird trotzdem eine unnötige Schicht erwerben – so funktioniert Docker.
  3. 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]/yourproject bei aktivierter paralleler Erstellung. Die unnötige Neubauten sind darauf zurückzuführen, dass das Verzeichnis .git in 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 Dokumentation.).

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. werf!

P.S. Dokumentationsliste zu diesem Thema

Lesen Sie auch in unserem Blog: „werf — unser Tool für CI/CD in Kubernetes (Übersicht und Video des Vortrags)».

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster