Passing the `defaultBranch` argument to `buildContainerImage2()` allows
setting the `latest` for projects where the default branch is not
*main*. For example:
```groovy
buildContainerImage2(defaultBranch: 'master')
```
This will update the `latest` tag whenever a new build is created on the
*master* branch.
The `buildContainerImage2` function now accepts an optional `schedule`
argument. If specified, the value will be used as the cron expression
for triggering a build periodically.
If the image being built is only for a single architecture, the step to
unstash the OCI archive file was missing. This caused the build to fail
at the Push step, since there was noting to push.
If the provided container image name includes a `/` character, the build
will fail when copying the OCI image to a tarball:
> + buildah push git.pyrocufflink.net/containerimages/build/selinux:dev-ci oci-archive:/home/jenkins/agent/workspace/ainerImages_build.selinux_dev_ci/build/selinux-amd64.tar
> Error: lstat /home/jenkins/agent/workspace/ainerImages_build.selinux_dev_ci/build: no such file or directory
To resolve this, we need to escape the image name when constructing the
path to the tar file.
The `buildContainerImage2` function is an improvement on the existing
`buildContainerImage` function, with a couple of enhancements.
Primarily, it supports building images for multiple architectures. For
each listed architecture, a pod is launched on a matching worker node to
build the image natively. The image is exported to an OCI archive and
"stashed" in the Jenkins workspace. After images for all architectures
are built, another pod is launched and all of the stashed archives are
copied there and assembled into a manifest list. Finally, the manifest
list is published to the OCI repository as usual, creating tags for the
Git branch and build number.
In addition to adding support for multiarch images, the
`buildContainerImage2` performs image builds in *unprivileged* pods.
Whereas the old function performed builds in a rootful container, the
new one configures requests pods with unique user namespaces. The build
runs as *root* in the container, but that user is mapped to an arbitrary
unprivileged user on the host.