Container-Images sind das Austauschformat moderner Deployment-Pipelines: Build-Systeme erzeugen Artefakte, Registries verteilen sie, Runtimes entpacken sie in Snapshotter- oder Union-Filesysteme. In der Praxis treffen dabei verschiedene Spezifikationen und Implementierungen aufeinander, vor allem das OCI-Format als Standard und Docker-kompatible Varianten, die historisch gewachsen sind und in Toolchains weiterhin sichtbar bleiben. Wer Images zwischen Registries spiegelt, Multi-Arch-Images ausliefert, Caches debuggt oder Signaturen prüft, muss die tatsächlichen Datenstrukturen verstehen: Welche Felder stehen im Manifest, wie referenzieren Digests die Konfiguration und Layer, was genau wird gehasht, und an welcher Stelle greifen Media Types und Registry-API-Versionen ein. Typische Störungen wie beschädigte Layer, inkonsistente Content-Addresses oder unerwartete Pull-Fehler lassen sich ohne dieses Modell kaum sauber eingrenzen. Aus Lesersicht steht damit eine konkrete Frage im Raum: Wie unterscheiden sich OCI und Docker-Image-Strukturen im Detail, welche Mechanismen stellen Integrität und Vertrauenswürdigkeit her, und welche technischen Ursachen führen in realen Umgebungen zu Layer-Korruption oder vermeintlich „kaputten“ Images?

