38 Dockerfile-Verarbeitung

Ein Dockerfile ist weit mehr als ein Skript, das Anweisungen in ein Image gießt. Es ist eine deklarative Beschreibung eines schichtweisen Build-Prozesses, der reproduzierbar, deterministisch und auditierbar sein muss. Podman – intern auf Buildah basierend – interpretiert Dockerfiles strikt nach der OCI/Bildbau-Logik und erzeugt daraus ein genau definiertes Layer-Modell. Die Qualität eines Images hängt daher in hohem Maße davon ab, wie präzise das Dockerfile geschrieben wurde und wie gut der Entwickler die semantischen Implikationen der einzelnen Anweisungen versteht.

38.1 Das Layer-Konzept als strukturelle Grundlage

Ein Dockerfile besteht aus Anweisungen, die jeweils eine neue Layer erzeugen oder Metadaten aktualisieren. Der Aufbau folgt einem unveränderlichen Grundsatz: jede Zeile ist ein potenzielles Caching-Grenzobjekt und ein Bestandteil der finalen Image-Struktur.

Die elementare Schichtenlogik lässt sich grafisch verdeutlichen:

Dabei gilt: frühere Layer beeinflussen spätere, und jede Änderung in einer frühen Anweisung invalidiert den Cache aller nachfolgenden.

38.2 FROM: das Fundament und zugleich der implizite Vertrag

Die FROM-Anweisung ist das Architekturstatement. Sie definiert:

Wenige Zeilen bestimmen damit den größten Teil der späteren Wartungskosten. Ein Wechsel des Base Images ist vergleichbar mit dem Austausch des Unterbaus eines Hochhauses: technisch machbar, aber aufwendig.

Ein häufiges Missverständnis: FROM legt die Architektur fest, aber ein Multi-Stage-Dockerfile kann problemlos unterschiedliche Architekturen bedienen, solange Buildah/Podman entsprechende Plattformen bereitstellen.

38.3 RUN: deterministische Kommandos und ihr Einfluss auf Caching

RUN ist der am häufigsten missbrauchte Befehl in Dockerfiles. Die Versuchung, ganze Shellskripte einzubetten, ist groß. Technisch betrachtet ist das möglich, aber es erzeugt komplexe Layer, deren Verhalten schwer nachvollziehbar ist. RUN sollte so deterministisch wie möglich sein.

Beispiele für gute RUN-Blöcke:

Schlechte Beispiele:

Ein gut formulierter RUN erzeugt vorhersehbare Layer und verlässliche Caches.

38.4 COPY und ADD: das Transportieren von Kontext

COPY ist die Standardmethode, um Dateien aus dem Build-Kontext in das Image zu übertragen. Der Build-Kontext ist dabei ein eigenes Ökosystem. Unkontrollierte Kontexte führen zu riesigen Images und ineffizienten Builds.

Ein .containerignore (analog zu .dockerignore) ist Pflicht, nicht optional. Wer ganze Repositories kopiert, ohne Node-Modules, Build-Artefakte oder temporäre Dateien auszuschließen, baut unnötig große Layer.

ADD wird oft missverstanden. ADD ist COPY mit zusätzlichen Features (z. B. Entpacken von TAR-Dateien oder automatisches Downloaden von URLs). Genau diese „Magie“ macht ADD aber schwerer kontrollierbar. In Enterprise-Workflows ist ADD selten gewünscht, COPY hingegen eindeutig und sauber.

38.5 ENV, LABEL, EXPOSE, USER – Metadaten und Identität

Diese Anweisungen erzeugen keine Dateisystemschichten, sondern Metadatenlayer. Sie beeinflussen:

Ein Beispiel ist USER: Setzt man ihn zu spät im Dockerfile, laufen Build-Schritte weiterhin als root und erzeugen potenzielle Sicherheitsprobleme innerhalb der Layer. Setzt man ihn zu früh, scheitern Build-Prozesse wegen fehlender Rechte.

In sicherheitskritischen Projekten sind LABELs unverzichtbar, etwa für:

38.6 ENTRYPOINT und CMD: semantische Ausführungseinheiten

ENTRYPOINT definiert die unverrückbare Startlogik des Containers. CMD definiert die Standardargumente. In der Praxis missbrauchen viele Entwickler CMD als Startkommando – was zu Konflikten mit ENTRYPOINT führt.

Ein robustes Muster:

Dadurch behalten Orchestrierungssysteme wie Kubernetes volle Kontrolle über die Ausführungsargumente, ohne das Grundverhalten zu verändern.

38.7 Multi-Stage-Dockerfiles als Architekturwerkzeug

Multi-Stage-Builds adressieren zwei fundamentale Probleme:

Podman/Buildah implementieren Multi-Stage effizient und deterministisch. Ein typisches Muster:

  1. Builder-Stage mit Compiler, Toolchain, Build-Dependencies
  2. Test-Stage (optional)
  3. Runtime-Stage mit minimalem Footprint

Der entscheidende Vorteil ist die Isolation: was im Builder passiert, bleibt im Builder.

38.8 Kontextverhalten und Dateisystemoptimierung

Der Build-Kontext ist eine eigene Welt. Podman packt den Kontext vor dem Build zusammen und übergibt ihn an Buildah. Deshalb beeinflussen unnötige Dateien die Buildzeit erheblich.

Typische Fehlkonfigurationen:

Die Kunst eines Dockerfiles beginnt damit, was nicht hineingeladen wird.

38.9 Plattformsteuerung: Linux, ARM, x86 und Build-Transparenz

Podman unterstützt --platform, um Builds für verschiedene Architekturen zu erzeugen. Dies ist essenziell für ARM-basierte Developer-Laptops oder hybride Produktionsumgebungen.

Die Plattformangabe beeinflusst:

Ein Build für arm64 ist kein Build für amd64 – und viele Entwickler bemerken das erst, wenn ihre Applikation im Cluster crasht.

38.10 Best Practices für produktionsnahe Dockerfiles

Einige Grundregeln haben sich in produktionsnahen Teams bewährt:

Dockerfiles sind Architekturbausteine, nicht bloß Buildskripts. Wer sie pflegt, pflegt die Stabilität der gesamten Deployment-Landschaft.