Wie wir unsere Docker-Bauzeiten um 40% reduziert haben
04.10.2023
•
Niels Claeys
Dieser Beitrag beschreibt zwei Möglichkeiten, das Erstellen Ihrer Docker-Images zu beschleunigen: Das Caching von Build-Informationen remote und die Verwendung der Link-Option beim Kopieren von Dateien.
Ähnlich wie viele Unternehmen erstellen wir Docker-Images für alle Komponenten, die in unserem Produkt verwendet werden. Im Laufe der Zeit sind einige dieser Images immer größer geworden und auch unsere CI-Bauten benötigten immer länger. Mein Ziel ist es, dass CI-Bauten nicht länger als 5 Minuten dauern. Die Idee hinter dieser Zeitspanne stammt aus der Tatsache, dass dies die ideale Dauer für eine Kaffeepause ist. Wenn Builds länger dauern, verlangsamt sich die Produktivität der Entwickler.
Der Grund für den Produktivitätsverlust liegt an:
Entwickler müssen auf den Abschluss des Builds warten und verschwenden dadurch Zeit
Entwickler beginnen mit etwas Neuem und kommen später darauf zurück. Dies erfordert mehr Kontextwechsel, was oft auch zu Ineffizienzen führt.

In diesem Blogbeitrag möchte ich 2 kleine Änderungen veranschaulichen, die wir angewendet haben und die zu einer drastischen Verbesserung unserer Build-Zeiten führten. Bevor wir uns auf diese Verbesserungen konzentrieren, stellen Sie sicher, dass Sie bereits die Best Practices für die Erstellung von Dockerfiles befolgen, wie:
die Anzahl der Schichten minimieren
Multistage-Bauten verwenden
ein minimales Basis-Image verwenden
…
Buildkit vs Buildx
Beginnen wir mit der Erklärung von Buildkit und Buildx, da beide Begriffe oft austauschbar verwendet werden, aber sie nicht dasselbe sind. Bevor ich diesen Beitrag schrieb, verstand ich den Unterschied zwischen beiden auch nicht vollständig.
Buildkit
Buildkit ist das verbesserte Backend, um den veralteten Docker-Bauer zu ersetzen. Es ist seit 2018 in Docker integriert und wurde ab Docker-Engine 23.0 zum Standardbauer.
Es bietet viele interessante Funktionen:
verbesserte Cache-Fähigkeiten
Paralleles Bauen von verschiedenen Schichten
faule Beschaffung des Basis-Images (≥ Buildkit 0.9)
Wenn Sie Buildkit verwenden, fällt Ihnen schnell auf, dass die Ausgabe des docker build Befehls sauberer und strukturierter aussieht.
Eine typische Möglichkeit, Buildkit mit einer Docker-Version vor 23.0 zu verwenden, besteht darin, das Buildkit-Argument wie folgt festzulegen:
Buildx
Buildx ist ein Plugin für Docker, das es Ihnen ermöglicht, das volle Potenzial von Buildkit in Docker auszuschöpfen. Es wurde geschaffen, weil Buildkit viele neue Konfigurationsoptionen unterstützt, die nicht alle auf eine rückwärtskompatible Weise in den docker build Befehl integriert werden können.
Über das Erstellen von Images hinaus unterstützt Buildx die Verwaltung mehrerer Builder. Dies kann in CI nützlich sein, um abgegrenzte Umgebungen mit unterschiedlicher Konfiguration zu definieren, da sie den gemeinsamen Docker-Daemon nicht ändern.
Sie können mit Buildx wie folgt beginnen:
Vom Remote-Cache profitieren
Eine erste Möglichkeit, Ihre Builds zu beschleunigen, besteht darin, Ihr Image in einem Remote-Registry zu cachen. Auf diese Weise können Sie vom Build-Cache profitieren, selbst wenn Ihr Build auf einem anderen Computer durchgeführt wird, wie dies typischerweise in CI der Fall ist. Viele Leute haben als workaround die neueste Version des Images vor dem Erstellen einer neuen Image-Version abgerufen. Der Vorteil ist, dass Sie die Schichten, die sich nicht geändert haben, zu den Kosten des anfänglichen Pulls des vollständigen Images cachen können. Das Abrufen des vollständigen Images kann eine Weile dauern, aber es gibt auch keine Garantie, dass Schichten wiederverwendet werden können. Um dies zu veranschaulichen, verwendeten wir die folgenden Befehle:
Mit Buildx können Sie die Cache-Informationen an einem Remote-Ort speichern (z. B. Container-Registry, Blob-Speicher, …). Der Builder überprüft, ob eine bestimmte Schicht bereits vorhanden ist, und falls ja, wird sie wiederverwendet, anstatt sie erneut zu erstellen. Dies kann sogar ohne das lokale Abrufen der Schicht erfolgen. Um von diesem Mechanismus zu profitieren, haben wir die vorherigen Befehle neu gestaltet:
Modus „max“ bedeutet, dass wir Build-Informationen für jede Schicht speichern, sogar Schichten, die nicht im resultierenden Image verwendet werden (z. B. bei Verwendung von Multistage-Bauten). Standardmäßig wird der Modus „min“ verwendet, der nur Build-Informationen über die Schichten speichert, die im endgültigen Image vorhanden sind.
Ein Sonderfall des Cachings besteht darin, die Cache-Daten „inline“ zu speichern, was bedeutet, dass sie zusammen mit dem Image zwischengespeichert werden. Diese Option wird auch unterstützt, wenn Sie Buildkit ohne Buildx verwenden. Es ist am einfachsten zu beginnen, jedoch komplizierter bei der Verwendung von Multistage-Bauten und bietet keine klare Trennung zwischen den Ausgaben der Artefakte und dem Cache. Die Befehle zum Speichern der Cache-Daten „inline“ sehen wie folgt aus:
Neue Möglichkeit, Dateien zum Docker-Image hinzuzufügen
Docker hat eine neue Version seiner Syntax für die Erstellung von Dockerfiles eingeführt, nämlich: #syntax=docker/dockerfile:1.4. Sie unterstützt eine zusätzliche Link-Option für COPY und ADD Befehle.
Früher, wenn Sie den COPY oder ADD Befehl verwendeten, erstellte der Builder einen neuen Snapshot, der die neuen Dateien mit dem bereits vorhandenen Dateisystem zusammenführte. Die Konsequenz ist, dass die übergeordneten Schichten vor dieser Operation existieren müssen, da sonst das Zielverzeichnis möglicherweise noch nicht existiert. Am Ende besteht Ihr Image (das Ergebnis des Build-Befehls) aus Tarballs pro Schicht, die den Unterschied zwischen den jeweiligen Snapshots enthalten.
Bei Verwendung der Link-Option werden neue Dateien in ihrem eigenen Snapshot abgelegt, ohne von den vorherigen Schichten abhängig zu sein. Die verlinkten Dateien werden in ihrem eigenen Tarball gespeichert, und die verschiedenen Tarballs werden miteinander verknüpft, ohne vom vorhandenen Dateisystem abhängig zu sein, wie das folgende Bild illustriert.

Der große Vorteil besteht darin, dass die Dateien nicht mehr von vorherigen Schichten abhängig sind. Die Schicht kann wiederverwendet werden, solange sich die Dateien nicht geändert haben, selbst wenn sich die übergeordneten Schichten geändert haben.
Darüber hinaus kann dies auch die Geschwindigkeit Ihrer Builds verbessern, da mehrere Schichten, die Daten kopieren, jetzt parallel ausgeführt werden können.
Fazit
Dieser Blogbeitrag beschreibt einige neue Erkenntnisse, die wir nach der Optimierung unserer CI-Pipelines gewonnen haben. Ich bespreche 2 kleine Änderungen, die zu einer 40-prozentigen Reduzierung unserer gesamten Docker-Bauzeiten führten:
Speichern der Build-Cache-Informationen remote
Verwenden der Link-Option, wenn Sie Hinzufügen, Dateien kopieren in Ihr Docker-Image
Latest
Why not to build your own data platform
A round-table discussion summary on imec’s approach to their data platform
Securely use Snowflake from VS Code in the browser
A primary activity among our users involves utilizing dbt within the IDE environment.
The benefits of a data platform team
For years, organizations have been building and using data platforms to get value out of data.