Files
secureblue/scripts
Arcitec e8b5be6e83 fix!: optimize container layers and reduce image size
Every individual RUN, COPY and ADD action creates an extra container layer, so there was plenty of room for improvement in our Containerfile.

This optimization gets rid of 4 useless layers from our final container image, and shrinks the final OCI download size as follows:

- Removing the "mkdir /tmp/scripts" layer. It's not necessary to manually create the target directory for the container copy action.

- Removing the manual "chmod +x" for the scripts, and putting that step inside "build.sh" instead.

- Removing the manual copying of "build.sh", by instead placing it at "scripts/build.sh" so that it's automatically copied together with all the other scripts in one layer instead.

- Removing the separate "chmod +x build.sh && run build script" step by merging it with the "cleanup temp files and then finalize the container" step, so that we don't create a pointless extra filesystem layer just for the build.sh script execution.

These changes also reduce the size of the final image, because we're cleaning up the image in the exact same step that we run the "build.sh". If we didn't combine these steps, we'd still be keeping a useless extra layer with all the /tmp/ and /var/ junk files that were left over after the build.

Most seriously, the "/var/cache" folder contained copies of ALL RPM FILES that build.sh installed via "rpm-ostree install". This meant that we were generating a very big layer with a lot of junk data that shipped in the final image.

Our build now only generates 7 layers (instead of 11), and users will have a much smaller OCI download since we aren't shipping the cached RPM "build leftovers" or temp files via useless extra layers anymore.
2023-05-20 08:07:46 +00:00
..

Custom scripts

You can add custom scripts to this directory and declare them to be run at build time in the scripts: section of recipe.yml. Custom scripts can be run at either the pre: execution phase right after the custom repositories are added, or at the post: phase after all of the automatic build steps.

Your scripts will be given exactly one argument when they are executed, which specifies its precise execution phase (pre or post). The primary purpose of this argument is to streamline the reuse of scripts for multiple stages. This argument is provided for both manually declared scripts and scripts ran by autorun.sh.

Creating a script

Look at example.sh for an example shell script. You can rename and copy the file for your own purposes. In order for the script to be executed, either move it to scripts/pre/ or scripts/post/ (if using autorun.sh) or declare it in the recipe.yml.

All commands from RPMs you've declared in the recipe.yml should be available when running scripts at the post execution phase.

When creating a script, please make sure

  • ...its filename ends with .sh.
    • This follows convention for (especially bash) shell scripts.
    • autorun.sh only executes files that match *.sh.
  • ...it starts with a shebang like #!/usr/bin/env bash.
    • This ensures the script is ran with the correct interpreter / shell.
  • ...it contains the command set -oue pipefail near the start.
    • This will make the image build fail if your script fails. If you do not care if your script works or not, you can omit this line.

autorun.sh

autorun.sh is a script that automatically runs all scripts in the folders scripts/pre/ and scripts/post/ at the correct execution phases. It is enabled by default, but you can disable it by removing it from recipe.yml. Manually listed scripts can be combined with autorun.sh.

There are a few rules, which aim to simplify your script management:

  • autorun.sh will only execute scripts at the FIRST level within the directory, which means that anything stored in e.g. scripts/pre/deeperfolder/ will NOT execute. This is intentional, so that you can store libraries and helper scripts within subdirectories.
  • You script directories and the scripts within them can be symlinks, to allow easy reuse of scripts. For example, if you want the same scripts to execute during both the pre and post stages, you could simply symlink individual scripts or the entire pre and post directories to each other. However, remember to only use RELATIVE symlinks, to ensure that the links work properly. For example, ln -s ../pre/foo.sh scripts/post/foo.sh.
  • All scripts execute in a numerically and alphabetically sorted order, which allows you to easily control the execution order of your scripts. If it's important that they execute in a specific order, then you should give them appropriate names. For example, 05-foo.s would always execute before another script named 99-bar.sh. It's recommended to use zero-padded, numerical prefixes when you want to specify the execution order.
  • The manually listed scripts in recipe.yml should be stored directly within scripts/, or in a custom subdirectory that doesn't match any of the execution phases. For example, you could set the pre: section of recipe.yml to execute both autorun.sh and fizzwidget/something.sh, and then place a bunch of auto-executed scripts under scripts/pre/ for the autorunner. This makes it very simple to reuse common scripts between multiple different recipe.yml files, while also having some scripts be specific to different recipe.ymls.
  • You can safely specify autorun.sh as a script in recipe.yml, even if the special directories don't exist or don't contain any scripts. It will gracefully skip the processing if there's nothing to do.