Building based on Containers

Note

Abstract

When building images, the KIWI NG stash and stackbuild commands provide an opportunity to address the following requirements:

  • Preserve the image rootfs for a later rebuild without requiring the original software repositories.

  • Build an image based on an existing container.

  • Build an image based on a container stack.

  • Transform a container into a KIWI NG image type.

Requirements

The stash and stackbuild commands are part of KIWI NG. Add the KIWI NG repo from the Open Build Service. For details, see Installation from OBS. The following package pulls in the host requirements for the stash and stackbuild commands, like podman and the OCI container tools:

$ sudo zypper in kiwi-systemdeps-stackbuild

Note

The stash and stackbuild commands were formerly provided by the kiwi-stackbuild-plugin. The plugin is no longer needed and is replaced by the kiwi-systemdeps-stackbuild package.

Concept

The design of the stackbuild concept is twofold:

First, KIWI NG comes with a command called stash that allows you to store a kiwi-built root tree as an OCI container. OCI stands for Open Container Initiative and is a de facto standard format in the container world. Once the container has been created, it can be managed using the preferred container toolchain. The stash and stackbuild commands use podman to work with containers.

As a next step, and with the root tree as a container, KIWI NG offers the opportunity to build images based on one or more containers. That’s also the reason why the other command is called stackbuild, as it allows you to stack different root containers together.

The stash and stackbuild commands can be used independently from each other. If there is already a registry with containers that should be used to build images from, stackbuild can directly consume them.

This concept leads to a number of use cases, and a few of them were picked and put into the abstract of this article. For the purpose of documenting the functionality of the commands, only a part of the possibilities are taken into account as follows:

Create a stash

The stash command creates an OCI-compliant container from a given KIWI Next Generation (KIWI NG) image root tree and registers it in the local container registry. From there, a user can push it to any registry of choice.

The following example creates a stash of a Tumbleweed build and illustrates how to register it in a foreign container registry:

# Build some image...
$ git clone https://github.com/OSInside/kiwi.git
$ sudo kiwi-ng system build \
    --description kiwi/build-tests/x86/tumbleweed/test-image-MicroOS/ \
    --set-repo http://download.opensuse.org/tumbleweed/repo/oss \
    --target-dir /tmp/myTWToday

# Stash the image root into a container
$ sudo kiwi-ng system stash \
    --root /tmp/myTWToday/build/image-root \
    --container-name twmos-snapshot

# Register the stash in a registry
$ podman login
$ podman push twmos-snapshot \
    docker://docker.io/.../twmos-snapshot:2021-10-08

If the stash command is called multiple times with the same container name, this leads to a new layer in the container for each call. To inspect the number of layers added to the container, the following command can be used:

$ podman inspect twmos-snapshot

To list all stashes created by the stash command, the following command can be used:

$ kiwi-ng system stash --list

Rebuild from a stash

The stackbuild command takes the given container(s) from the local or remote registry and uses it/them to either rebuild an image from that data or build a new image on top of that data. If multiple containers are given, the stackbuild command stacks them together in the order in which they were provided.

Note

When using multiple containers, the result stack root tree is created from a sequence of rsync commands into the same target directory. The stackbuild command does this with any container content given and does not check, validate, or guarantee that the selection of containers is actually stackable or leads to a usable root tree. This means it’s the caller’s responsibility to make sure the provided containers can actually be stacked together in the given order.

To simply rebuild the image from the stash created in Create a stash, call stackbuild as follows:

# Delete the image
$ sudo rm -rf /tmp/myTWToday

# Rebuild image from stash
$ sudo kiwi-ng system stackbuild \
    --stash twmos-snapshot \
    --target-dir /tmp/myTWToday

This rebuilds the image from the stash and the KIWI NG configuration inside of the stash. As all rootfs data is already in the stash, the command will not need external resources to rebuild the image.

Additional arguments for the kiwi-ng system create command, or for the kiwi-ng system build command if --description is given, can be passed after the kiwi subcommand. For compatibility with the former kiwi-stackbuild-plugin, the -- separator is accepted as an alias for kiwi. For all options, see kiwi-ng system stackbuild and kiwi-ng system stash.

Turn a container into a VM image

Another use case for the stackbuild command is the transformation of container images into another image type that is supported by KIWI NG. The following example demonstrates how an existing container image from the openSUSE registry can be turned into a virtual machine image.

When moving a container into a virtual machine image, the following aspects have to be taken into account:

  1. A container image usually has no kernel installed.

  2. A container image usually has no bootloader installed.

  3. A container image usually has no user configured.

For a VM image, the mentioned aspects are mandatory. Therefore, the following KIWI NG image description contains this additional information that the container cannot provide: Create the KIWI NG description as follows:

$ mkdir container_to_VM_layer
$ vi container_to_VM_layer/config.kiwi

And place the following content:

<?xml version="1.0" encoding="utf-8"?>

<image schemaversion="8.5" name="Leap-VM">
    <description type="system">
        <author>The Author</author>
        <contact>user@example.org</contact>
        <specification>
            Leap Container as VM
        </specification>
    </description>
    <preferences>
        <type image="oem" filesystem="xfs" firmware="uefi">
            <oemconfig>
                <oem-resize>false</oem-resize>
            </oemconfig>
        </type>
        <version>1.99.1</version>
        <packagemanager>zypper</packagemanager>
        <locale>en_US</locale>
        <keytable>us</keytable>
        <timezone>UTC</timezone>
    </preferences>
    <repository type="rpm-md" alias="Leap">
        <source path="https://download.opensuse.org/distribution/leap/16.0/repo/oss"/>
    </repository>
    <packages type="image">
        <package name="grub2"/>
        <package name="grub2-x86_64-efi" arch="x86_64"/>
        <package name="grub2-i386-pc"/>
        <package name="shim"/>
        <package name="kernel-default"/>
    </packages>
    <users>
        <user password="$1$wYJUgpM5$RXMMeASDc035eX.NbYWFl0" home="/root" name="root" groups="root"/>
    </users>
</image>

To build the virtual machine image from the currently hosted Leap 16.0 container at SUSE, call the following stackbuild command:

$ sudo kiwi-ng system stackbuild \
    --stash leap:16.0 \
    --from-registry registry.opensuse.org/opensuse \
    --target-dir /tmp/myLeap \
    --description container_to_VM_layer

The resulting virtual machine image can be booted as follows:

$ qemu-kvm Leap-VM.x86_64-1.99.1.raw