1
0
mirror of https://github.com/coreos/fedora-coreos-config.git synced 2026-02-06 03:46:24 +01:00

Containerfile: run postprocess scripts in build stage

To have optimal layers, let's run our postprocess scripts in the build
stage _before_ chunking occurs. That way, the chunking operates on the
final flattened tree and we don't carry around a fat layer at the end
with lots of whiteouts.

For example, we nuke documentation as a postprocess script, which meant
that we were actually still carrying all the docs in the lower layers.
(On that topic, we should switch to `documentation: false` really.) But
also e.g. we recompile the SELinux policy, edit a bunch of files, etc.

This also fixes a bug in 29ac01e6 ("Containerfile: include rechunking
step"), in which I forgot to remove a `COPY` statement that copies the
whole rootfs on top of the rechunked image. Ouch.

This uses bwrap to run the scripts. Another way to do this of course
is to go back to what we had before 29ac01e6 (where we copied the
rootfs from the previous stage into a scratch rootfs and then ran the
postprocess scripts) and _then_ rechunk. The huge advantage doing it the
bwrap way is that it avoids that expensive full rootfs copy.

With this change, the image size in the container-native and non-native
paths are comparable.
This commit is contained in:
Jonathan Lebon
2025-07-14 18:42:42 -04:00
parent 401456b003
commit 23a549ad39
2 changed files with 21 additions and 11 deletions

View File

@@ -41,14 +41,6 @@ RUN --mount=type=bind,from=builder,target=/var/tmp \
--mount=type=bind,target=/run/src,rw \
rm /run/src/out.ociarchive
COPY --from=builder /target-rootfs/ /
RUN <<EOF
set -xeuo pipefail
for script in /usr/libexec/coreos-postprocess-*; do
$script; rm $script
done
EOF
LABEL containers.bootc=1
LABEL ostree.bootable=1
LABEL org.opencontainers.image.version=$VERSION

View File

@@ -46,7 +46,7 @@ def main():
if version != "":
inject_version_info(target_rootfs, manifest['mutate-os-release'], version)
inject_postprocess_scripts(target_rootfs, manifest)
run_postprocess_scripts(target_rootfs, manifest)
def get_treefile(manifest_path):
@@ -120,15 +120,33 @@ def inject_passwd_group(parent_dir):
shutil.copy(os.path.join(parent_dir, 'group'), dst_group)
def inject_postprocess_scripts(rootfs, manifest):
def run_postprocess_scripts(rootfs, manifest):
# since we have the derive-only manifest handy, just inject a script now
# that we can execute in the second stage. we could of course use e.g.
# bwrap to run those now, but... it's just cleaner to use multi-stage build
# semantics
for i, script in enumerate(manifest.get('postprocess', [])):
with open(os.path.join(rootfs, f'usr/libexec/coreos-postprocess-{i}'), mode='w') as f:
name = f'usr/libexec/coreos-postprocess-{i}'
with open(os.path.join(rootfs, name), mode='w') as f:
os.fchmod(f.fileno(), 0o755)
f.write(script)
bwrap(rootfs, [f'/{name}'])
os.unlink(os.path.join(rootfs, name))
# Could upstream this as e.g. `bootc-base-imagectl runroot /rootfs <cmd>` maybe?
# But we'd need to carry it anyway at least for RHCOS 9.6.
def bwrap(rootfs, args):
subprocess.check_call(['bwrap',
'--dev', '/dev', '--proc', '/proc',
'--dir', '/tmp', '--dir', '/var', '--tmpfs', '/run',
'--bind', '/run/.containerenv', '/run/.containerenv',
'--bind', f'{rootfs}/usr', '/usr',
'--bind', f'{rootfs}/etc', '/etc',
'--symlink', '/usr/lib', '/lib',
'--symlink', '/usr/lib64', '/lib64',
'--symlink', '/usr/bin', '/bin',
'--symlink', '/usr/sbin', '/sbin', '--'] + args)
def get_locked_nevras():