Skip to main content

Create a package (RPM or Container image) using OBS (openSUSE Build Service)

openSUSE Build Service

The openSUSE Build Service is the public instance of the Open Build Service used for development of the openSUSE distribution and to offer packages from same source for Fedora, Debian, Ubuntu, SUSE Linux Enterprise and other distributions.

This service is also able to build container images, using either a Dockerfile or a KIWI configuration.

Everyone can create a SUSE IdP account to be able to use this service.

A published container image will be available on registry.opensuse.org and a published package would be available at download.opensuse.org

Prerequisites

In order to use OBS you first need an IdP account (sign up here) and you need to log into build.opensuse.org

You will also need the osc (for openSUSE Commander) command as this quickstart will do it the CLI way, but most things can be done in the WebUI if you prefer.

To install osc:

zypper install osc

Create and configure a project

We are going to create a project under your home namespace, this will bring up your editor to configure it right away.

osc meta prj -e "home:$USERNAME:$PROJECTNAME"
note

If you want to use your home project root just specify home:$USERNAME here and in following steps.

In the editor you can now fill the metadata to look similar to this:

<project name="home:$USERNAME">
<title/>
<description/>
<person userid="$USERNAME" role="maintainer"/>
<!--
If you want to build RPM packages you need a block like this one, here for
SLE-15 SP5 replace accordingly to the distribution you want to target
-->
<repository name="sp5">
<path project="SUSE:SLE-15-SP5:Update" repository="standard"/>
<path project="SUSE:SLE-15-SP5:GA" repository="standard"/>
<arch>x86_64</arch>
<arch>aarch64</arch>
</repository>
<!-- If you want to build container images you need a block akin to this one -->
<repository name="containers">
<!--
This defines the available source images for the build (here any from
registry.suse.com)
-->
<path project="SUSE:Registry" repository="standard"/>
<!--
This defines package repositories available during build, I am
refering to the one above here so I can use the RPM packages published
in this project for the container images of the project
-->
<path project="home:$USERNAME:$PROJECTNAME" repository="sp4"/>
<!-- This is the list of architecture you want to build for -->
<arch>x86_64</arch>
<arch>aarch64</arch>
</repository>
</project>

If you want to build containers you need to tweak the configuration of the project as well:

osc meta prjconf -e "home:$USERNAME:$PROJECTNAME"

The configuration is different whether you want to use KIWI or Dockerfile build system:

%if "%_repository" == "containers"
Type: docker
Repotype: none
Patterntype: none
BuildEngine: podman
%endif
note

If you want to build containers using both KIWI and Dockerfiles in the same project, you need two repositories in your project's metadata (with different names) and both snippets in project's configuration (one for each repository).

Create a package

To create a package in your project use the following command:

osc meta pkg -e home:$USERNAME:$PROJECTNAME $PACKAGENAME

There you'll get another XML file to edit, you only have to set a title and description here.

Now you can checkout the directory to start adding your files:

osc co home:$USERNAME:$PROJECTNAME/$PACKAGENAME

Now go into the directory and when all is ready you can add your files and commit using:

osc add <files>...
osc ci

Now let's see the specificities of RPM and Container packages

RPM package

An RPM package is defined by the presence of a spec file, I will not go into the details of that file as this is way beyond the scope of that quickstart, please refer to https://en.opensuse.org/Portal:Packaging for more details about packaging.

I will however get into more details about the _service and _constraints special files that may change the behavior of OBS.

The _service file allows one to define automation to happen on said time, for RPM packages these are usually manually triggered. It is then possible to automate fetching a git repository into a tarball, updating the specfile version from git info, vendoring go or rust dependencies, etc...You can get more insight into what is possible here https://en.opensuse.org/openSUSE:Build_Service_Concept_SourceService .

Here is one for a rust project for example:

_services
<services>
<service name="tar_scm" mode="manual">
<param name="scm">git</param>
<param name="url">https://github.com/project-akri/akri</param>
<param name="filename">akri</param>
<param name="versionformat">@PARENT_TAG@</param>
<param name="versionrewrite-pattern">v(.*)</param>
<param name="revision">v0.10.4</param>
</service>
<service name="recompress" mode="manual">
<param name="file">*.tar</param>
<param name="compression">xz</param>
</service>
<service name="set_version" mode="manual" />
<service name="cargo_vendor" mode="manual">
<param name="srcdir">akri</param>
<param name="compression">xz</param>
</service>
</services>

The _constraints file allow to define "restrictions" about the builder selected by OBS, like for example the disk size, if your build complains about having not enough space, this is the file you should edit/create. See here for the complete guide: https://openbuildservice.org/help/manuals/obs-user-guide/cha.obs.build_job_constraints.html

Container image

You can build a container image in two different ways, you can either use a Dockerfile or a KIWI configuration.

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 opensuse/tumbleweed.

I won't go into details how a Dockerfile or a kiwi build works, I'll just tell about the interaction with OBS.

First the kiwi_metainfo_helper service that you can add as a buildtime source service allows to substitute buildtime placeholders to use in you Dockerfile or kiwi configuration. You can find a list of the placeholders here: https://build.opensuse.org/package/view_file/openSUSE:Factory/obs-service-kiwi_metainfo_helper/README

Another useful service is the replace_using_package_version service, that allows to replace a placeholder with the version of a RPM package. For example if I have foobar package in version 1.2.3 in an available RPM repository, I can use this service to automatically tag an image that has this package installed. Here it would replace %PKG_VERSION% to 1.2.

_services
<services>
<service mode="buildtime" name="kiwi_metainfo_helper"/>
<service mode="buildtime" name="replace_using_package_version">
<param name="file">Dockerfile</param>
<param name="regex">%PKG_VERSION%</param>
<param name="parse-version">minor</param>
<param name="package">foobar</param>
</service>
</services>

You now have to tell OBS about the name and tag of your image:

You can use one or multiple BuildTag as comments in your Dockerfile like this:

#!BuildTag: foo/bar:latest foo/bar:%PKG_VERSION%.%RELEASE%
#!BuildTag: foo/bar:tag foo/bar:anothertag