Wie und wann Docker-Labels / OCI-Container-Annotationen verwendet werden
3. November 2021
0 Min. LesezeitDie meisten Container-Images werden mithilfe von Dockerfiles erstellt, die eine Kombination von Anweisungen wie FROM, RUN, COPY, ENTRYPOINT usw. enthalten, um die Layer eines OCI-konformen Images zu erstellen. Eine Anweisung wird jedoch überraschend selten verwendet: LABEL. In diesem Beitrag befassen wir uns mit Labels („Annotationen“ in der OCI Image Specification), erklären, was sie sind, welche standardisierten Einsatzmöglichkeiten es gibt und wie Sie mit einigen Best Practices Ihre Container-Sicherheitslage verbessern können.
Im weiteren Verlauf dieses Artikels sprechen wir von Labels – und nicht von Annotationen –, da dies der gebräuchlichere Begriff ist. Legen wir los!
Was sind Docker-Image-Labels?
Docker-Image-Labels ermöglichen es Ihnen, Ihrem Image selbst Schlüssel-Wert-Metadaten hinzuzufügen. Diese Daten sind für einen Container, der auf dem Image basiert, nicht sichtbar. Sie sind vielmehr nützlich, um beispielsweise festzuhalten, wo sich der Quellcode für das Image befindet, wer für das Image zuständig ist oder welcher CI-Build es erstellt hat.
Docker-/OCI-Image-Metadaten erklärt
Wenn Sie schon einmal ein Softwarepaket erstellt haben, wissen Sie, dass es im Allgemeinen aus der Software, einer Konfiguration und manchmal auch aus funktionalen Daten sowie Metadaten zum Paket selbst besteht.
Java-Dateien mit der Endung .jar sind beispielsweise im Grunde .zip-Archive. Sie enthalten jedoch alle ein Verzeichnis namens META-INF auf der obersten Ebene, in dem sich mehrere Dateien und Verzeichnisse befinden. Laut der Java 2 Platform spec werden diese „… von der Java 2 Platform erkannt und interpretiert, um Anwendungen, Erweiterungen, Classloader und Services zu konfigurieren“. Öffnen wir eine .jar-Datei, die mit dem beliebten Build-Tool Maven erstellt wurde, finden wir in der Regel unter anderem ein Verzeichnis namens maven mit Inhalten wie der effektiven Maven-pom.xml und der pom.properties, die zum Erstellen der .jar-Datei verwendet wurden. (Übrigens steht „POM“ für Mavens Project Object Model.)
RPM, APT, NPM und die meisten anderen Paketverwaltungstools enthalten ähnliche Metadaten. Die Tools verwenden sie bei der Installation oder Ausführung der enthaltenen Software. Außerdem können Repositorys oder Laufzeitüberwachungssysteme sie für eigene Zwecke nutzen.

