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-Servern đŸ”„ Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Servern | ProHoster