From 6e76ff873d64eafbc69c4ab014a57e78135cedb9 Mon Sep 17 00:00:00 2001 From: Trey Dockendorf Date: Mon, 4 Aug 2025 18:43:57 -0400 Subject: [PATCH 1/4] Add EL9 image-builder image Possible solution for #33 Signed-off-by: Trey Dockendorf --- .github/workflows/build.yaml | 18 ++++++++++--- README.md | 3 +++ dockerfiles/dnf/Dockerfile.el9 | 47 ++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 dockerfiles/dnf/Dockerfile.el9 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 8ea81fc..786a3d5 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -45,12 +45,12 @@ jobs: id: set_tag run: | if [[ "${GITHUB_REF}" == refs/tags/* ]]; then - TAG="ghcr.io/openchami/image-build:${GITHUB_REF#refs/tags/}" + TAG="${GITHUB_REF#refs/tags/}" elif [[ "${GITHUB_REF}" == refs/pull/* ]]; then PR_NUMBER=$(echo "${GITHUB_REF}" | awk -F'/' '{print $3}') - TAG="ghcr.io/openchami/image-build:pr-${PR_NUMBER}" + TAG="pr-${PR_NUMBER}" else - TAG="ghcr.io/openchami/image-build:test" + TAG="test" fi echo "tag=${TAG}" >> $GITHUB_OUTPUT echo "Computed tag: ${TAG}" @@ -63,7 +63,17 @@ jobs: context: . file: dockerfiles/dnf/Dockerfile push: true - tags: ${{ steps.set_tag.outputs.tag }} + tags: ghcr.io/openchami/image-build:${{ steps.set_tag.outputs.tag }} + + - name: Build and push Docker image (EL9) + # Only run this step if a valid tag is computed + if: steps.set_tag.outputs.tag != '' + uses: docker/build-push-action@v3 + with: + context: . + file: dockerfiles/dnf/Dockerfile.el9 + push: true + tags: ghcr.io/openchami/image-build-el9:${{ steps.set_tag.outputs.tag }} - name: Generate release notes # Only run this step if version was computed from tag diff --git a/README.md b/README.md index acaaf9a..1a84cee 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,14 @@ To build an image using the container, the config file needs to be mapped into t podman run \ --rm \ --device /dev/fuse \ + --userns keep-id:uid=1002,gid=1002 \ -v /path/to/config.yaml:/home/builder/config.yaml \ ghcr.io/openchami/image-build:latest \ image-build --config config.yaml ``` +If you are building EL9 images, use the `ghcr.io/openchami/image-build-el9:latest` image. + If the config.yaml pushes to S3, specify the credentials by adding `-e S3_ACCESS=` and `-e S3_SECRET=` to the command above. See [S3](#s3) below. # Building Container diff --git a/dockerfiles/dnf/Dockerfile.el9 b/dockerfiles/dnf/Dockerfile.el9 new file mode 100644 index 0000000..77614a7 --- /dev/null +++ b/dockerfiles/dnf/Dockerfile.el9 @@ -0,0 +1,47 @@ +FROM docker.io/library/almalinux:9.6 + +RUN dnf clean all && \ + dnf update --nogpgcheck -y && \ + dnf install -y epel-release && \ + dnf config-manager -y --set-enabled crb + +RUN dnf install -y \ + bash \ + buildah \ + python3.11 \ + python3.11-pip \ + fuse-overlayfs \ + tar \ + squashfs-tools \ + fuse-overlayfs + +# Ensure python3 shebang uses Python 3.11 +RUN alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1 && \ + alternatives --set python3 /usr/bin/python3.11 + +COPY requirements.txt / +RUN pip3.11 install -r /requirements.txt + +COPY src/ /usr/local/bin/ +RUN chmod -R 0755 /usr/local/bin/ + +# Allow non-root to run buildah commands +RUN setcap cap_setuid=ep "$(command -v newuidmap)" && \ + setcap cap_setgid=ep "$(command -v newgidmap)" &&\ + chmod 0755 "$(command -v newuidmap)" && \ + chmod 0755 "$(command -v newgidmap)" && \ + rpm --restore shadow-utils && \ + echo "builder:2000:50000" > /etc/subuid && \ + echo "builder:2000:50000" > /etc/subgid + +# Create local user for rootless image builds +RUN useradd --uid 1002 builder && \ + chown -R builder /home/builder + +# Make builder the default user when running container +USER builder +WORKDIR /home/builder + +ENV BUILDAH_ISOLATION=chroot + +ENTRYPOINT ["/usr/bin/buildah", "unshare"] From ea081c0b5a70eacee852fa8d9754d21d30e8d792 Mon Sep 17 00:00:00 2001 From: Trey Dockendorf Date: Fri, 8 Aug 2025 14:23:28 -0400 Subject: [PATCH 2/4] Support 'args' for 'cmd' Signed-off-by: Trey Dockendorf --- README.md | 3 +++ src/installer.py | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a84cee..77bfbe7 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,9 @@ packages: # control command verbosity. By default, it is 'INFO'. cmds: - cmd: 'echo hello' +# 'cmd' also supports 'args' that are passed to 'buildah run' + - cmd: 'id user' + args: ['--volume', '/var/lib/sss:/var/lib/sss:z'] # OpenSCAP options to use with scap_benchmark or oval_eval. Each OpenSCAP # command gets passed to the shell. By default, the results from OpenSCAP will be saved diff --git a/src/installer.py b/src/installer.py index 5b4d766..83beb2a 100644 --- a/src/installer.py +++ b/src/installer.py @@ -215,7 +215,10 @@ def install_base_commands(self, commands): logging.info(f"COMMANDS: running these commands in {self.cname}") for c in commands: logging.info(c['cmd']) - args = [self.cname, '--', 'bash', '-c', c['cmd']] + args = [] + if 'args' in c: + args.extend(c['args']) + args.extend([self.cname, '--', 'bash', '-c', c['cmd']]) if 'loglevel' in c: if c['loglevel'].upper() == "INFO": loglevel = logging.info @@ -239,4 +242,4 @@ def install_base_copyfiles(self, copyfiles): args.extend(o.split()) logging.info(f['src'] + ' -> ' + f['dest']) args += [ self.cname, f['src'], f['dest'] ] - out=cmd(["buildah","copy"] + args) \ No newline at end of file + out=cmd(["buildah","copy"] + args) From 427accbddb5a93ebfb754ea2187926f47aef4a7c Mon Sep 17 00:00:00 2001 From: Trey Dockendorf Date: Mon, 11 Aug 2025 12:56:33 -0400 Subject: [PATCH 3/4] Rename 'args' to 'buildah_extra_args' Signed-off-by: Trey Dockendorf --- README.md | 4 ++-- src/installer.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 77bfbe7..e6a0e00 100644 --- a/README.md +++ b/README.md @@ -140,9 +140,9 @@ packages: # control command verbosity. By default, it is 'INFO'. cmds: - cmd: 'echo hello' -# 'cmd' also supports 'args' that are passed to 'buildah run' +# 'cmd' also supports 'buildah_extra_args' that are passed to 'buildah run' - cmd: 'id user' - args: ['--volume', '/var/lib/sss:/var/lib/sss:z'] + buildah_extra_args: ['--volume', '/var/lib/sss:/var/lib/sss:z'] # OpenSCAP options to use with scap_benchmark or oval_eval. Each OpenSCAP # command gets passed to the shell. By default, the results from OpenSCAP will be saved diff --git a/src/installer.py b/src/installer.py index 83beb2a..524389e 100644 --- a/src/installer.py +++ b/src/installer.py @@ -215,10 +215,10 @@ def install_base_commands(self, commands): logging.info(f"COMMANDS: running these commands in {self.cname}") for c in commands: logging.info(c['cmd']) - args = [] - if 'args' in c: - args.extend(c['args']) - args.extend([self.cname, '--', 'bash', '-c', c['cmd']]) + build_cmd = ["buildah","run"] + if 'buildah_extra_args' in c: + build_cmd.extend(c['buildah_extra_args']) + args = [self.cname, '--', 'bash', '-c', c['cmd']] if 'loglevel' in c: if c['loglevel'].upper() == "INFO": loglevel = logging.info @@ -228,7 +228,7 @@ def install_base_commands(self, commands): loglevel = logging.error else: loglevel = logging.error - out = cmd(["buildah","run"] + args, stderr_handler=loglevel) + out = cmd(build_cmd + args, stderr_handler=loglevel) def install_base_copyfiles(self, copyfiles): if len(copyfiles) == 0: From b7b58fdc529c7558b96cc4c82bbbded19bbea849 Mon Sep 17 00:00:00 2001 From: Trey Dockendorf Date: Sun, 17 Aug 2025 15:10:41 -0400 Subject: [PATCH 4/4] Ensure tags all have same SHA image Signed-off-by: Trey Dockendorf --- src/publish.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/publish.py b/src/publish.py index 8d59997..3c862e1 100644 --- a/src/publish.py +++ b/src/publish.py @@ -82,14 +82,16 @@ def publish(cname, args): registry_opts = args['registry_opts_push'] publish_dest = args['publish_registry'] print("Publishing to registry at " + publish_dest) + image_name = layer_name+':'+publish_tags[0] + # Add labels if they exist + if labels: + label_args = [] + for key, value in labels.items(): + label_args.extend(['--label', f'{key}={value}']) + cmd(["buildah", "config"] + label_args + [cname], stderr_handler=logging.warn) + cmd(["buildah", "commit", cname, image_name], stderr_handler=logging.warn) for tag in publish_tags: - # Add labels if they exist - if labels: - label_args = [] - for key, value in labels.items(): - label_args.extend(['--label', f'{key}={value}']) - cmd(["buildah", "config"] + label_args + [cname], stderr_handler=logging.warn) - cmd(["buildah", "commit", cname, layer_name+':'+tag], stderr_handler=logging.warn) + cmd(["buildah", "tag", image_name, layer_name+':'+tag], stderr_handler=logging.warn) registry_push(layer_name, registry_opts, tag, publish_dest) # Clean up