I have wanted to create RedHat Enterprise Linux Docker containers for a long time, to better test some of the distro-specific tools I work on.
Prerequisites
A RedHat Enterprise Linux subscription. I got the Individual Developer Subscription. This subscription allows creating up to 16 physical or virtual instances.
I created one activation key for each RHEL version I used, so one each for RHEL 7.x, 8.x and 9.x, in the new Hybrid Cloud Console. (Services -> RedHat Enterprise Linux -> Inventory -> System Configuration -> Activation Keys.)
The “Activation Keys” page in the RedHat console also shows the “Organization ID”, I also needed that.
It might make sense to change the staleness config, so that stale VMs are deleted as soon as possible. This helps if the container quits before unregistering with RedHat. I did that in the hybrid cloud console, in Services -> Red Hat Enterprise Linux -> Inventory -> System Configuration -> Staleness and Deletion. I set all three values to the smallest possible, 1 day, 2 days and 3 days respectively.
Dockerfile
The Dockerfiles
are slightly different for RHEL 7, 8 and 9. Here I’ll
only include the one for RHEL 9.x, and link to the others.
1 | FROM redhat/ubi9:latest |
I started with the RedHat Universal Base Image.
It makes sense to make the R version a build argument, it defaults to the current release of R.
1 | # To work around a rig bug and a pak bug |
Temporary workarounds for bugs in rig and pak.
Now comes the main part of the file.
1 | RUN --mount=type=secret,id=REDHAT_ORG_RHEL9 \ |
During the build I had to register the container with
subscription-manager
because I needed to use the default RedHat
repositories to install R’s dependencies. Some of them are not available
on the default UBI repositories. This means that I had to inject two
pieces of information into the bulding container: the organization id and
the activation key.
I put all these into a single step, so there are no Docker layers that store a state that is registered to RedHat. If such a layer was included in a public Docker image, somebody could use it to run an instance against my RedHat subscription, in theory. I don’t know enough of how the subscription management work to decide if this is a real danger or not, but did not want to risk the leakage of my organization id or activation keys.
I used build secrets to
pass the org id and the activation key to the builder, because it is not
safe to use build
arguments for confidential data. REDHAT_ORG_RHEL9
and
REDHAT_ACTIVATION_KEY_RHEL9
are passed to docker build
as environment
variables and they are stored in files in the /run/secrets/
directory
in the container during build.
The next two lines install rig and then use rig to install the requested R version.
The sed
line is another temporary workaround for a bug in rig.
I preinstalled a couple of packages (git
, libgit2
, fribidi-devel
)
from the RedHat repos, so in the final container it would be possible to
install the tidyverse package without registration. I also pre-installed
glibc-langpack-en
, so the en_US.UTF-8
locale is available, this is
needed for R CMD check
.
The final lines clean up and unregister the instance.
1 | RUN curl -o /usr/local/bin/checkbashisms \ |
This last part installs the checkbashisms
script. It is currently not
available in an RHEL 9 package, as far as I can tell. I could not
find a way to skip the check that needs it during R CMD check
. (No, the
_R_CHECK_BASHISMS_=false
env var does not work.)
The image has a single R version, to keep it lean, but I can use rig
to easily add more, using one of the Posit R builds, from R 3.0.0 to the daily build of
the next R release, or the development version of R:
1 | rig add 4.3.3 |
Note that using rig needs registration via subscription-manager register
first.
I can build this image with:
1 | REDHAT_ORG_RHEL9=<org> REDHAT_ACTIVATION_KEY_RHEL9=<key> \ |
This Dockerfile
is in the r-hub/containers repo. The RHEL 7 and RHEL 8 images are very similar, and they are also in the same repository.
The built images are in the GHCR and
Docker Hub registries,
for both linux/amd64
and linux/arm64
platforms.
They are rebuilt daily.
The R-hub containers web site has the latest information about the software on the images. The rhel7, rhel8, rhel9 images are at the bottom.
GitHub Actions
I managed to use the RHEL 8 and RHEL9 images on GitHub Actions.
The RHEL 7 image is trickier because RHEL 7 cannot run Node 20.x, which is
needed for the newer versions of the Node.js actions, e.g.
actions/checkout@v4
.
The repository of the cli package has a
workflow
that runs R CMD check
both on RHEL 8 and RHEL 9, using the standard
r-lib/actions
actions.
You’ll need to add your own RedHat organization id and activation keys as repository (or organization) secrets to use this workflow.
Some more interesting parts:
1 | jobs: |
The activation keys are taken from the REDHAT_ACTIVATION_KEY_RHEL8
and
REDHAT_ACTIVATION_KEY_RHEL9
secrets.
1 | steps: |
The REDHAT_ORG
secret is used for the organization id.
1 | - name: Install R |
I used rig to install R, unless the preinstalled version is requested.
1 | - uses: r-lib/actions/setup-r-dependencies@v2 |
This is mostly as usual, but since the image does not set NOT_CRAN
,
I do it here, to make testthat::skip_on_cran()
work.
1 | - name: Unregister |
Always unregister at the end.
Improvements
It would be great to be able to use these images in R-hub but that seems difficult because of the need for the secrets.
I could use a custom GHA shell to run RHEL 7, the same way I ran s390x Linux. I am not sure how important this is, as RHEL 7 is not supported by RedHat any more.
Updates
2024-09-26: note about changing the staleness config.