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:

DOCKER_BUILDKIT=1 docker build --platform linux/amd64 . -t someImage:someVersion
DOCKER_BUILDKIT=1 docker push someImage:someVersion

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:

docker buildx create --bootstrap --name builder
docker buildx use builder

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:

docker pull someImage:latest || true
docker build --platform linux/amd64 . \
-t someImage:someVersion \
-f Dockerfile \
--cache-from someImage:latest

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:

docker buildx build --platform linux/amd64 . \
-t someImage:someVersion - push \
--cache-to type=registry,ref=someCachedImage:someVersion,mode=max
--cache-from type=registry,ref=someCachedImage:someVersion

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:

docker buildx build - platform linux/amd64 . \
-t someImage:someVersion --push \
--cache-to type=inline,mode=max \
--cache-from someImage:somePreviousVersion

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.

FROM baseImage:version
COPY binary /opt

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.

# syntax=docker/dockerfile:1.4
FROM baseImage:version
COPY [--chown=<user>:<group>] [--chmod=<perms>

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
Securely use Snowflake from VS Code in the browser
Securely use Snowflake from VS Code in the browser

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
The benefits of a data platform team
The benefits of a data platform team

The benefits of a data platform team

For years, organizations have been building and using data platforms to get value out of data.

Hinterlasse deine E-Mail-Adresse, um den Dataminded-Newsletter zu abonnieren.

Hinterlasse deine E-Mail-Adresse, um den Dataminded-Newsletter zu abonnieren.

Hinterlasse deine E-Mail-Adresse, um den Dataminded-Newsletter zu abonnieren.

Belgien

Vismarkt 17, 3000 Leuven - HQ
Borsbeeksebrug 34, 2600 Antwerpen


USt-IdNr. DE.0667.976.246

Deutschland

Spaces Kennedydamm,
Kaiserswerther Strasse 135, 40474 Düsseldorf, Deutschland


© 2025 Dataminded. Alle Rechte vorbehalten.


Vismarkt 17, 3000 Leuven - HQ
Borsbeeksebrug 34, 2600 Antwerpen

USt-IdNr. DE.0667.976.246

Deutschland

Spaces Kennedydamm, Kaiserswerther Strasse 135, 40474 Düsseldorf, Deutschland

© 2025 Dataminded. Alle Rechte vorbehalten.


Vismarkt 17, 3000 Leuven - HQ
Borsbeeksebrug 34, 2600 Antwerpen

USt-IdNr. DE.0667.976.246

Deutschland

Spaces Kennedydamm, Kaiserswerther Strasse 135, 40474 Düsseldorf, Deutschland

© 2025 Dataminded. Alle Rechte vorbehalten.