3 Label Schema
Note: I’m only considering labels on images built from Dockerfiles, not images modified interactively and then saved and shared.
3.1 The LABEL instruction
The goal of the LABEL
Dockerfile instruction is to specify metadata as key=“value” entries that can be inspected, e.g. with docker info <imageName>
. Labels can also be added at build time by using the docker build --label "key=value"
option.
Note: Adding a label at build time could break the build cache, but it is implemented smartly; labels are added at the end of the build, so if a new or different label is added to a previously-run build command, everything is preserved except for the final step. Even the “add labels” step is cached and reused if the build command uses the same labels [SRJ in the same order?].
3.2 Image label standards
There are more than one labeling standard, none of which are complete. So I just use them for source info on what kinds of labels I want. My notes on them follow in the sections Open Containers Standard{open-containers-standard} and Biocontainers Standard
What’s missing is that metadata needs to be inherited in a hierarchy, not flat. Flat means values inherited from parents are lost when a child declares a label of the same name, and if a child does not define a label the parent does, it is inherited with no indication of where it came from - e.g. the email of the maintainer.
To add this without changing how docker formats labels is the trick. It requires every image to have its own unique namespace prefix that is used as a prefix for all its labels. Then each (reverse-domain-name prefixed) label inherited is preserved and associate with a specific parent image.
3.4 io.github.jefferysdockers Label Schema
3.4.1 Required prefixes
All labels must be prefixed by the full reverse domain name for the image pull command, converting slashes to periods and leaving out a leading com.dockerhub.
if needed. For example, if an image primary hosting is at
dockerhub.com/jefferys/ubu-lts
its prefix would be
jefferys.ubu-lts.
Following the image prefix, images should be labeled by the reverse domain name of the schema where the labels are defined. This schema is defined at
jefferysdockers.github.io
so its labels are specified with a prefix of
io.github.jefferysdockers.
So in total, all labels from this schema in the above image would have a prefix of
jefferys.ubu-lts.io.github.jefferysdockers.
Labels from other schema can be included in conforming containers, but must also have the image hosting prefix in addition to their domain specific labels, or even simple labels. For example other labels added to the image for some use cases might look like:
jefferys.ubu-lts.com.example.rating="10"
jefferys.ubu-lts.com.needs-mem="32G"
It is permissible to add a simple label like needs-mem="32G"
to an image for purely local use, but such labels should never be used on shared hosted images, and care must be taken by local users in labeling images used as the base for another.
Note: Since there are required labels, and only conforming images should use the io.github.jefferysdockers.
prefixes, it is always possible to parse the image name prefix preceding such a label, and hence user labels are can be parsed as well.
3.4.2 Required labels
-
io.github.JefferysDockers.base-prefix
- Declares the prefix used in the base image. […]By specifying the prefix the base image uses to identify its labels, image -> base image relationships can be deduced. Must be
"scratch"
if an image has no base, and must be""
(the empty string) if the base image does not conform to theio.github.JefferysDockers
labeling standard.Examples:
LABEL jefferys.ubu-lts.io.github.JefferysDockers.base-prefix="scratch" LABEL jefferys.bioc.io.github.JefferysDockers.base-prefix=""
-
io.github.JefferysDockers.label-schema-version
- The version of theio.github.JefferysDockers
labeling schema a conforming image uses. […]Must be specified last in the Dockerfile or be followed only by LABEL statements. It may also be specified on the build command line using the
--label
option as those are added into the container at the end asLABEL
instructions.Examples:
LABEL jefferys.ubu-lts.io.github.JefferysDockers.label-schema-version="0.0.1" docker build --label "jefferys.ubu-lts.io.github.JefferysDockers.label-schema-version=0.0.1"
[TODO - CONTINUE FROM HERE]
3.4.3 Optional Labels
[TODO - CONTINUE FROM HERE]
3.4.4 Example build script
This is essentially the build.sh for the ubu-lts base Docker, with several optimizations to use with DockerHub’s automated build environment, which includes the environmental variables:
$DOCKER_REPO
- The base name of the repo that will be pulling and building this
$DOCKERFILE_PATH
- The path to the Dockerfile, relative to the root of the build source repo.
"TAG"
- The name of the file containing the full version tag to use, as
In reality this will be in a file “hooks/build”, the real build.sh in the repo just calls this script and provides values for the ENV variables above, if not specified
###
# Label input parameters
###
# Describing the image
imageName="${DOCKER_REPO}"
dockerfilePath="${DOCKERFILE_PATH}"
spdxLicense=""
licenseFile="https://ubuntu.com/licensing"
baseImagePrefix="scratch"
title="${imageName} - Base OS derived from Ubuntu."
description="Based on Ubuntu this is a completely local build of a base Docker from scratch."
keywords="Linux, Ubuntu, scratch, os"
# Describing the image's content (the included Ubuntu distro)
contentHome="https://wiki.ubuntu.com/Base"
contentSource="http://cdimage.ubuntu.com/ubuntu-base/"
contentTitle="Ubuntu base os distribution"
contentDescription="Minimalist non-official functional distribution of Ubuntu, including apt-get"
contentSpdxLicense=""
contentLicenseFile="https://ubuntu.com/licensing"
contentVendor="Canonical"
contentVendorUrl="https://canonical.com/"
# Independent of image and content
labelSchemaVersion="0.0.1"
vendor="UNC - Lineberger"
vendorUrl="https://lbc.unc.edu/"
# Constant across my dockers
labelSchema="io.github.JefferysDockers"
imageRepoOwner="jefferys"
sourceRepoOwner="JefferysDockers"
imageRepoRootUrl="https://hub.docker.com/r"
sourceRepoRootUrl="https://github.com"
maintainer="Stuart R. Jefferys <stuart_jefferys@med.unc.edu>"
###
# End of label input parameters
###
# Get tag for image, and parse into parts: the before first "-" part (the tool
# version) and the after first "-" part (the build version).
read TAG < "TAG"
contentVersion="${TAG%%-*}"
sourceVersion="${TAG#*-}"
# Time created
created="$(date "+%Y-%m-%dT%H:%M:%S%z")"
afterPos=$(( ${#created} - 2 ))
created="${created:0:${afterPos}}:${created:${afterPos}}"
# Full label namespace with unique image id prepended
NS="${imageRepoOwner}.${imageName}.${labelSchema}"
###
# Build command.
###
docker build \
--label "${NS}.base-prefix=${baseImagePrefix}" \
--label "${NS}.name=${imageName}" \
--label "${NS}.home=${imageRepoRootUrl}/${imageRepoOwner}/${imageName}" \
--label "${NS}.version=${TAG}" \
--label "${NS}.maintainer=${maintainer}" \
--label "${NS}.source-version=${sourceVersion}" \
--label "${NS}.source-home=${sourceRepoRootUrl}/${sourceRepoOwner}/${imageName}" \
--label "${NS}.source-maintainer=${maintainer}" \
--label "${NS}.pull=${imageRepoOwner}/${imageName}:$TAG" \
--label "${NS}.license-spdx=${spdxLicense}" \
--label "${NS}.license-file=${licenseFile}" \
--label "${NS}.vendor=${vendor}" \
--label "${NS}.vendorUrl=${vendorUrl}" \
--label "${NS}.title=${title}" \
--label "${NS}.description=${description}" \
--label "${NS}.content-home=${contentHome}" \
--label "${NS}.content-version=${contentVersion}" \
--label "${NS}.content-source=${contentSource}" \
--label "${NS}.content-license-spdx=${contentSpdxLicense}" \
--label "${NS}.content-license-file=${contentLicenseFile}" \
--label "${NS}.content-vendor=${contentVendor}" \
--label "${NS}.content-vendorUrl=${contentVendorUrl}" \
--label "${NS}.content-title=${contentTitle}" \
--label "${NS}.content-description=${contentDescription}" \
--label "${NS}.created=${created}" \
--label "${NS}.label-schema-version=${labelSchemaVersion}" \
--tag "${imageRepoOwner}/${imageName}:latest" \
--tag "${imageRepoOwner}/${imageName}:${contentVersion}" \
--tag "${imageRepoOwner}/${imageName}:${contentVersion}-${sourceVersion}" \
-f ${dockerfilePath} \
.