Auch Container-Images enthalten Metadaten in ihren Layern. Wenn Sie den „Verlauf“ eines Images auflisten, werden Sie oft Layer mit einer Größe von null Byte sehen. Sie enthalten keine Änderungen am Dateisystem, sondern Metadaten, die zur Laufzeit verwendet werden und häufig durch Dockerfile-Befehle hinzugefügt werden:
USER: Gibt an, unter welchem Benutzer der Prozess ausgeführt wirdENV: Gibt eine Variable (und ihren Wert) an, die in der Prozessumgebung festgelegt wirdARG: Build-Argument, das an den Container übergeben wird, in dem der Container-Build ausgeführt wird, und im Build-Kontext wie eine Umgebungsvariable verwendet wirdCMD: Befehl und/oder Parameter zum Starten des Prozesses (ENTRYPOINT funktioniert ähnlich)LABEL: Schlüssel-Wert-Paare, die von der Laufzeit-Engine nicht verwendet werden
Die meisten dieser Elemente sind allgemein bekannt und kommen in jedem Dockerfile zum Einsatz. Da Label-Metadaten jedoch nicht für die Ausführung Ihrer Container erforderlich sind, werden sie oft übersehen.
Warum Sie Container-Image-Labels verwenden sollten
Es gibt viele Gründe, Labels für Ihre Images zu verwenden – etwa, um Versionsinformationen zu dokumentieren, Kontaktangaben zu den Projektverantwortlichen hinzuzufügen oder Informationen zur Laufzeitnutzung bereitzustellen. Ein besonders häufiger Anwendungsfall ist die Dokumentation der Erstellung des Images. Diese Informationen können in der Software-Supply-Chain des Image-Artefakts verwendet werden.
Metadatentypen für Docker-Labels und OCI-Image-Annotationen
Standardisierte Labels
Metadaten zur Erstellung und Herkunft eines Images werden so häufig verwendet, dass das OCI-Team einen standardisierten Satz von Schlüsseln veröffentlicht. Sie beginnen alle mit „org.opencontainers.image.“ und umfassen unter anderem:
source: URL zum Quellcode, mit dem das Image erstellt wurderevision: Revisionskennung der Versionsverwaltung für die paketierte Softwarebase.digest: Digest (Hash) des Images, auf dem dieses Image basiertbase.name: Image-Referenz des Images, auf dem dieses Image basiertversion: Version der paketierten Software
Benutzerdefinierte Labels
Da es sich dabei lediglich um Schlüssel-Wert-Paare handelt, kann Ihr Projekt oder Ihre Organisation praktisch beliebige Werte festlegen. Einige mögliche Ideen (mit einem Präfix wie „com.mycorp.myteam.“):
ci-build: URL zum CI-Projektlauf, der das Image erstellt hatreleasenotes: Versionshinweise zur paketierten Softwarehealthz: HTTP-Endpunkt für Zustandsprüfungendocker.run: Beispiel für einen Docker-Befehl zum Ausführen eines Containers aus diesem Imagek8s.deployment: Base64-kodiertes YAML für ein Kubernetes-Deployment, das dieses Image verwendet
Der letzte Eintrag ist besonders interessant, denn Sie können praktisch alles, was sich mit Base64 kodieren lässt, als Wert eines Label-Schlüssels speichern. Das bedeutet, Sie könnten das Image abrufen und anschließend einen Befehl wie den folgenden ausführen, um eine beispielhafte YAML-Deployment-Datei zu erhalten, die Sie dann für einen Kubernetes-Cluster verwenden können:
Sie könnten die Ausgabe sogar direkt an kubectl weiterleiten und das Deployment sofort ausführen – ganz ohne Helm-Charts oder separate YAML-Dateien in Ihrem Git-Repository!
Docker-Labels und OCI-Annotationen nutzen
Wie Sie sich vorstellen können, lassen sich Labels mit beliebigen Werten befüllen, auf die Ihr CI-System Zugriff hat. Durch einfaches Auslesen der Labels können Sie Images und/oder laufende Container ihren Quellen, ihrer Dokumentation usw. zuordnen. Angenommen, Ihre Organisation veröffentlicht Images mit dem OCI-Standard-Label org.opencontainers.image.source, das die URL des SCM-Repositorys enthält, aus dem das Image stammt. Wenn Sie herausfinden möchten, welche Repositorys den Images auf einem bestimmten Docker-Host zugrunde liegen, könnten Sie einen Befehl wie diesen ausführen:
Die Ausgabe zeigt die IDs von zwei laufenden Containern. Einer davon hat das Label, daher wird sein Wert ausgegeben.
In einem Kubernetes-Cluster wird es etwas komplizierter, da Sie wahrscheinlich keinen Zugriff auf die Sockets der Container-Engine auf den Cluster-Knoten haben. Leider gibt es in kubectl keine API, über die sich diese Labels abrufen lassen. Deshalb müssen wir etwas kreativer vorgehen. Das folgende Bash-Skript ermittelt die im Namespace des aktuellen Kontexts laufenden Images und fragt dann die Image-Registry nach den Image-Metadaten ab, um die Label-Informationen zurückzugeben:
Ich verwende dafür das hervorragende Tool regctl aus dem Open-Source-Projekt regclient project. Damit kann ich Informationen zu Images direkt aus einer Registry abrufen, ohne ein Image zur Prüfung in meine lokale Umgebung herunterladen zu müssen. So kann ich das Skript außerdem überall ausführen, ohne eine Container-Laufzeit-Engine zu benötigen.
Führen wir das nun für einen Cluster aus und suchen nach den Repositorys der Images, die in meinem Cluster laufen:
Wie Sie sehen, laufen in meinem Cluster derzeit zwei Images in Pods, die das Label org.opencontainers.image.source haben.
Auch wenn diese Beispiele recht einfach sind, können Sie die Konzepte sicher erweitern und eigene Skripte oder API-Aufrufe entwickeln, die den Anforderungen Ihrer Organisation entsprechen.
Snyk-Integration
Ein besonders interessanter Aspekt aus Sicherheitssicht ist, dass Snyk beim Image-Scanning inzwischen das gescannte Image anhand von Image-Labels automatisch dem zugehörigen Dockerfile zuordnen kann.
Die Integration von Snyk mit Quellcode-Repositorys kann Dockerfiles in Ihrem Code bereits statisch erkennen und scannen. Auch Images, die aus Ihren Container-Registrys importiert wurden, lassen sich scannen. Bis vor Kurzem mussten Sie die Zuordnung jedoch selbst verwalten: Entweder mussten Sie dem Image manuell die Referenz auf das Dockerfile hinzufügen oder eine eigene Automatisierung dafür über API-Aufrufe einrichten.
Fügen Sie jetzt einfach das OCI-Standard-Label org.opencontainers.image.source mit der URL des Repositorys hinzu, in dem sich das Dockerfile befindet. Wenn Sie das Image importieren, übernimmt Snyk die Zuordnung automatisch.

Beispiel für ein automatisch verknüpftes Image-Scan-Projekt
Zusammenfassung
Zusammengefasst sind Image-Labels beziehungsweise -Annotationen ein oft übersehenes, aber leistungsstarkes Werkzeug, mit dem Sie Metadaten direkt in Ihre Images einfügen können. Mit standardisierten Schlüsseln können Sie nicht nur dokumentieren, woher ein Image stammt. Auch Deployment- und Sicherheitstools können diese Informationen nutzen, damit Sie einen besseren Überblick über Ihre bereitgestellte Umgebung erhalten.
Sie können die automatische Image-Verknüpfung von Snyk ab sofort nutzen. Fügen Sie dazu einfach das OCI-Standard-Label org.opencontainers.image.source zu den Dockerfiles hinzu, die derzeit in Ihrem Account gescannt werden. Sie haben noch keinen Snyk-Account? Registrieren Sie sich kostenlos und legen Sie gleich los!
Mich interessiert, wie Sie Labels einsetzen. Sind diese Ideen neu für Sie oder verwenden Ihre Projekte sie bereits? Auf welche anderen interessanten Arten versehen Sie Ihre Images mit Annotationen, und welche neuen Integrationen würden Sie sich für Snyk oder andere Tools wünschen? Markieren Sie mich (@ericsmalling) mit Ihren Ideen auf Twitter – ich freue mich auf Ihre Gedanken!
Container-Sicherheit mit Fokus auf Entwickler
Snyk findet und behebt automatisch Schwachstellen in Container-Images und Kubernetes-Workloads.
