Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .github/workflows/build_container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
# Reusable workflow: build one container image from build/Dockerfiles/ and
# optionally push it to ghcr.io. Called by build_containers.yml (manual,
# single image) and containers.yml (PR validation + push/schedule publish).
name: 'Reusable: build container image'

on:
workflow_call:
inputs:
dockerfile:
description: "Dockerfile filename under build/Dockerfiles/"
required: true
type: string
image_name:
description: "Image name to publish under ghcr.io/<owner>/"
required: true
type: string
ruby_version:
description: "Default Ruby version build arg (ignored by Beaker images)"
required: false
type: string
default: "3.2"
ref:
description: "Branch, tag, or SHA to build from"
required: false
type: string
default: ""
push:
description: "Push the image to ghcr.io (false = build only, for PRs)"
required: false
type: boolean
default: false
extra_tag:
description: "Optional additional tag (in addition to latest + date)"
required: false
type: string
default: ""

permissions:
contents: read
packages: write

jobs:
build:
name: "${{ inputs.image_name }}"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.ref }}

- name: Compute image tags
id: meta
env:
IMAGE: "ghcr.io/${{ github.repository_owner }}/${{ inputs.image_name }}"
EXTRA_TAG: ${{ inputs.extra_tag }}
run: |
# Date-based tag (UTC) so it is clear when an image was built.
date_tag="$(date -u +%Y%m%d)"
tags="${IMAGE}:${date_tag},${IMAGE}:latest"
if [ -n "$EXTRA_TAG" ]; then
tags="${tags},${IMAGE}:${EXTRA_TAG}"
fi
echo "tags=${tags}" >> "$GITHUB_OUTPUT"
echo "Image tags: ${tags}"

- name: Log in to GitHub Container Registry
if: ${{ inputs.push }}
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build${{ inputs.push && ' and push' || ' (no push)' }}
env:
DOCKERFILE: ${{ inputs.dockerfile }}
RUBY_VERSION: ${{ inputs.ruby_version }}
TAGS: ${{ steps.meta.outputs.tags }}
PUSH: ${{ inputs.push }}
run: |
cd build/Dockerfiles
IFS=',' read -ra image_tags <<< "$TAGS"
tag_args=()
for t in "${image_tags[@]}"; do
tag_args+=( -t "$t" )
done
docker build --pull \
--build-arg ruby_version="$RUBY_VERSION" \
-f "$DOCKERFILE" \
"${tag_args[@]}" .
if [ "$PUSH" = "true" ]; then
for t in "${image_tags[@]}"; do
docker push "$t"
done
fi
60 changes: 24 additions & 36 deletions .github/workflows/build_containers.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
---
# Manual, single-image build + publish. For ad-hoc rebuilds with a specific
# Ruby version, git ref, or extra tag. The full set of images is built
# automatically by containers.yml.
name: 'RELENG: Build + publish SIMP container image'

on:
workflow_dispatch:
inputs:
ruby_version:
description: "Ruby version build arg"
required: true
type: choice
options:
- "2.7"
- "3.1"
- "3.3"
dockerfile:
description: >
Filename of Dockerfile to build (under build/Dockerfiles/).
Expand All @@ -20,12 +15,20 @@ on:
image_name:
description: >
Image name to publish under ghcr.io/<org>/.
Example: simp-build-el9
Example: simp-el9-build
required: true
container_tag:
description: "Image tag. Example: latest, 20250427"
ruby_version:
description: "Default Ruby version build arg (3.2 = OpenVox 8, 4.0 = OpenVox 9)"
required: true
default: latest
type: choice
default: "3.2"
options:
- "3.2"
- "4.0"
container_tag:
description: "Optional extra tag (latest + a YYYYMMDD date tag are always applied)"
required: false
default: ""
git_ref:
description: "Branch, tag, or SHA to build from"
required: true
Expand All @@ -36,27 +39,12 @@ permissions:
packages: write

jobs:
build_container:
name: Build and push container
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.git_ref }}

- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
env:
RUBY_VERSION: ${{ inputs.ruby_version }}
DOCKERFILE: ${{ inputs.dockerfile }}
IMAGE_REF: ghcr.io/${{ github.repository_owner }}/${{ inputs.image_name }}:${{ inputs.container_tag }}
run: |
cd build/Dockerfiles
docker build --build-arg ruby_version="$RUBY_VERSION" -f "$DOCKERFILE" -t "$IMAGE_REF" .
docker push "$IMAGE_REF"
build:
uses: ./.github/workflows/build_container.yml
with:
dockerfile: ${{ inputs.dockerfile }}
image_name: ${{ inputs.image_name }}
ruby_version: ${{ inputs.ruby_version }}
ref: ${{ inputs.git_ref }}
push: true
extra_tag: ${{ inputs.container_tag }}
68 changes: 68 additions & 0 deletions .github/workflows/containers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
# Build all container images from build/Dockerfiles/.
#
# - Pull requests touching the Dockerfiles build every image WITHOUT pushing,
# to catch breakage before merge (the scripts are fail-fast, so a broken
# build fails the check instead of shipping a broken image).
# - Pushes to master touching the Dockerfiles, the weekly schedule, and manual
# runs build AND push to ghcr.io. Images are tagged `latest` and `YYYYMMDD`.
#
# The weekly schedule keeps the images current with upstream base/package
# updates even when the Dockerfiles themselves have not changed.
name: Containers

