Where’s The Red Hat Universal Base Image Dockerfile?

So, you’re looking for the Dockerfile used to create the Red Hat Universal Base Image (UBI)? Since it’s release this has become a very popular question. The first time somebody asked me, I literally froze. It made no sense to me and for a split second I even second guessed my own knowledge of how base images are created (I started creating them back in 2014). Sigh – what are you trying to do? After some probing, I figured out that most people don’t have a clear understanding of:

  1. What a base image is
  2. How operating systems are installed
  3. How base images are built
  4. How these two things are basically the same

People are actually looking to understand how UBI is built. It’s hard to feel good about something until you understand it to a certain level of clarity.

TL;DR – The contents of most base images are created with operating system installers. While many base images utilize a Dockerfile, it probably doesn’t provide what you’re looking for. There’s an underlying chicken and egg problem because without a package manager installed and configured, the step by step instructions of how every file is laid out on disk can’t be easily expressed in a Dockerfile.

Let me explain why this question is so weird. We often abuse the word base image. We use it to describe any image that we build our application on, but this creates a lot of confusion. True base images are fundamentally different than layered images. Dockerfiles are good at building layered images, not base images. The contents of a base image are often referred to as a root filesystem or rootfs. This is an old school way of describing the files that you see when you type ls in the the root directory (aka slash, aka “/”) on Linux and Unix. Operating system installers have always handled the creation of this rootfs. This includes installing a package manager and configuring it correctly so that users can install more packages later. Have you ever typed yum update and gotten a new version of rpm – think through how that’s possible – it’s a deep problem. Many of us old school Linux users just assume everybody out there has done a Gentoo Stage 1 install before and understands all of this with crystal clarity. While I would urge everyone to suffer through one of those installs, let’s try to explain it in less time 🙂

If you were to build a base image from a Dockerfile, most people assume you would start from scratch like this:

FROM scratch

.....

But, that doesn’t work. Scratch images are fine for simple binaries (C/C++ or Golang), but how do you get access to RPM, YUM or APT in there? There’s a clear chicken and egg problem. The next logical step is to copy files from the build host. That’s called bootstrapping. In fact, that’s exactly what many base image builders do. Check out these examples:

Three different Linux distributions, with completely different people building them, all copy a tar file into the container. But, where do those tar files come from? What builds them? Clearly some other group of people figured out how to assemble these files so that we could use them in container base images right? Yes, the operating system installer people figured this out. It turns out, building disk images, Live CDs, and container base images are a similar problem.

Since Red Hat Enterprise Linux (RHEL) development happens upstream with Fedora, we can easily take a look at some public builds to understand how RHEL/UBI images are built. Let’s look at the Dockerfile used for the official Fedora base image on DockerHub. At the time of writing (Monday, June 17th 2019), the latest build was from June 9th, 2019:

FROM scratch
LABEL maintainer="Clement Verna <[email protected]>"
ENV DISTTAG=f30-updates-candidatecontainer FGC=f30-updates-candidate FBR=f30-updates-candidate
ADD fedora-30-updates-candidate-x86_64-20190609.tar.xz /
CMD ["/bin/bash"]

Notice that the Dockerfile is pulling in a tar file called fedora-30-updates-candidate-x86_64-20190609.tar.xz. If we go track this down in the public Koji instance for Fedora, we can quickly see that build 1282975 created the root filesystem for this base image:

Notice a few important things about this build:

  • It’s built for four different architectural platforms – x86, ARM, s390 and PowerPC. Every architecture needs its own container image because containers can’t abstract hardware like virtualization
  • You can see the Kickstart files – this gives you access to the exact instructions that were used to construct the root filesystem
  • You can see the build logs – this gives you some insight into what a kickstart looks like
  • The root filesystem build happens on Fedora Koji while the Dockerfile gets built on a Jenkins Instance
  • Most of the real work happens in the Koji build

Internally, Red Hat has a similar Koji instance that builds the rootfs for official Red Hat images using kickstarts. It’s obvious from the Dockerfiles published in the Red Hat Container Catalog:

Notice the first line in all of these Dockerfiles pulls from a prebuilt image. Instead of copying the rootfs into the scratch build, it pulls from a stored image. It’s a slightly different methodology, but logically equivalent. It gets the rootfs into the base image:

FROM koji/image-build

...

So, Red Hat UBI gets built quite similarly to how official ISOs or KVM images get built. At a high level the process looks like this:

  1. Kickstart a virtual machine
  2. Copy the root file system out
  3. Remove unwanted pieces like /dev, /proc, /sys, and /temp
  4. Save the resultant rootfs as a tar file and compress it
  5. Import it into a container engine
  6. Push base image to registry server back end for Red Hat Container Catalog (currently uses pulp, but moving to quay.io as a back end)

Basically the Red Hat Universal Base Image is a minimal RHEL kickstart with some stuff removed to minimize the size. Red Hat and Fedora have been building operating systems for a long time, so they have added some nice features for reverse engineering how they’re built. The beauty of Kickstart/Anaconda is that it leaves a log of what was installed right in the rootfs. See for yourself by running the following command:

podman run -it registry.access.redhat.com/ubi8/ubi cat /root/anaconda-ks.cfg

The output of the kickstart file embeds a lot of the important information you’re probably looking for when you ask for the Dockerfile. Things like:

  • Basic kickstart options
  • Language settings
  • Timezone info
  • Root password is locked (prevents Alpine Linux root password problem – aka operating system experience matters)
  • Package list
  • The contents of the /etc/yum.repos.d/ubi.repo file (aka what packages are included in UBI)

Hopefully, this breaks it down so that you can answer your own questions about how Red Hat base images are built. Clearly, you could take the kickstart provided and build a Red Hat Universal Base image from scratch. That said, it’s a lot easier to just pull it from the product page on the Red Hat Container Catalog

Find me on Twitter: @fatherlinux

Originally posted on June 17th at https://crunchtools.com/ubi-build

3 comments on “Where’s The Red Hat Universal Base Image Dockerfile?

Leave a Reply

Your email address will not be published. Required fields are marked *