The wikis are now using the new authentication system.
If you did not migrate your account yet, visit

Building derived containers

Jump to: navigation, search
This article provides a guide and a specification for building container images derived from openSUSE base 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.

Rules enforced by openSUSE:Factory

If these rules are not followed, the factory-auto bot will reject the submit request to openSUSE:Factory.

  • The container image must be built using KIWI
  • Custom repositories are not added inside the *.kiwi file (only obsrepositories:/ allowed)
  • The file has a matching foo.changes file
  • The <image name="foo"/> attribute inside the file matches the file's basename

Image name

The name of the image (e.g. opensuse/hello-world) has to be prefixed with either opensuse/ or kubic/ and must not collide with other images in openSUSE distributions, as they would overwrite each other.


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.


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 org.opensuse.<containername>.

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 openSUSE Tumbleweed Base Container
org.opencontainers.image.description org.opensuse.base.description org.opencontainers.image.description Yes Short description of the image Image containing a minimal environment for containers based on openSUSE Tumbleweed.
org.opencontainers.image.version org.opensuse.base.version org.opencontainers.image.version Yes Version of the image. <version>.<cicnt>.<bldcnt> 20181224.4.2
org.opencontainers.image.created org.opensuse.base.created org.opencontainers.image.created Yes Date/time of image build 2019-01-05T14:12:30Z
org.opencontainers.image.vendor org.opensuse.base.vendor org.opencontainers.image.vendor No Vendor of the image openSUSE Project
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 obs://
org.opensuse.reference org.opensuse.base.reference org.opensuse.reference Yes Reference pointing to this specific image ([:tag])


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 in 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

Getting started

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.

Choose one of the "Container built using KIWI" options 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.

Editing the Predefined Configuration

As first step, you should rename the file appropriately and adjust the name inside. For instance, if you want to build a container for "foo", rename into and set the name attribute at the top as well, e.g. <image name="foo" ... />.

Next, set the metainfo in the <containerconfig/> element, so name, tag(s), labels and the history entry. Also adjust the <description/> element to match the image you're creating.

For the syntax and structure of the .kiwi file in general, read the KIWI manual.


After enabling publishing for the package (or entire project) on OBS, the image is accessible through You can use docker and podman to download it, see the registry overview page.


Container images can be submitted to openSUSE:Factory and 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.

After the image got accepted into the distro, ask the release team to enable it for publishing either per E-Mail to the [opensuse-factory] mailing list or the #opensuse-factory IRC channel on freenode.

Implementation Details


KIWI supports an additionaltags attribute and obs services, such as obs-service-kiwi_metainfo_helper, can add build-time information to tags.

    <type image="docker">
            maintainer="Fabian Vogt <>">


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 <suse_label_helper:add_prefix/> element.


<image [...] xmlns:suse_label_helper="com.suse.label_helper">
       <containerconfig [...]>
          <suse_label_helper:add_prefix prefix="org.opensuse.base">
            <label name="org.opencontainers.image.title" value="openSUSE Tumbleweed Base Container"/>

expands to

<image [...] xmlns:suse_label_helper="com.suse.label_helper">
       <containerconfig [...]>
           <label name="org.opencontainers.image.title" value="openSUSE Tumbleweed Base Container"/>
           <label name="org.opensuse.base.title" value="openSUSE Tumbleweed Base Container"/>


To make it possible to include buildtime information as used for the labels and tags, this service substitutes certain placeholders.

An updated list of all placeholders and their content is in the package itself, you can read it here.

Release mechanism

Containers are built in openSUSE:Factory and 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 and openQA can download and test them from there. This is done by the "docker_image" test module.

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 openSUSE:Containers:Tumbleweed. 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. opensuse/tumbleweed and 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 itself are publish disabled to make it work.

For providing the dynamic opensuse/leap:latest and opensuse/leap:15 tags, those are added to the aggregates as specified in the project config.