# On PRs the images are built but NOT published (push: false below), so the
# run title reflects build-only vs. build + publish per trigger.
run-name: >-
Containers: ${{ github.event_name == 'pull_request' && 'build (no publish)' || 'build + publish' }}

on:
pull_request:
paths:
- 'build/Dockerfiles/**'
- '.github/workflows/containers.yml'
- '.github/workflows/build_container.yml'
push:
branches:
- master
paths:
- 'build/Dockerfiles/**'
- '.github/workflows/containers.yml'
- '.github/workflows/build_container.yml'
schedule:
# Weekly, Mondays 06:17 UTC
- cron: '17 6 * * 1'
workflow_dispatch:

permissions:
contents: read
packages: write

concurrency:
group: containers-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- dockerfile: SIMP_EL8_Beaker.dockerfile
image_name: simp-el8-beaker
- dockerfile: SIMP_EL9_Beaker.dockerfile
image_name: simp-el9-beaker
- dockerfile: SIMP_EL10_Beaker.dockerfile
image_name: simp-el10-beaker
- dockerfile: SIMP_EL8_Build.dockerfile
image_name: simp-el8-build
- dockerfile: SIMP_EL9_Build.dockerfile
image_name: simp-el9-build
- dockerfile: SIMP_EL10_Build.dockerfile
image_name: simp-el10-build
uses: ./.github/workflows/build_container.yml
with:
dockerfile: ${{ matrix.dockerfile }}
image_name: ${{ matrix.image_name }}
# Build only on PRs; build + push everywhere else.
push: ${{ github.event_name != 'pull_request' }}
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ The Rakefile also loads `simp-rake-helpers` (`Simp::Rake::Build::Helpers`) which
### CI (`.github/workflows/`)

- **`pr_checks.yml`** — runs on PRs: YAML lint, RPM file checks (`rake check:dot_underscore`, `rake check:test_file`), metadata lint, and `pdk build`; sets `SIMP_RPM_dist=.el7`
- **`build_containers.yml`** — manual workflow to build and push Docker build/test images to a registry
- **`containers.yml`** — builds all `build/Dockerfiles/` images. On PRs touching the Dockerfiles it builds every image without pushing (pre-merge validation); on push to master (path-filtered), a weekly schedule, and manual dispatch it builds and pushes to `ghcr.io` tagged `latest` + `YYYYMMDD`
- **`build_container.yml`** — reusable (`workflow_call`) workflow that builds/pushes a single image; called by `containers.yml` and `build_containers.yml`
- **`build_containers.yml`** — manual (`workflow_dispatch`) single-image build + publish for ad-hoc rebuilds (specific Ruby version, git ref, or extra tag)

### Gemfile Notes

Expand Down
52 changes: 41 additions & 11 deletions build/Dockerfiles/README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,62 @@
# SIMP Dockerfiles

These files are meant to assist with various SIMP build activities
These files assist with various SIMP build and test activities. There are two
families of image, and they run **different** sets of scripts:

Please read each file for details as to the purpose and usage of the file
| Image family | Dockerfiles | Purpose |
|---|---|---|
| **Beaker SUT** | `SIMP_EL*_Beaker.dockerfile` | Minimal, systemd-enabled containers used by Beaker as acceptance-test nodes (systems under test). They do **not** contain Ruby or an agent — Beaker installs the OpenVox/Puppet agent at test time. Published as `ghcr.io/simp/simp-el<N>-beaker`. |
| **ISO build** | `SIMP_EL*_Build.dockerfile` | Full dev/build toolchain (mise-managed Ruby, rpmbuild, ISO tooling) for building SIMP ISOs and RPMs as the unprivileged `build_user`. |

## Helper Scripts

There are helper scripts in the `scripts` directory that you may find useful if
you are setting up your own development system from scratch.
Scripts live under `scripts/`. `scripts/common/` is shared; `scripts/el8/`,
`scripts/el9/`, and `scripts/el10/` hold per-release variants. Each Dockerfile
`ADD`s the common scripts plus the matching per-release directory, so a
per-release script of the same name overrides the common one.

Every script carries a header comment describing its purpose and which image
family uses it. In summary:

