Building derived containers
This is the specification for all container images inside openSUSE distributions. If you build images in your home project on OBS or in a devel project not intended for submission to a openSUSE distribution, they are not required to follow this specification.
Checking most rules during build is being worked on. Once that is active, any violation of the rules will be reported during build, and inside of
openSUSE: projects result in a build failure.
Certain terms referring to parts of a container image reference are used throughout this document:
namespace tag |-------| |----| registry.opensuse.org/foo/bar/baz:latest |--------------------|-----------| registry repository |--------------------------------------| reference
Choice of Build Tool
The container image must be built either using a KIWI recipe or a Dockerfile (built using podman).
Each method has their own benefits and drawbacks. Kiwi supports using the package manager from the host/build system, so it can build base images and derive images which don't contain a package manager, like
opensuse/busybox. With Dockerfile, it's practically required to use a full base image like
- An image submitted as
foo-imageneeds to contain a matching
- Mentioning repositories directly is not allowed (using
- When using kiwi, the package name used for submission and
<image name="foo"/>attribute inside the
.kiwifile have to be identical
- The build recipe and accompanying files have to be under an OSI approved license. The full license text has to be included as a separate file.
All images published from
openSUSE:Containers subprojects on OBS are visible on registry.opensuse.org with the repositories and tags defined by those images (See Tagging). Unlike for home: and devel projects, there is no forced prefix based on the project and (build) repository names.
As every image can define its location(s) on the registry freely, it is important that there is coordination and collaboration between them. This is mainly to avoid conflicts and confusion, but also to ensure consistency, because those references are publicly visible.
registry.opensuse.org is shared between the officially released images and arbitrary images from devel and home projects, special care has to be taken that it's easy to tell whether a specific image is from an official source. Currently this is achieved by reserving special prefixes which don't overlap with non-official projects:
While the repository and tag names can be any valid OCI identifiers, there are certain restrictions imposed by external tools:
- docker defaults to using Docker Hub as registry (hardcoded!), where anyone can upload images. It is beneficial that the chosen repository name is not allocated on Docker Hub, otherwise that might be used by accident. The
opensuse/prefix (e.g. used by base containers) on Docker Hub is empty, thus there is no ambiguity.
- Some registries do not support repositories at the root (
registry.opensuse.org/foo:latest) or nested namespaces (
registry.opensuse.org/asdf/bar/baz:latest). The latter is becoming less of an issue lately though.
- Repository names can't also be used as namespaces, e.g. (
registry.opensuse.org/some/container/withstuff:latest), which means that for instance
opensuse/tumbleweed/httpdis not possible.
The package name (e.g.
opensuse-tumbleweed-image) has to end in either
-container and have a relation to the main image name. For
opensuse/hello-world, matching package names would be
opensuse-hello-world-image or just
Tags can be defined freely. On every release of a new build (Tumbleweed Snapshot, Leap Images build), the new builds are
released into a subproject of
openSUSE:Container and the old images are kept.
If a tag is provided by multiple images, the newest image is used.
There has to be a tag which is provided by a single specific build only. This can only be achieved by including the full version (with build counter).
When using kiwi_metainfo_helper service, this could be expressed as e.g.
#!BuildTag: opensuse/example:1.0 opensuse/example:1.0.%RELEASE%
This tag is the one which has to be used in the
One drawback of using Docker labels (which we need for compatibility) is that there is only one level of them in an image and not one per layer.
This means that labels defined in the base container can be overwritten by labels in derived images. Those which aren't overwritten aren't shown as coming from the base container.
To workaround that, specific information has to be cloned in container-specific labels, which are prefixed with
Here's the full list of labels/annotations defined in a openSUSE base container. Most of them need to be provided by derived images as well.
|Label(s)||OCI Annotation||Must be provided by derived images||Description||Example|
|org.opencontainers.image.title org.opensuse.base.title||org.opencontainers.image.title||Yes||Title of the image|
|org.opencontainers.image.description org.opensuse.base.description||org.opencontainers.image.description||Yes||Short description of the image|
|org.opencontainers.image.version org.opensuse.base.version||org.opencontainers.image.version||Yes||Version of the image. <version>.<cicnt>.<bldcnt>|
|org.opencontainers.image.created org.opensuse.base.created||org.opencontainers.image.created||Yes||Date/time of image build|
|org.opencontainers.image.vendor org.opensuse.base.vendor||org.opencontainers.image.vendor||No||Vendor of the image|
|org.opencontainers.image.url org.opensuse.base.url||org.opencontainers.image.url||No||URL with more information|
|org.openbuildservice.disturl org.opensuse.base.disturl||org.openbuildservice.disturl||Yes||Dist URL as provided by OBS|
|org.opensuse.reference org.opensuse.base.reference||org.opensuse.reference||Yes||Reference pointing to this specific image (
Each image should define a history entry with a human-readable description of what it is. This way it's easy to get an overview on what each layer in an image is.
> docker history opensuse/tumbleweed IMAGE CREATED CREATED BY SIZE COMMENT aaa05880bad2 2 days ago KIWI 9.17.15 123MB openSUSE Tumbleweed 20190312 Base Container
The easiest way to get started with a new container image build is by using the predefined templates and submitting them.
Branching a Template
On the OBS main page, there's a link to an overview of available templates. The "Application Container using Dockerfile/KIWI" and "Derived Container using KIWI" templates are usable as a base for submission to openSUSE distributions. If you click on the title of the template, you can look around inside and find out which one fits best
Depending on your choice of tool, select the appropriate template for the distribution you want to build against. Make sure to branch into a project which does not exist yet or the image will not build correctly. If the target project is already set up to build images against the distro you selected, for instance by branching into the project previously, that's fine too.
Adjusting the Build Recipe Files
Each template has a README file with instructions specific to the template inside.
Adding a .changes file
Either use the Web UI to create the
foo.changes file (matching the package name) and create an entry or run
osc vc foo.changes in the OSC checkout.
The first changelog entry should contain a short description of what the image is.
Adding a README
This step isn't mandatory, but recommended for images with a custom entrypoint. Documentation on how to use the image and which variables it accepts belongs in here.
After enabling publishing for the package (or entire project) on OBS, the image is accessible through registry.opensuse.org. You can use docker and podman to download it, see the registry overview page.
The location is the project name on OBS with ':' substituted with '/' and the repository (KIWI:
e.g. https://build.opensuse.org/package/show/openSUSE:Templates:Images:Tumbleweed/dockerfile-application-container builds
opensuse/example:latest and is available as
Container images can be submitted to
openSUSE:Leap:15.1 and later.
For Leap it's possible to introduce new images by submitting it as maintenance update.
The usual rules for submission to distros apply, so a devel project needs to be picked and used as submission base.
Useful OBS services
Multiple OBS services aid in implementing the specification by simplifying some processes like label definition and version handling.
They are added and configured in the _service files (see the templates for examples) and run various scripts before the build begins.
Dockerfile + KIWI: obs-service-kiwi_metainfo_helper
To make it possible to include buildtime information like the current build number in labels and tags, this service substitutes certain placeholders in the recipe file. It works for both .kiwi and Dockerfile recipes.
An updated list of all placeholders and their content is in the package itself, you can read it here.
KIWI only: obs-service-kiwi_label_helper
To make it easier to define labels for the "org.opensuse.<containername>" namespace, there's an OBS service that converts the OCI annotations to the final labels.
Copy of the README:
This service can be enabled to run during buildtime, when it will edit the
kiwi image descriptions to expand the
<image [...] xmlns:suse_label_helper="com.suse.label_helper"> [...] <containerconfig [...]> <labels> <suse_label_helper:add_prefix prefix="org.opensuse.base"> <label name="org.opencontainers.image.title" value="openSUSE Tumbleweed Base Container"/> </suse_label_helper:add_prefix>
<image [...] xmlns:suse_label_helper="com.suse.label_helper"> [...] <containerconfig [...]> <labels> <label name="org.opencontainers.image.title" value="openSUSE Tumbleweed Base Container"/> <label name="org.opensuse.base.title" value="openSUSE Tumbleweed Base Container"/>
Dockerfile only: obs-service-docker_label_helper
To make it easier to define labels for the "org.opensuse.<containername>" namespace, there's an OBS service
which provides a
PREFIXEDLABEL pseudoinstruction which expands to both the original label as well as the container-specific one with the defined
See the README for details.
Tips for using KIWI
KIWI supports an
additionaltags attribute and obs services, such as obs-service-kiwi_metainfo_helper, can add build-time information to tags.
<preferences> <type image="docker"> <containerconfig name="opensuse/leap" tag="15.0.%RELEASE%" additionaltags="15.0" maintainer="Fabian Vogt <firstname.lastname@example.org>"> <labels>
Tips for using Dockerfile
Dockerfile recipes don't have any information about how the built image should be called, this is passed to
docker/podman build manually when building an image.
OBS gets that information from special comments inside the Dockerfile, such as:
#!BuildTag: opensuse/example:1.0 opensuse/example:latest
You can mention multiple names in the same
BuildTag comment or add multiple of those comments.
Containers are built in
openSUSE:Leap:15.x:Images next to other images in the same repo. A list in the OSRT:ToTestManagerConfig attribute for each project tells the totest-manager bot which of the built images are container images and should be released to the registry instead of the download server.
Those images are released into the
containers repo of the
:ToTest subproject, where they are pushed to
registry.opensuse.org and openQA can download and test them from there. This is done by the "image" test module, which is instantiated for multiple container runtimes (docker, podman, ...).
After openQA marks a snapshot/build as good, ttm releases the containers from
:ToTest/containers into its releasetarget. For
openSUSE:Factory:ToTest/containers that is
Those target projects have
kind="maintenance_release" set in their meta, so on every release, binaries are added instead of overwritten. This means that every container released (and not cleaned up) is available on OBS and the registry.
For every repo on the registry (e.g.
kubic/pause), there's exactly one project/repo combination on OBS which provides the images to feed those. This is not an issue for Tumbleweed and Kubic currently, but as all versions of Leap share one repo but the images are distributed over multiple projects (
openSUSE:Containers:Leap:15.x), this has to be worked around. It is achieved by creating an intermediate project at
openSUSE:Containers:Leap which aggregates all binaries ending up in the
opensuse/leap repo on the registry. The origin projects themselves are published disabled to make it work.
For providing the dynamic
opensuse/leap:15 tags, those are added to the aggregates as specified in the project config.