diff --git a/.github/workflows/build-base-images.yml b/.github/workflows/build-base-images.yml index 75d959b5d..953ca29b4 100644 --- a/.github/workflows/build-base-images.yml +++ b/.github/workflows/build-base-images.yml @@ -20,6 +20,9 @@ jobs: - debian-11 - debian-12 - debian-13 + - rhel-8 + - rhel-9 + - rhel-10 steps: - name: Checkout repository uses: actions/checkout@v6 diff --git a/build-in-container-inner.sh b/build-in-container-inner.sh index c4f250bda..455bb184b 100755 --- a/build-in-container-inner.sh +++ b/build-in-container-inner.sh @@ -31,9 +31,12 @@ for repo in $repos; do # regardless of the host directory layout. # Exclude acceptance test workdirs — they contain broken symlinks left # over from previous test runs and are not needed for building. + # Also skip node_modules/vendor for hub builds. if [ -d "$src" ] || [ -L "$src" ]; then echo "Syncing $repo..." - sudo rsync -aL --exclude='config.cache' --exclude='workdir' --chown="$(id -u):$(id -g)" "$src/" "$BASEDIR/$repo/" + sudo rsync -aL --exclude='config.cache' --exclude='workdir' \ + --exclude='node_modules' --exclude='vendor' \ + --chown="$(id -u):$(id -g)" "$src/" "$BASEDIR/$repo/" else echo "ERROR: Required repository $repo not found" >&2 exit 1 diff --git a/build-in-container.md b/build-in-container.md index 34da135cf..5aa8e0e2e 100644 --- a/build-in-container.md +++ b/build-in-container.md @@ -58,14 +58,22 @@ None of the above arguments are required for `--update`. ## Supported platforms -| Name | Base image | -| ----------- | -------------- | -| `ubuntu-20` | `ubuntu:20.04` | -| `ubuntu-22` | `ubuntu:22.04` | -| `ubuntu-24` | `ubuntu:24.04` | -| `debian-11` | `debian:11` | -| `debian-12` | `debian:12` | -| `debian-13` | `debian:13` | +| Name | Base image | +| ----------- | -------------------------- | +| `ubuntu-20` | `ubuntu:20.04` | +| `ubuntu-22` | `ubuntu:22.04` | +| `ubuntu-24` | `ubuntu:24.04` | +| `debian-11` | `debian:11` | +| `debian-12` | `debian:12` | +| `debian-13` | `debian:13` | +| `rhel-8` | `rockylinux/rockylinux:8` | +| `rhel-9` | `rockylinux/rockylinux:9` | +| `rhel-10` | `rockylinux/rockylinux:10` | + +RHEL packages are built on Rocky Linux base images. The build scripts detect +`OS=rhel` from `/etc/redhat-release` (which reports `Rocky Linux release ...`), +so the produced `.rpm`s are ordinary Red Hat / rpm packages. AlmaLinux is _not_ +recognized by `build-scripts/detect-environment`, which is why Rocky is used. Adding a new Debian/Ubuntu platform requires a new entry in `platforms.json` and adding the platform name to the matrix in @@ -85,8 +93,17 @@ The new entry in `platforms.json` needs: --platform ` and it will fetch the current digest from Docker Hub and write it into `platforms.json`. -Adding a non-debian based platform (e.g., -RHEL/CentOS) requires a new `container/Dockerfile.rhel` plus platform entries. +Adding another RHEL-family platform (a new Rocky/RHEL major version) works the +same way: add a `platforms.json` entry with `"dockerfile": "Dockerfile.rhel"` +and a matrix entry, then set any per-version `extra_build_args` — `CRB_REPO` +(`powertools` on 8, `crb` on 9+), `PHP_MODULE_STREAM` (`remi-8.3` where the +distro's default PHP is older than 8.3; RHEL 10 already ships 8.3), and +`EXTRA_PKGS` for version-specific packages. Note that `--update-sha` also works +for the namespaced `rockylinux/rockylinux` base images, not just official +Docker Hub library images. + +Adding an entirely different, non-RHEL/non-Debian platform family (e.g. SUSE) +would require a new `container/Dockerfile.` plus platform entries. ## How it works @@ -100,8 +117,10 @@ The system has three components: source repos from the read-only mount, then calls the existing build scripts in order. -3. **`container/Dockerfile.debian`** -- parameterized Dockerfile shared by all - Debian/Ubuntu platforms via a `BASE_IMAGE` build arg. +3. **`container/Dockerfile.debian`** and **`container/Dockerfile.rhel`** -- + parameterized Dockerfiles shared across platforms of the same family via a + `BASE_IMAGE` build arg (plus per-platform `extra_build_args` in + `platforms.json`, e.g. the CRB repo name and PHP module stream for RHEL). ### Container mounts diff --git a/build-in-container.py b/build-in-container.py index 52e063f04..64b140dee 100755 --- a/build-in-container.py +++ b/build-in-container.py @@ -195,9 +195,12 @@ def update_platform_versions(platform_name=None): def latest_base_image_digest(base_image): """Fetch current manifest digest from Docker Hub for a base image.""" # Docker Hub's v2 API path requires a namespace. Official images (ubuntu, - # debian, ...) live under "library/". + # debian, ...) carry no namespace and live under "library/"; images that + # already have an "org/name" namespace (e.g. rockylinux/rockylinux) are + # used as-is. repo, tag = base_image.rsplit(":", 1) - repo = f"library/{repo}" + if "/" not in repo: + repo = f"library/{repo}" # The v2 API requires a bearer token even for anonymous public pulls. token_url = ( diff --git a/container/Dockerfile.rhel b/container/Dockerfile.rhel new file mode 100644 index 000000000..3a2bd265a --- /dev/null +++ b/container/Dockerfile.rhel @@ -0,0 +1,64 @@ +ARG BASE_IMAGE=rockylinux/rockylinux:9 +FROM ${BASE_IMAGE} + +# allow older packages when the newest has unmet deps (as build hosts do). +RUN echo "best=False" >> /etc/dnf/dnf.conf + +# Enable CRB (crb on 9+, powertools on 8) + EPEL for the -devel/build packages. +ARG CRB_REPO=crb +RUN dnf install -y dnf-plugins-core epel-release \ + && dnf config-manager --set-enabled ${CRB_REPO} \ + && dnf clean all + +# Deps like zlib build without full debug symbols; disable debuginfo extraction +# so rpm doesn't abort with "No debugging symbols". We don't ship debuginfo here. +RUN echo '%debug_package %{nil}' > /etc/rpm/macros.cfengine-nodebug + +# Build toolchain (see redhat section of ci/cfengine-build-host-setup.cf). +# "Development Tools" provides gcc, make, autotools, rpm-build, core perl, etc. +RUN dnf groupinstall -y "Development Tools" \ + && dnf install -y \ + gcc-c++ pam-devel ncurses ncurses-devel expat expat-devel gettext \ + rpm-build-libs selinux-policy selinux-policy-devel \ + pkgconf pkgconf-pkg-config \ + perl perl-Module-Load-Conditional perl-ExtUtils-MakeMaker perl-IPC-Cmd \ + perl-IO-Compress \ + python3 python3-pip python3-devel \ + git rsync wget which psmisc unzip diffutils file sudo \ + && dnf clean all + +# Hub tools: Node 20 (system nodejs too old for the node: protocol) + less. +RUN curl -fsSL https://rpm.nodesource.com/setup_20.x | bash - \ + && dnf install -y nodejs \ + && dnf clean all +RUN npm install -g less + +ARG PHP_MODULE_STREAM="" +RUN if [ -n "${PHP_MODULE_STREAM}" ]; then \ + dnf install -y https://rpms.remirepo.net/enterprise/remi-release-$(rpm -E %rhel).rpm \ + && dnf module reset -y php \ + && dnf module enable -y php:${PHP_MODULE_STREAM}; \ + fi \ + && dnf install -y php-cli php-xml php-mbstring \ + && (dnf install -y php-json || true) \ + && (dnf install -y php-zip || dnf install -y php-pecl-zip || true) \ + && dnf clean all +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer.phar + +# Rust + protobuf for the cargo-based leech2 dep (prebuilt tarballs, shared with Debian). +COPY --from=ci linux-install-protobuf.sh linux-install-rust.sh /tmp/ +RUN /tmp/linux-install-protobuf.sh +RUN /tmp/linux-install-rust.sh + +# Per-version extras (rhel-8: cfbs py3_shebang_fix macro; rhel-10: patch). +RUN if [ -n "${EXTRA_PKGS}" ]; then dnf install -y ${EXTRA_PKGS} && dnf clean all; fi + +# Build user with passwordless sudo (needed by install-dependencies, package, etc.) +RUN useradd -m -s /bin/bash builder \ + && echo "builder ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/builder + +USER builder +WORKDIR /home/builder + +# Pre-create so a volume mounted here is owned by builder, not root. +RUN mkdir -p /home/builder/build diff --git a/platforms.json b/platforms.json index 40b869d7d..e3df87804 100644 --- a/platforms.json +++ b/platforms.json @@ -43,5 +43,37 @@ "base_image": "debian:13", "base_image_sha": "sha256:d07d1b51c39f51188e60be9b64e6bf769fa94e187f092bc32b91305cfa34ba5a", "dockerfile": "Dockerfile.debian" + }, + "rhel-8": { + "image_name": "cfengine-builder-rhel-8", + "image_version": "latest", + "base_image": "rockylinux/rockylinux:8", + "base_image_sha": "sha256:e8a49c5403b687db05d4d67333fa45808fbe74f36e683cec7abb1f7d0f2338c6", + "dockerfile": "Dockerfile.rhel", + "extra_build_args": { + "CRB_REPO": "powertools", + "PHP_MODULE_STREAM": "remi-8.3", + "EXTRA_PKGS": "python3-rpm-macros platform-python-devel" + } + }, + "rhel-9": { + "image_name": "cfengine-builder-rhel-9", + "image_version": "latest", + "base_image": "rockylinux/rockylinux:9", + "base_image_sha": "sha256:8101994123cf3d0a8fee517bee7f39e555c7d92bd2d9eb3303cc988a0eeed00f", + "dockerfile": "Dockerfile.rhel", + "extra_build_args": { + "PHP_MODULE_STREAM": "remi-8.3" + } + }, + "rhel-10": { + "image_name": "cfengine-builder-rhel-10", + "image_version": "latest", + "base_image": "rockylinux/rockylinux:10", + "base_image_sha": "sha256:827d37bc128288ccf160ee318bb3cb92d591164cb217e92f8bc61e3982ae1834", + "dockerfile": "Dockerfile.rhel", + "extra_build_args": { + "EXTRA_PKGS": "patch" + } } }