| Script | Purpose | Used by |
|---|---|---|
| `common/minimize_package_installs.sh` | Configure dnf for a minimal footprint (no docs/weak deps, single langpack); refresh TLS trust + curl | both |
| `common/package_cleanup.sh` | Clear dnf caches and delete stray doc files to shrink the image | both |
| `el*/00_system_prep.sh` | Install dnf config-manager, bake in minimization settings, rebuild rpmdb, install yum-utils | both |
| `common/beaker_packages.sh` | Install the baseline userland a Beaker node needs | Beaker SUT |
| `common/container_safe_services.sh` | Install a systemd unit that strips container-incompatible directives from unit files | Beaker SUT |
| `el*/00_setup_vault.sh` | Pin repos to AlmaLinux Vault at the oldest point release for a stable library floor | ISO build |
| `el*/05_selinux.sh` | Downgrade to the vault baseline and install SELinux policy/tooling | ISO build |
| `el*/10_dev_packages.sh` | Install the full ISO/RPM build toolchain | ISO build |
| `common/user.sh` | Create the `build_user` build account | ISO build |
| `el*/install_mise.sh` | Install [mise](https://mise.jdx.dev) system-wide (per-release repo setup) | ISO build |
| `common/mise.sh` | Provision Ruby (3.2 + 4.0) for `build_user` via mise and install bundler | ISO build |
| `common/prime_ruby.sh` | Clone simp-core and `bundle install` to warm the gem cache | ISO build |

All scripts use `set -euo pipefail` so a failing step aborts the image build
instead of silently producing a broken image.

## Building

`buildah build -t <friendly image name> -f <Dockerfile> .`

### Build args

The `SIMP_*_Build.dockerfile` builds support a `--build-arg` to set the initial
`ruby_version` of RVM:
The `SIMP_*_Build.dockerfile` builds support a `--build-arg` to set the default
`ruby_version` that mise activates. Both Ruby **3.2** and **4.0** are always
installed; the build arg only selects which is the global default:

```
buildah build -t simp_build_centos8_ruby3_1 --build-arg ruby_version=3.1 -f SIMP_EL8_Build.dockerfile
buildah build -t simp_build_el8_ruby40 --build-arg ruby_version=4.0 -f SIMP_EL8_Build.dockerfile
```

The current default for this argument is `2.7` (to support Puppet 7)
The default for this argument is `3.2`:

- Ruby **3.2** → OpenVox 8 (current)
- Ruby **4.0** → OpenVox 9 (upcoming)

## Pushing

If you build using `buildah`, you'll need to make sure you push to Dockerhub
using `podman push --format=docker ...`

Images are published to the GitHub Container Registry (`ghcr.io`). If you build
with `buildah`, push using `podman push --format=docker ...`. CI publishing is
handled by `.github/workflows/build_containers.yml`.
5 changes: 3 additions & 2 deletions build/Dockerfiles/SIMP_EL10_Build.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

FROM almalinux:10.0
ENV container docker
ARG ruby_version=3.3
ARG ruby_version=3.2

RUN mkdir /root/build_scripts
ADD scripts/common/* /root/build_scripts/
Expand All @@ -40,7 +40,8 @@ RUN ./minimize_package_installs.sh
RUN ./05_selinux.sh
RUN ./10_dev_packages.sh
RUN ./user.sh
RUN ./rvm.sh build_user "$ruby_version"
RUN ./install_mise.sh
RUN ./mise.sh build_user "$ruby_version"
RUN ./prime_ruby.sh
RUN ./package_cleanup.sh
RUN rm -rf /root/build_scripts
Expand Down
5 changes: 3 additions & 2 deletions build/Dockerfiles/SIMP_EL8_Build.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

FROM almalinux:8.4
ENV container docker
ARG ruby_version=2.7
ARG ruby_version=3.2

RUN mkdir /root/build_scripts
ADD scripts/common/* /root/build_scripts/
Expand All @@ -40,7 +40,8 @@ RUN ./minimize_package_installs.sh
RUN ./05_selinux.sh
RUN ./10_dev_packages.sh
RUN ./user.sh
RUN ./rvm.sh build_user "$ruby_version"
RUN ./install_mise.sh
RUN ./mise.sh build_user "$ruby_version"
RUN ./prime_ruby.sh
RUN ./package_cleanup.sh
RUN rm -rf /root/build_scripts
Expand Down
5 changes: 3 additions & 2 deletions build/Dockerfiles/SIMP_EL9_Build.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

FROM almalinux:9.0
ENV container docker
ARG ruby_version=3.1
ARG ruby_version=3.2

RUN mkdir /root/build_scripts
ADD scripts/common/* /root/build_scripts/
Expand All @@ -40,7 +40,8 @@ RUN ./minimize_package_installs.sh
RUN ./05_selinux.sh
RUN ./10_dev_packages.sh
RUN ./user.sh
RUN ./rvm.sh build_user "$ruby_version"
RUN ./install_mise.sh
RUN ./mise.sh build_user "$ruby_version"
RUN ./prime_ruby.sh
RUN ./package_cleanup.sh
RUN rm -rf /root/build_scripts
Expand Down
Loading