Inhalt
- Image-Spezifikationen und Datenmodelle: OCI Image Spec, Docker V2 Schema 2, Manifest-Listen und Media Types
- OCI Image Spec: Kernobjekte und referentielle Integrität
- Docker V2 Schema 2: Äquivalenzen, Abweichungen und Übergangsflächen
- Manifest-Listen / Image Index: Multi-Architektur und Plattform-Selektion
- Media Types, Kompression und Layer-Repräsentationen
- Kompatibilität in Registries: Accept-Aushandlung und Fallbacks
- Layer-Mechanik im Detail: DiffIDs, ChainIDs, Content-Digests, Kompression, Whiteouts und typische Storage-Treiber (overlay2, aufs, btrfs, zfs)
- Unkomprimiert vs. komprimiert: DiffID, Blob-Digest und warum beides nötig ist
- ChainID und Layer-Ketten: Identität eines Zustands statt eines einzelnen Deltas
- Whiteouts und Opaque-Verzeichnisse: Löschoperationen in Tar-basierten Layern
- Kompression und Reproducibility: Warum derselbe Layer nicht immer denselben Digest hat
- Storage-Treiber im Kontext der Layer-Mechanik: overlay2, aufs, btrfs, zfs
- Typische Fehlerbilder bei Layer-Korruption und wie sie sich technisch einordnen
- Distribution und Sicherheit: Registry-API v2, Blob-Transfer und Garbage Collection, Signierung (Notary v1, Cosign/Sigstore), Content Trust und Fehlerbilder bei Layer-Korruption
- Registry-API v2: Referenzen, Manifeste und Negotiation
- Blob-Transfer, Chunking und Hash-Mechanik im Fehlerfall
- Garbage Collection und Retention: Wann Blobs verschwinden
- Signierung und Content Trust: Notary v1 versus Cosign/Sigstore
- Typische Fehlerbilder bei Layer-Korruption und systematische Eingrenzung
Image-Spezifikationen und Datenmodelle: OCI Image Spec, Docker V2 Schema 2, Manifest-Listen und Media Types
Container-Images werden in der Praxis über Manifest-Dokumente beschrieben, die Blobs (Layer und Konfiguration) adressieren und damit die Datenebene von Transport- und Storage-Implementierungen trennen. Der entscheidende Schritt der letzten Jahre besteht in der weitgehenden Konvergenz: Docker Registry HTTP API V2 und die OCI Distribution Spec verwenden kompatible Grundmechaniken, während OCI Image Spec das Datenmodell standardisiert. Unterschiede zeigen sich weniger in der Layer-Mechanik als in Media Types, Artefakt-Ökosystemen und in Details der Mehrarchitektur-Beschreibung.
OCI Image Spec: Kernobjekte und referentielle Integrität
Das OCI-Image-Datenmodell besteht aus drei zentralen Bausteinen: Manifest, Image Configuration und Layer. Das Manifest ist das „Inhaltsverzeichnis“: Es verweist auf genau eine Konfiguration und eine geordnete Liste von Layer-Descriptors. Die Konfiguration beschreibt Metadaten wie os, architecture, Prozessparameter (config.Env, config.Cmd, config.Entrypoint) sowie rootfs.diff_ids. Layer sind Tar-Archive (meist gzip-komprimiert), die Dateisystemänderungen als „Diff“ transportieren.
Integrität entsteht durch Content Addressing: Jeder referenzierte Blob wird im Descriptor über digest und size eindeutig identifiziert. Der Digest ist typischerweise sha256:<hex> über den exakten Blob-Bytestrom, wie er in der Registry liegt (bei komprimierten Layern also über das komprimierte Archiv). Die Konfiguration enthält zusätzlich diff_ids, die sich auf den unkomprimierten Layer-Stream beziehen. Damit lassen sich Kompression, Transport und lokale Storage-Layouts variieren, ohne die semantische Layer-Kette zu verlieren.
Docker V2 Schema 2: Äquivalenzen, Abweichungen und Übergangsflächen
Docker V2 Schema 2 definiert ein Manifest-Format, das dem OCI-Manifest strukturell sehr nahe ist (Descriptor für Config, Liste von Layer-Descriptors). Historisch sind die Unterschiede vor allem in den Media Types und in einigen Feldbezeichnungen der Konfiguration sichtbar. In modernen Toolchains wird häufig zwischen OCI und Docker Media Types umgeschaltet, ohne dass sich der zugrunde liegende Blob-Inhalt ändert. Kritisch wird das dort, wo Validierer strikt auf Media Types prüfen oder Signatur- und Policy-Systeme bestimmte Typen zulassen bzw. verbieten.
Für Interoperabilität gilt: Registries und Clients sollten sowohl OCI- als auch Docker-Media-Types akzeptieren. Wenn ein Client nur OCI akzeptiert, können Docker-spezifische Manifeste trotz identischer Layer-Digests abgelehnt werden. Umgekehrt können ältere Docker-Stacks OCI-Manifesttypen nicht verstehen, obwohl die Registry die Blobs korrekt vorhält. In heterogenen Umgebungen entscheidet daher die Fähigkeit zur Aushandlung über Accept-Header und die korrekte Wahl der Referenz (Tag oder Digest), ob Pull-Vorgänge deterministisch bleiben.
| Aspekt | OCI Image Spec (Manifest) | Docker V2 Schema 2 (Manifest) |
|---|---|---|
| Manifest Media Type | application/vnd.oci.image.manifest.v1+json |
application/vnd.docker.distribution.manifest.v2+json |
| Config Descriptor | config.mediaType meist application/vnd.oci.image.config.v1+json |
config.mediaType meist application/vnd.docker.container.image.v1+json |
| Layer Media Type | application/vnd.oci.image.layer.v1.tar+gzip (oder Varianten) |
application/vnd.docker.image.rootfs.diff.tar.gzip |
| Digest/Size | Descriptor mit digest, size, optional urls, annotations |
Descriptor mit digest, size, optional urls |
| Semantik der Layer-Reihenfolge | Geordnet, Basis zuerst; Merge durch Snapshotter/Graphdriver | Geordnet, Basis zuerst; identische Mechanik |
Manifest-Listen / Image Index: Multi-Architektur und Plattform-Selektion
Mehrarchitektur-Images werden nicht als „ein Manifest mit vielen Layer-Sätzen“ modelliert, sondern als Index, der auf mehrere Manifeste verweist. OCI nennt dieses Objekt Image Index, Docker spricht von Manifest List. Jeder Eintrag enthält einen Descriptor auf ein konkretes Manifest sowie eine Plattformbeschreibung. Clients wählen anhand von os, architecture und optional variant (z. B. für ARM) den passenden Eintrag aus. Die Auflösung erfolgt typischerweise beim Pull anhand von Accept und lokaler Plattformdaten, kann aber auch durch explizite Auswahl (Digest eines Ziel-Manifests) erzwungen werden.
In der Praxis entstehen Fehlerbilder, wenn Plattform-Metadaten unvollständig sind oder wenn eine Manifest-Liste Einträge referenziert, deren Blobs nicht vollständig in der Registry vorhanden sind. Da Tags auf Index-Objekte zeigen können, wird ein einzelner Tag dann zum Multiplexer. Für reproduzierbare Deployments gilt deshalb: Referenzen auf Digests (@sha256:...) stabilisieren die Auswahl und vermeiden spätere Tag-Mutationen.
- OCI Index Media Type:
application/vnd.oci.image.index.v1+json - Docker Manifest List Media Type:
application/vnd.docker.distribution.manifest.list.v2+json - Plattform-Felder:
platform.os,platform.architecture, optionalplatform.variant, optionalplatform.os.versionundplatform.os.features - Deterministische Referenz: Pull über Digest statt Tag, z. B.
example.org/repo/image@sha256:...
Media Types, Kompression und Layer-Repräsentationen
Media Types sind mehr als kosmetische Kennzeichnungen. Sie steuern Validierung, Policy-Entscheidungen und teils die Auswahl von Dekompressions- und Unpacking-Pfaden. OCI spezifiziert Layer als tar-basierte Changesets und unterscheidet zwischen „Distribution-Digest“ (komprimiert) und „DiffID“ (unkomprimiert). Zusätzlich existieren Media Types für alternative Kompressionen; die Akzeptanz hängt jedoch von Client, Runtime und Snapshotter ab. In containerd-Umgebungen wird die Unterstützung häufig über Plugins und Snapshotter-Backends bestimmt; bei CRI-O und Docker Engine spielen integrierte Entpacker und Kernel-Features eine Rolle.
Für Layer gelten zwei Prüfpunkte: Erstens muss der Blob-Digest zum tatsächlichen Transfer passen, sonst schlägt das Pull in der Regel mit einem Digest-Fehler fehl. Zweitens muss nach dem Entpacken der unkomprimierte Stream den erwarteten diff_id ergeben, sonst wird die Rootfs-Kette als inkonsistent betrachtet. Diese Trennung erklärt, warum ein Blob in der Registry „korrekt“ wirken kann, obwohl lokale Stores (Cache, Proxy, Mirror) beim Repack oder bei fehlerhaften Partial Downloads beschädigte Inhalte erzeugen.
| Objekt / Feld | Bedeutung | Typische Prüfstelle |
|---|---|---|
descriptor.digest |
Hash über den exakten Blob, wie gespeichert/übertragen | Registry-Client beim Download; Proxy/Mirror bei Weitergabe |
descriptor.size |
Blob-Größe in Bytes | Transfer-Validierung, Caching, Range-Requests |
rootfs.diff_ids |
Hashes über unkomprimierte Layer-Streams (Reihenfolge relevant) | Unpacker/Snapshotter beim Apply der Layer |
config.digest |
Hash über JSON-Konfiguration | Client beim Pull; Policy-Engines für Metadatenregeln |
Kompatibilität in Registries: Accept-Aushandlung und Fallbacks
Beim Abruf eines Manifests entscheidet der Accept-Header, welches Format die Registry zurückliefert, sofern mehrere Repräsentationen verfügbar sind. Clients, die sowohl application/vnd.oci.image.manifest.v1+json als auch Docker-Typen angeben, erhalten in der Regel eines der Formate, die die Registry bevorzugt. Probleme treten auf, wenn zwischengeschaltete Komponenten (Reverse Proxies, Content Caches, Air-Gap-Mirrors) Antworten nach Media Type cachen, aber den Vary-Kontext oder die Accept-Varianten nicht korrekt berücksichtigen. Dann kann ein Client ein Manifest erhalten, dessen Media Type nicht zur eigenen Parser-Logik passt.
In strikten OCI-Umgebungen wird zudem auf Konsistenz der Descriptor-Media-Types geachtet: Ein OCI-Manifest sollte OCI-Config- und OCI-Layer-Typen referenzieren; ein Docker-Manifest entsprechend Docker-Typen. Viele Tools tolerieren Mischformen, aber Policy-Prüfungen (z. B. in Admission Controllern) bewerten dies häufig als Abweichung vom erwarteten Format. Bei Debugging ist daher die Kombination aus Content-Type des Manifests, den mediaType-Feldern im JSON und den Digests der referenzierten Blobs gemeinsam zu prüfen.
Layer-Mechanik im Detail: DiffIDs, ChainIDs, Content-Digests, Kompression, Whiteouts und typische Storage-Treiber (overlay2, aufs, btrfs, zfs)
Unkomprimiert vs. komprimiert: DiffID, Blob-Digest und warum beides nötig ist
Container-Images bestehen logisch aus einer geordneten Liste von Layern. Jeder Layer beschreibt eine Dateisystemänderung (Add/Modify/Delete) relativ zum vorherigen Zustand. Technisch werden diese Änderungen als Tar-Stream transportiert, in Registries typischerweise komprimiert (häufig gzip, teils auch zstd abhängig von Registry/Client-Stack). Daraus ergeben sich zwei unterschiedliche, bewusst getrennte Hash-Begriffe: der Digest des übertragenen Blobs und der Hash der entpackten Nutzdaten.
Der Content-Digest (in OCI- und Docker-Manifests als digest geführt) ist ein kryptografischer Hash über den exakt gespeicherten Blob, also inklusive Kompression und exakter Bytestrom-Struktur. Er dient dem Transport und der Referenzierung: Pull/Push, Deduplication in der Registry und Integritätsprüfung beim Download. Die DiffID
- Blob-Digest (komprimiert): Referenz im Manifest, z. B.
sha256:<hex>; Hash über den gespeicherten Layer-Blob (inklusive Kompression), genutzt für Download-Integrität und Registry-Deduplizierung. - DiffID (unkomprimiert): Hash über den entpackten Layer-Tar-Stream; typischerweise in der lokalen Image-Metadatenstruktur (z. B. im Docker-
rootfs.diff_idsinnerhalb der Image-Konfiguration) und Grundlage für die Ableitung stabiler Ketten-IDs. - Kompressionseffekt: Derselbe Layer-Inhalt kann mehrere Blob-Digests besitzen (anders komprimiert, anderer Bytestrom), aber genau eine DiffID (identischer entpackter Inhalt).
ChainID und Layer-Ketten: Identität eines Zustands statt eines einzelnen Deltas
Ein einzelner Layer ist nur ein Delta; für Laufzeitsicht und Snapshotting zählt der zusammengesetzte Zustand aus Basis plus allen Vorgängern. Dafür verwenden verbreitete Implementierungen eine Kettenidentität (oft als ChainID bezeichnet). Sie entsteht deterministisch aus der Reihenfolge der DiffIDs und ändert sich sofort, wenn ein Layer in der Kette ausgetauscht, neu sortiert oder inhaltlich verändert wird. Dieses Konzept verhindert Kollisionen zwischen “gleichen” Einzellayern, die auf unterschiedlichen Basen zu unterschiedlichen Gesamtergebnissen führen.
In der Praxis nutzen Storage-Treiber oder darüberliegende Graphdriver-Schichten die ChainID, um Snapshot-Verzeichnisse, Mounts und Cache-Objekte eindeutig zu adressieren. Damit lassen sich gemeinsame Präfixe (identische Basis- und Zwischenlayer) zwischen mehreren Images speichern, ohne dass das obere Dateisystemlayout verwechselt wird.
| Begriff | Wofür er steht | Worauf der Hash gebildet wird | Typische Verwendung |
|---|---|---|---|
| Content-Digest | Adressierung eines Registry-Blobs | Bytestrom des gespeicherten Objekts, z. B. komprimierter Layer-Tar | Manifest-Referenzen, Pull/Push, Transport-Integrität |
| DiffID | Identität des Layer-Deltas | Entpackter Layer-Tar-Stream (uncompressed) | Lokale Rootfs-Metadaten, Validierung/Cache über Inhalt statt Kompression |
| ChainID | Identität einer Layer-Kette bis zu einem Punkt | Deterministische Ableitung aus der geordneten DiffID-Liste | Snapshot-/Mount-Identität, Shared Layers, eindeutige Zuordnung im Storage |
Whiteouts und Opaque-Verzeichnisse: Löschoperationen in Tar-basierten Layern
Layer-Tars können keine “echten” Löschoperationen ausdrücken, weil ein Tar-Archiv nur Einträge hinzufügt. Deshalb wird das Löschen in unionfähigen Dateisystemen über Whiteouts modelliert. Ein Whiteout ist eine spezielle Markierung im oberen Layer, die dem Merge-Algorithmus signalisiert, dass eine Datei oder ein Verzeichnis aus tieferen Layern im zusammengesetzten View nicht sichtbar sein soll. Zusätzlich existiert das Konzept “opaque directory”, das bewirkt, dass ein Verzeichnis nicht mit darunterliegenden Verzeichniseinträgen zusammengeführt wird.
- Datei-Whiteout: Ein Eintrag wie
.wh.<name>im betroffenen Verzeichnis blendet<name>aus unteren Layern aus; der Whiteout-Eintrag selbst ist nur Metadaten für den Merge. - Opaque-Verzeichnis: Eine Markierung wie
.wh..wh..opqbedeutet, dass das Verzeichnis als “undurchsichtig” gilt und Inhalte aus unteren Layern nicht “durchscheinen”. - Relevanz für Korrektheit: Fehlerhafte Whiteout-Interpretation führt zu scheinbar “wieder auftauchenden” Dateien, unerwarteten Duplikaten oder inkonsistenten Verzeichnislisten zwischen Build- und Run-Phase.
Kompression und Reproducibility: Warum derselbe Layer nicht immer denselben Digest hat
Da der Blob-Digest den komprimierten Bytestrom abdeckt, schlagen sich Kompressorparameter und Metadaten unmittelbar im Hash nieder. Bei gzip können beispielsweise Zeitstempel im Header oder unterschiedliche Kompressionslevel zu abweichenden Digests führen, obwohl der entpackte Inhalt identisch bleibt. Dieses Verhalten ist kein Fehler, sondern eine Konsequenz des “Content-Addressing” auf Byteebene. Für Build-Pipelines mit strengen Reproduzierbarkeitsanforderungen spielt daher nicht nur die Dateisystemänderung, sondern auch die deterministische Erzeugung des Layer-Blobs eine Rolle.
DiffIDs bleiben in solchen Fällen stabil, sofern der entpackte Tar-Stream identisch ist. Allerdings kann auch die Tar-Erzeugung selbst variieren, etwa durch abweichende Dateireihenfolgen, unterschiedliche UID/GID-Mappings oder nicht normalisierte Zeitstempel. Ein reproduzierbarer Layer setzt deshalb konsistente Tar-Erstellung und konsistente Metadaten voraus; andernfalls ändern sich DiffID und ChainID und damit Cache-Treffer und Sharing-Effekte.
Storage-Treiber im Kontext der Layer-Mechanik: overlay2, aufs, btrfs, zfs
Die Layer-Mechanik endet nicht beim Manifest; sie materialisiert sich lokal im Snapshot-/Graphdriver. Treiber unterscheiden sich vor allem darin, ob sie ein Overlay-/Union-Dateisystem auf Verzeichnisbäumen nutzen oder ob sie echte Copy-on-Write-Subvolumes/Datasets bereitstellen. Daraus folgen Unterschiede bei Performance-Eigenschaften, Fehlermodi und der Art, wie Whiteouts und Metadaten umgesetzt werden.
- overlay2: Nutzt das Linux-OverlayFS mit
lowerdir/upperdir/workdir; Whiteouts und Opaque-Dirs werden nach OverlayFS-Regeln abgebildet. Typische Ablage unter/var/lib/docker/overlay2/(Docker) bzw. bei containerd je nach Snapshotter-Konfiguration. - aufs: UnionFS-Ansatz mit eigener Semantik; historisch verbreitet, heute in vielen Distributionen nicht mehr standardmäßig verfügbar und in modernen Setups selten. Migrationsszenarien können dennoch auf AUFS-Artefakte treffen, etwa bei älteren Hosts oder Alt-Images.
- btrfs: Verwendet Subvolumes und Snapshots als CoW-Grundlage; Layer entsprechen häufig Snapshots, Deltas entstehen blockbasiert. Vorteilhaft bei vielen Snapshots, aber empfindlich gegenüber Dateisystemzustand (z. B. ENOSPC trotz freiem Platz durch Metadaten-Reservierung).
- zfs: Nutzt Datasets und Snapshots; Layer werden oft als Klone/Snapshots realisiert. Eigenschaften hängen stark von
recordsize, Kompression und Speicherpool-Gesundheit ab; Konsistenzprobleme manifestieren sich eher als Pool-/Dataset-Fehler als als einzelne “defekte Tar-Layer”.
Typische Fehlerbilder bei Layer-Korruption und wie sie sich technisch einordnen
Layer-Korruption zeigt sich meist als Diskrepanz zwischen erwarteten Hashes und dem lokal oder remote vorliegenden Content. Das kann ein beschädigter Blob in der Registry sein, ein fehlerhafter Download im lokalen Content-Store oder ein beschädigter Snapshot im Storage-Treiber. Weil Manifest-Digests den komprimierten Bytestrom adressieren, treten Abweichungen oft bereits beim Pull als Digest-Mismatch zutage. DiffID-Fehler erscheinen eher später, etwa bei der Entpack- oder Apply-Phase, wenn der entpackte Inhalt nicht zur erwarteten DiffID passt.
- Digest-Mismatch beim Pull: Clients brechen mit einer Meldung wie
failed to verify digestoderunexpected digestab; Ursache ist häufig ein falscher Blob unter korrekt referenziertemsha256:...in der Registry oder ein beschädigter lokaler Content-Cache. - Entpackfehler/Stream-Fehler: Meldungen wie
unexpected EOFoderinvalid tar headerdeuten auf truncierte oder beschädigte Layer-Blobs hin; besonders relevant bei instabilen Proxies, fehlerhaften Mirror-Caches oder defekten Speichermedien. - Apply-/Snapshot-Fehler: Fehler wie
failed to apply layer,no such file or directorywährend des Apply oder inkonsistente Dateibäume nach dem Start können auf Probleme in der Whiteout-Verarbeitung oder auf inkonsistente Snapshot-Verzeichnisse im Treiber hindeuten. - Overlay-spezifische Symptome: Bei
overlay2fallen inkonsistentelowerdir-Ketten, fehlende Verzeichnisse unter/var/lib/docker/overlay2/oder defektelink-Indizes auf; Ursache sind oft unvollständige Bereinigungen nach Crash oder Dateisystemfehler im Host.
Für die Einordnung hilft eine klare Trennung: Manifest- und Blob-Digests prüfen Transport und Ablage des komprimierten Contents, DiffIDs und ChainIDs binden die unkomprimierte Semantik und die Reihenfolge. Whiteouts bestimmen, ob “Löschen” korrekt wirkt. Storage-Treiber setzen die abstrakte Layer-Kette als konkrete Snapshot- und Merge-Strukturen um und prägen damit sowohl Performance als auch Fehlermuster.
Distribution und Sicherheit: Registry-API v2, Blob-Transfer und Garbage Collection, Signierung (Notary v1, Cosign/Sigstore), Content Trust und Fehlerbilder bei Layer-Korruption
Registry-API v2: Referenzen, Manifeste und Negotiation
Die OCI- und Docker-Distribution stützen sich in der Praxis auf die Docker Registry HTTP API v2. Zentrale Objekte sind Manifeste (Image-Index bzw. Image-Manifest) und Blobs (Layer-Tar, Konfigurations-JSON), die über Content-Addressing via Digest referenziert werden. Entscheidend für Interoperabilität ist die konsequente Trennung zwischen Referenzen (<name>:<tag>, <name>@sha256:...) und der tatsächlichen Nutzlast (Blobs), die unabhängig vom Tag stabil bleibt.
Content Negotiation erfolgt über Accept-Header und steuert, ob ein Registry-Endpunkt ein Docker- oder OCI-Media-Type-Dokument liefert. Bei Multi-Architektur-Images wird typischerweise zunächst ein Index (Manifest List) übertragen, der per Plattformselektor auf ein konkretes Image-Manifest verweist. Clients müssen mit Redirects, Proxys und Auth-Challenges umgehen; üblich sind 401 mit WWW-Authenticate: Bearer ... sowie anschließend tokenbasierte Zugriffe mit scopes (z. B. Pull/Push) pro Repository.
| Operation (API v2) | Typische Request/Response-Details | Relevanz für Integrität |
|---|---|---|
| Manifest lesen | GET /v2/<name>/manifests/<reference>Accept: application/vnd.oci.image.manifest.v1+json oder Docker-Äquivalent |
Manifest enthält Blobs per Digest; falscher Media Type oder alter Cache führt zu „manifest unknown“ oder falscher Auflösung bei Multi-Arch. |
| Digest des Manifests ermitteln | Response-Header Docker-Content-Digest: sha256:... |
Erlaubt Pinning von @sha256:...; schützt vor Tag-Mutation. |
| Blob herunterladen | GET /v2/<name>/blobs/sha256:...häufig mit 307/302 auf Storage-Backend |
Digest-Check des Clients deckt stille Korruption/Proxy-Manipulation auf. |
| Blob hochladen | POST /v2/<name>/blobs/uploads/ → LocationPATCH (Chunk) → FortschrittPUT ...?digest=sha256:... (Commit) |
Commit bindet Upload an Digest; „wrong digest“ signalisiert fehlerhafte Kompression, Chunk-Reihenfolge oder Proxy-Fehler. |
Blob-Transfer, Chunking und Hash-Mechanik im Fehlerfall
Beim Pull wird ein Layer typischerweise komprimiert (meist gzip) übertragen. Der Digest bezieht sich auf den gespeicherten Blob in der Registry, also auf die exakte Bytefolge des komprimierten Streams. Lokale Snapshotter/Storage-Treiber verarbeiten anschließend die dekomprimierten Inhalte und bauen daraus ein Rootfs; deren Integritätsprobleme zeigen sich oft erst beim Entpacken oder beim Mounten eines Snapshots. Beim Push entsteht eine zweite Fehlerklasse: der Client muss exakt den Digest committen, der dem hochgeladenen Byte-Stream entspricht; schon minimale Abweichungen (Proxy-Transformation, fehlerhafte Chunk-Resume-Implementierung) brechen den Commit.
- Chunk-Upload-Flow:
POST /v2/<name>/blobs/uploads/PATCH <upload-location>PUT <upload-location>?digest=sha256:<hex> - Content-Addressing:
sha256:<hex>bezeichnet den Hash über den gespeicherten Blob-Stream; die Registry verweigert einen Commit, wenndigestnicht exakt zum Upload passt. - Manifest-Pinning:
image@sha256:<manifest-digest>umgeht Tag-Races; der HeaderDocker-Content-Digestliefert den kanonischen Digest des ausgelieferten Manifests. - Erwartbare Fehlermeldungen: bei Digest-Mismatch erscheinen je nach Client/Registry Varianten wie
BLOB_UPLOAD_INVALID,blob unknownodermanifest blob unknown; technisch steckt meist eine fehlende Blob-Referenz oder ein nicht reproduzierbarer Upload dahinter.
Garbage Collection und Retention: Wann Blobs verschwinden
Registries speichern Blobs üblicherweise dedupliziert: mehrere Manifeste können auf denselben Layer zeigen. Garbage Collection (GC) entfernt Blobs, die von keinen „live“ markierten Manifesten mehr referenziert werden. Das ist sicherheits- und betriebsrelevant, weil Tag-Deletion, Retention-Policies oder aggressive Cleanup-Jobs indirekt Abhängigkeiten brechen können. Besonders riskant sind Rennen zwischen Push (Manifest wird spät geschrieben) und paralleler GC oder „unreferenced blob“-Bereinigungen.
Verlässliche Retention erfordert ein konsistentes Mark-and-Sweep-Modell: erst Manifeste und Indizes als Wurzeln markieren, dann referenzierte Blobs transitiv halten. Systeme, die Soft-Deletes oder eine Quarantänephase implementieren, reduzieren das Risiko. Bei externen Object-Stores (S3/GCS/Azure) kommen zusätzliche Konsistenz- und Lifecycle-Policies hinzu; ein versehentlich aktivierter Bucket-Lifecycle kann Blobs entfernen, ohne dass die Registry dies sofort bemerkt.
| Fehlerbild | Typische Ursache in Distribution/GC | Beobachtbares Symptom |
|---|---|---|
| „manifest blob unknown“ beim Pull | Blob wurde durch GC/Object-Store-Lifecycle gelöscht, Manifest existiert noch | Manifest lädt, einzelne Layer-Downloads scheitern mit 404 auf /blobs/sha256:... |
| „blob unknown“ bei Multi-Arch | Index zeigt auf Manifest, aber ein platform-spezifisches Manifest wurde entfernt | Pull funktioniert für eine Architektur, bricht für andere Plattformen ab |
| Intermittierende Digest-Mismatches | Proxy/Cache liefert falschen Blob zu Digest oder mischt Byte-Ranges | Download startet, Prüfsumme scheitert nach vollständigem Transfer |
| Layer-Extraktion bricht ab | Korruption im Blob oder im lokalen Content-Store/Snapshotter | Fehler beim Unpack, z. B. „unexpected EOF“ oder „invalid tar header“ in Client-Logs |
Signierung und Content Trust: Notary v1 versus Cosign/Sigstore
Integrität durch Digests schützt vor Übertragungsfehlern, nicht vor böswilligem Austausch eines getaggten Images. Signierung bindet eine Identität an einen konkreten Manifest-Digest und erlaubt Policies („nur signierte Artefakte deployen“). Historisch deckt Docker Content Trust (DCT) die Signierung über Notary v1 ab (TUF-basierte Metadaten). In der Praxis ist Notary v1 an Tag-Signierung gekoppelt und erzeugt ein separates Metadaten-Repository; das erleichtert Rollback- und Key-Rotation-Konzepte, erhöht aber die betriebliche Komplexität und ist nicht OCI-artefaktzentriert.
Cosign (Sigstore) signiert dagegen typischerweise den Manifest-Digest und veröffentlicht Signaturen als OCI-Artefakte neben dem Image (z. B. im gleichen Registry-Namespace). Moderne Flows nutzen „keyless“ Signaturen mit OIDC-Identität und Transparenzlog (Rekor) oder klassische Schlüsselpaare. Dadurch lassen sich Signaturen, Attestations (SLSA/Provenance) und SBOMs als erstklassige Artefakte behandeln; Policies greifen auf Digest-Pinning, Signaturverifikation und optional auf die Transparenzlog-Prüfung zurück. Welche Beweiskette als ausreichend gilt, bleibt eine Policy-Entscheidung (z. B. Offline-Verifikation nur gegen Public Key versus Online-Verifikation inkl. Rekor-Inclusion-Proof).
- Notary v1 / DCT: bindet Vertrauen an Tags; typische Aktivierung erfolgt über
DOCKER_CONTENT_TRUST=1, Schlüsselmaterial wird clientseitig verwaltet, Metadaten liegen getrennt vom Image-Manifest. - Cosign (Sigstore): Signatur bezieht sich auf
sha256:<manifest-digest>; Publikation als OCI-Artefakt ermöglicht ko-lokalisierte Verteilung in der gleichen Registry, inkl. Attestations und SBOM-Artefakten. - Policy-Anker: robuste Richtlinien kombinieren
image@sha256:...mit Verifikation gegen definierte Identitäten (z. B. OIDC-Issuer/Subject) oder feste Public Keys; reine Tag-Vertrauensmodelle bleiben anfällig für Re-Tags. - Transport-Sicherheit: Signierung ersetzt kein TLS; Pull/Push erfolgt über
https://, und Token-Scopes begrenzen Zugriffe aufrepository:<name>:pullbzw....:push.
Typische Fehlerbilder bei Layer-Korruption und systematische Eingrenzung
Layer-Korruption tritt entlang der Pipeline an mehreren Stellen auf: im Object-Store (Bitrot, falsche Lifecycle-Regeln), in CDN/Proxy-Caches (Range-Requests, Content-Encoding-Manipulation), während Chunk-Uploads (Resume-Bugs) oder lokal im Content-Store/Snapshotter (Plattenfehler, inkonsistente Metadaten). Die Symptome unterscheiden sich je nach Zeitpunkt: Digest-Fehler erscheinen beim Verifizieren des heruntergeladenen Blobs; Entpackfehler erst beim Apply des Layers; Mount-Probleme beim Start des Containers, wenn ein Snapshot inkonsistent ist.
Die Eingrenzung beginnt mit der Frage, ob ein Digest stabil reproduzierbar ist. Schlägt der Pull desselben Digests auf unterschiedlichen Hosts identisch fehl, liegt die Ursache häufig serverseitig (Registry/Object-Store/CDN). Tritt der Fehler nur auf einem Host auf, sprechen Indikatoren eher für lokales Storage. Hilfreich ist außerdem die Trennung zwischen Manifest- und Blob-Ebene: Ein gültiges Manifest mit fehlenden Blobs deutet auf GC/Retention oder partiellen Push hin; ein vorhandener Blob mit falschem Inhalt deutet eher auf Cache-/Proxy-Fehlverhalten oder Storage-Korruption.
Meroth IT-Service ist Ihr lokaler IT-Dienstleister in Frankfurt am Main für kleine Unternehmen, Selbstständige und Privatkunden
Kostenfreie Ersteinschätzung Ihres Anliegens?
Werbung
(**) UVP: Unverbindliche Preisempfehlung
Preise inkl. MwSt., zzgl. Versandkosten
