From 613f05dfdea0148484c3b72431544f5967defd29 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Wed, 18 Mar 2026 20:42:00 -0700 Subject: [PATCH] Add consistent OCI labels to all container Dockerfiles Every container now carries title, description, version, source, and vendor labels per the OCI image spec. Version is derived from the existing CONTAINER_APP_VERSION ARG at build time. Co-Authored-By: Claude Opus 4.6 (1M context) --- containers/alloy/Dockerfile | 7 +++++-- containers/cv/Dockerfile | 7 +++++++ containers/devpi/Dockerfile | 6 ++++++ containers/grafana-sidecar/Dockerfile | 5 ++++- containers/grafana/Dockerfile | 5 ++++- containers/homepage/Dockerfile | 7 +++++-- containers/kiwix-serve/Dockerfile | 7 +++++++ containers/kubectl/Dockerfile | 7 +++++++ containers/loki/Dockerfile | 7 +++++-- containers/mealie/Dockerfile | 5 ++++- containers/miniflux/Dockerfile | 7 +++++-- containers/navidrome/Dockerfile | 8 +++++--- containers/nettest/Dockerfile | 7 +++++++ containers/ntfy/Dockerfile | 7 +++++-- containers/prometheus/Dockerfile | 7 +++++-- containers/quartz/Dockerfile | 7 +++++++ containers/runner-job-image/Dockerfile | 6 ++++++ containers/teslamate/Dockerfile | 7 +++++++ containers/transmission-exporter/Dockerfile | 4 ++++ containers/transmission/Dockerfile | 6 ++++++ containers/unpoller/Dockerfile | 5 ++++- docs/changelog.d/+oci-labels.infra.md | 1 + 22 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 docs/changelog.d/+oci-labels.infra.md diff --git a/containers/alloy/Dockerfile b/containers/alloy/Dockerfile index e9bae40..f2f30f6 100644 --- a/containers/alloy/Dockerfile +++ b/containers/alloy/Dockerfile @@ -48,9 +48,12 @@ RUN RELEASE_BUILD=1 VERSION=${ALLOY_VERSION} \ FROM alpine:3.22 -LABEL org.opencontainers.image.title=alloy +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="Alloy" LABEL org.opencontainers.image.description="Grafana Alloy is an OpenTelemetry Collector distribution" -LABEL org.opencontainers.image.source=https://github.com/grafana/alloy +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" RUN apk --no-cache add ca-certificates tzdata \ && addgroup -g 473 alloy \ diff --git a/containers/cv/Dockerfile b/containers/cv/Dockerfile index 517e387..9bfebe0 100644 --- a/containers/cv/Dockerfile +++ b/containers/cv/Dockerfile @@ -10,6 +10,13 @@ ARG CONTAINER_APP_VERSION=1.0.3 FROM nginx:alpine +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="CV" +LABEL org.opencontainers.image.description="Static site server for CV/resume" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" + # Install curl for downloading release assets RUN apk add --no-cache curl diff --git a/containers/devpi/Dockerfile b/containers/devpi/Dockerfile index 6a881e7..69e14c3 100644 --- a/containers/devpi/Dockerfile +++ b/containers/devpi/Dockerfile @@ -4,6 +4,12 @@ FROM python:3.12-slim ARG CONTAINER_APP_VERSION ARG DEVPI_SERVER_VERSION=${CONTAINER_APP_VERSION} + +LABEL org.opencontainers.image.title="devpi" +LABEL org.opencontainers.image.description="devpi PyPI server and caching proxy" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" ARG DEVPI_WEB_VERSION=5.0.1 # Install devpi-server and devpi-web diff --git a/containers/grafana-sidecar/Dockerfile b/containers/grafana-sidecar/Dockerfile index e3f83c8..28dd983 100644 --- a/containers/grafana-sidecar/Dockerfile +++ b/containers/grafana-sidecar/Dockerfile @@ -20,9 +20,12 @@ RUN python -m venv .venv && \ FROM base +ARG CONTAINER_APP_VERSION LABEL org.opencontainers.image.title="Grafana Sidecar" LABEL org.opencontainers.image.description="K8s sidecar to sync ConfigMap dashboards into Grafana" -LABEL org.opencontainers.image.source="https://github.com/kiwigrid/k8s-sidecar" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" ENV PYTHONUNBUFFERED=1 WORKDIR /app diff --git a/containers/grafana/Dockerfile b/containers/grafana/Dockerfile index f89adda..3d5b12b 100644 --- a/containers/grafana/Dockerfile +++ b/containers/grafana/Dockerfile @@ -51,9 +51,12 @@ USER grafana WORKDIR /usr/share/grafana EXPOSE 3000 +ARG CONTAINER_APP_VERSION LABEL org.opencontainers.image.title="Grafana" LABEL org.opencontainers.image.description="Grafana OSS observability platform" -LABEL org.opencontainers.image.source="https://github.com/grafana/grafana" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" ENTRYPOINT ["/usr/bin/dumb-init", "--"] CMD ["grafana", "server", \ diff --git a/containers/homepage/Dockerfile b/containers/homepage/Dockerfile index a3133ad..31b72f9 100644 --- a/containers/homepage/Dockerfile +++ b/containers/homepage/Dockerfile @@ -21,9 +21,12 @@ RUN mkdir -p config \ FROM node:24-alpine -LABEL org.opencontainers.image.title=Homepage +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="Homepage" LABEL org.opencontainers.image.description="A self-hosted services landing page" -LABEL org.opencontainers.image.source=https://github.com/gethomepage/homepage +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" WORKDIR /app diff --git a/containers/kiwix-serve/Dockerfile b/containers/kiwix-serve/Dockerfile index 5fe6df7..17167e5 100644 --- a/containers/kiwix-serve/Dockerfile +++ b/containers/kiwix-serve/Dockerfile @@ -38,6 +38,13 @@ RUN set -e && \ curl -k -L $url | tar -xz -C /usr/local/bin/ --strip-components 1 && \ apk del curl +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="kiwix-serve" +LABEL org.opencontainers.image.description="Kiwix content server for offline ZIM files" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" + EXPOSE 80 # Run as non-root diff --git a/containers/kubectl/Dockerfile b/containers/kubectl/Dockerfile index ef37e20..bcec94a 100644 --- a/containers/kubectl/Dockerfile +++ b/containers/kubectl/Dockerfile @@ -27,6 +27,13 @@ RUN apk add --no-cache curl && \ FROM alpine:3.22 +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="kubectl" +LABEL org.opencontainers.image.description="Minimal kubectl container" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" + COPY --from=downloader /kubectl /usr/local/bin/kubectl # Add ca-certificates for HTTPS connections and bash for scripts diff --git a/containers/loki/Dockerfile b/containers/loki/Dockerfile index 5edb71b..518c493 100644 --- a/containers/loki/Dockerfile +++ b/containers/loki/Dockerfile @@ -25,9 +25,12 @@ RUN go build -tags netgo \ FROM alpine:3.22 -LABEL org.opencontainers.image.title=Loki +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="Loki" LABEL org.opencontainers.image.description="Grafana Loki log aggregation system" -LABEL org.opencontainers.image.source=https://github.com/grafana/loki +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" RUN apk add --no-cache ca-certificates tzdata RUN mkdir -p /loki && chown 10001:10001 /loki diff --git a/containers/mealie/Dockerfile b/containers/mealie/Dockerfile index fe1bf02..8df38bf 100644 --- a/containers/mealie/Dockerfile +++ b/containers/mealie/Dockerfile @@ -135,8 +135,11 @@ ENV HOST=0.0.0.0 COPY --from=backend-builder /src/docker/entry.sh $MEALIE_HOME/run.sh RUN chmod +x $MEALIE_HOME/run.sh +ARG CONTAINER_APP_VERSION LABEL org.opencontainers.image.title="Mealie" LABEL org.opencontainers.image.description="Self-hosted recipe manager" -LABEL org.opencontainers.image.source="https://github.com/mealie-recipes/mealie" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" ENTRYPOINT ["/app/run.sh"] diff --git a/containers/miniflux/Dockerfile b/containers/miniflux/Dockerfile index 83a1034..4e987cc 100644 --- a/containers/miniflux/Dockerfile +++ b/containers/miniflux/Dockerfile @@ -18,9 +18,12 @@ RUN make miniflux FROM alpine:3.22 -LABEL org.opencontainers.image.title=Miniflux +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="Miniflux" LABEL org.opencontainers.image.description="Miniflux is a minimalist and opinionated feed reader" -LABEL org.opencontainers.image.source=https://github.com/miniflux/v2 +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" EXPOSE 8080 ENV LISTEN_ADDR=0.0.0.0:8080 diff --git a/containers/navidrome/Dockerfile b/containers/navidrome/Dockerfile index 285fd06..7f78d36 100644 --- a/containers/navidrome/Dockerfile +++ b/containers/navidrome/Dockerfile @@ -38,10 +38,12 @@ RUN go build -tags=netgo \ FROM alpine:3.22 -LABEL org.opencontainers.image.title=Navidrome +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="Navidrome" LABEL org.opencontainers.image.description="Navidrome is a self-hosted music server and streamer" -# Points to upstream canonical source, not the forge mirror used for builds -LABEL org.opencontainers.image.source=https://github.com/navidrome/navidrome +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" RUN apk add --no-cache ca-certificates tzdata taglib ffmpeg \ && addgroup -g 1000 navidrome \ diff --git a/containers/nettest/Dockerfile b/containers/nettest/Dockerfile index 2f6991b..4bb1284 100644 --- a/containers/nettest/Dockerfile +++ b/containers/nettest/Dockerfile @@ -8,6 +8,13 @@ ARG CONTAINER_APP_VERSION=0.1.0 FROM alpine:3.22 +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="nettest" +LABEL org.opencontainers.image.description="Network connectivity test container for CI/CD debugging" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" + RUN apk add --no-cache \ curl \ ca-certificates \ diff --git a/containers/ntfy/Dockerfile b/containers/ntfy/Dockerfile index 3fa5c30..238e8c1 100644 --- a/containers/ntfy/Dockerfile +++ b/containers/ntfy/Dockerfile @@ -49,9 +49,12 @@ RUN go build \ FROM alpine:3.22 -LABEL org.opencontainers.image.title=ntfy +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="ntfy" LABEL org.opencontainers.image.description="ntfy is a simple HTTP-based pub-sub notification service" -LABEL org.opencontainers.image.source=https://github.com/binwiederhier/ntfy +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" RUN apk --no-cache add tzdata diff --git a/containers/prometheus/Dockerfile b/containers/prometheus/Dockerfile index 90be789..717293d 100644 --- a/containers/prometheus/Dockerfile +++ b/containers/prometheus/Dockerfile @@ -54,9 +54,12 @@ RUN go build -tags netgo,builtinassets \ FROM alpine:3.22 -LABEL org.opencontainers.image.title=Prometheus +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="Prometheus" LABEL org.opencontainers.image.description="Prometheus monitoring system and time series database" -LABEL org.opencontainers.image.source=https://github.com/prometheus/prometheus +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" RUN apk add --no-cache ca-certificates tzdata diff --git a/containers/quartz/Dockerfile b/containers/quartz/Dockerfile index 5d81920..8ffd44c 100644 --- a/containers/quartz/Dockerfile +++ b/containers/quartz/Dockerfile @@ -11,6 +11,13 @@ ARG NGINX_VERSION=${CONTAINER_APP_VERSION} FROM nginx:${NGINX_VERSION}-alpine +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="Quartz" +LABEL org.opencontainers.image.description="Static site server for Quartz-built documentation" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" + # Install curl for downloading release assets RUN apk add --no-cache curl diff --git a/containers/runner-job-image/Dockerfile b/containers/runner-job-image/Dockerfile index b814339..0018c64 100644 --- a/containers/runner-job-image/Dockerfile +++ b/containers/runner-job-image/Dockerfile @@ -17,6 +17,12 @@ ARG TARGETARCH ARG CONTAINER_APP_VERSION ARG DAGGER_VERSION=${CONTAINER_APP_VERSION} +LABEL org.opencontainers.image.title="Runner Job Image" +LABEL org.opencontainers.image.description="Forgejo Actions job execution environment" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" + # Install base dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ diff --git a/containers/teslamate/Dockerfile b/containers/teslamate/Dockerfile index 2624822..70c6d71 100644 --- a/containers/teslamate/Dockerfile +++ b/containers/teslamate/Dockerfile @@ -45,6 +45,13 @@ RUN SKIP_LOCALE_DOWNLOAD=true mix release --path /opt/built # Runtime image FROM debian:trixie-slim AS app +ARG CONTAINER_APP_VERSION +LABEL org.opencontainers.image.title="TeslaMate" +LABEL org.opencontainers.image.description="Tesla data logger and visualization" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" + ENV LANG=C.UTF-8 \ SRTM_CACHE=/opt/app/.srtm_cache \ HOME=/opt/app diff --git a/containers/transmission-exporter/Dockerfile b/containers/transmission-exporter/Dockerfile index 6a2f2dd..c9d0655 100644 --- a/containers/transmission-exporter/Dockerfile +++ b/containers/transmission-exporter/Dockerfile @@ -5,8 +5,12 @@ ARG CONTAINER_APP_VERSION=1.0.1 FROM python:3.13-alpine3.23 +ARG CONTAINER_APP_VERSION LABEL org.opencontainers.image.title="Transmission Exporter" LABEL org.opencontainers.image.description="Prometheus exporter for Transmission BitTorrent client" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv diff --git a/containers/transmission/Dockerfile b/containers/transmission/Dockerfile index 67ffab2..6d7bcab 100644 --- a/containers/transmission/Dockerfile +++ b/containers/transmission/Dockerfile @@ -8,6 +8,12 @@ FROM alpine:3.22 ARG CONTAINER_APP_VERSION ARG TRANSMISSION_VERSION=${CONTAINER_APP_VERSION} +LABEL org.opencontainers.image.title="Transmission" +LABEL org.opencontainers.image.description="Transmission BitTorrent daemon" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" + # Transmission 4.1.x is only in edge; base OS stays on stable 3.22 RUN apk add --no-cache \ --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community \ diff --git a/containers/unpoller/Dockerfile b/containers/unpoller/Dockerfile index 0391f6d..241b375 100644 --- a/containers/unpoller/Dockerfile +++ b/containers/unpoller/Dockerfile @@ -26,9 +26,12 @@ RUN go build -ldflags="-s -w \ FROM alpine:3.22 +ARG CONTAINER_APP_VERSION LABEL org.opencontainers.image.title="UnPoller" LABEL org.opencontainers.image.description="UniFi metrics exporter for Prometheus" -LABEL org.opencontainers.image.source="https://github.com/unpoller/unpoller" +LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}" +LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops" +LABEL org.opencontainers.image.vendor="blumeops" RUN apk add --no-cache ca-certificates tzdata diff --git a/docs/changelog.d/+oci-labels.infra.md b/docs/changelog.d/+oci-labels.infra.md new file mode 100644 index 0000000..a09b3a8 --- /dev/null +++ b/docs/changelog.d/+oci-labels.infra.md @@ -0,0 +1 @@ +Standardize OCI labels across all container Dockerfiles with consistent title, description, version, source, and vendor metadata.