Adding and Modifying Container Images

All container images are defined in the bci_build.package package as instances of the DevelopmentContainer, ApplicationStackContainer or OsContainer classes.

The different classes result in slightly different images, mostly with respect to the way versions, tags and labels are handled. For example instances of ApplicationStackContainer will receive the label com.suse.image-type="application", whereas all others will have com.suse.image-type="sle-bci".

To create a new container image, pick the most fitting class for it and create an instance of it supplying the following values:

  • name: This is a short identifier of your image and is used to generate the name of this image on the registry as well as the prefixlabel. Pick something short and descriptive, e.g. node for a Node.js container image.

  • pretty_name

  • package_name: The name of the package on build.opensuse.org in devel:BCI:SLE-15-SP${os_version} that is used to build this container image. This value is not autogenerated, as we were inconsistent in the past, but this value should default to uid -image.

  • os_version

  • release_stage

  • package_list: The list of packages to be installed into the container image. You can either provide a list of strings here or provide a list of Package class instances. The latter is only necessary if you want to build your container image with kiwi and wish to customize the package installation (or deletion) process. See Installing Packages into the Container Image for further details.

Adding files to the Image

The package on build.opensuse.org will by default only consist of the following files:

  • Dockerfile or $pkg_name.kiwi and optionally a config.sh

  • $pkg_name.changes

  • _service

It is sometimes necessary to include additional files in a Container Image, e.g. a longer script or configuration file. This can be achieved by adding the file to the extra_files dictionary. The key should be the file name and the value are the file contents.

Please only include very short files directly in package. Longer files should go into a subdirectory of src/bci_build/package/ and be read in on construction. In case you are taking the additional file from an upstream source, then consider adding it to the script update-files.sh as well. A Github Action runs this script every day and ensures that your external file stays up to date.

Automatic Package Version Substitution

Some Container Images ship with environment variables that include the version of a component in the container image. For example the PostgreSQL Container Image sets the environment variable PG_VERSION to the major.minor version of PostgreSQL installed in the container image.

Setting this environment variable manually is rather brittle and would require to constantly update the sources. Instead, we can leverage the service obs-service-replace_using_package_version.

The BaseContainerImage has builtin support for this service via the attribute replacements_via_service. To use it in your container image, pick a replacement string that is unique for your whole build description. For the PostgreSQL version we could for instance pick %%pg_version%%. Then an instance of Replacement needs to be added to the list replacements_via_service, where the attribute regex_in_build_description is set to the replacement string. Additionally the attribute package_name has to be set to the exact name of the package which version we wish to extract. If only a part of the version is required, e.g. as with PG_VERSION where we only care about the major and minor version, but not the patch level, we can instruct the service to only extract the version up to a certain point via the attribute parse_version.

Our PostgreSQL example would result in the following code:

ApplicationStackContainer(
    additional_versions=[f"%%pg_version%%"],
    env={
        "PG_VERSION": f"%%pg_version%%",
    },
    replacements_via_service=[
        Replacement(
            regex_in_build_description="%%pg_version%%",
            package_name=f"postgresql14-server",
            parse_version="minor",
        )
    ],
    # rest follows here
)

Note that this process is not limited to environment variable, it can be used to replace anything inside the container build description. This can be seen in the above code block, where we also set the additional_versions attribute via this mechanism.

Caution

The current setup cannot replace versions in READMEs. If you rely on versions getting replaced in a README (usually via the pretty_reference property), then you must hardcode the version using the mechanism outlined in the versions module.

Installing Packages into the Container Image

In most cases it sufficient to just set the package_list attribute to a list of package names as strings. This will yield a RUN zypper -n in --no-recommends $list_of_packages line in the Dockerfile or the following XML in the kiwi build description:

<packages type="image">
  <!-- one line per package -->
  <package name="$pkg_name"/>
</packages>

Kiwi supports additional package types to e.g. explicitly delete packages or add them to the bootstrap image. Please see https://osinside.github.io/kiwi/concept_and_workflow/packages.html for further details.

To add packages of a different type than image requires to use instances of Package with the pkg_type set to the appropriate value. For example:

package_list=[
    Package(name, pkg_type=PackageType.BOOTSTRAP)
    for name in (
        "bash",
        "ca-certificates-mozilla-prebuilt",
        "distribution-release",
    )
]

Applying additional changes to your Image

Container Images can be tweaked extensively via a plethora of different keywords in Dockerfile. To stay compatible with kiwi build descriptions and to avoid some common pitfalls when creating a Dockerfile.

For the following Dockerfile settings, use the respective properties of BaseContainerImage:

For additional settings that do not fit the existing attributes, either create an abstraction (if feasible and meaningful) or use custom_end to write a raw Dockerfile yourself.

New Package Checklist

  • [ ] Merge the pull request creating the container into main

  • [ ] Review the automatically created pull request against the deployment branches and add a changelog entry

  • [ ] Create the package on devel:BCI: with a <scmsync> entry so that it is pulled from git, this can be done automatically via the scratch_build_bot setup_obs_package command.

  • [ ] Set up branch protection rules for the deployment branches including the newly added package for the OBS SCM builds