Chapter 12. Managing file systems in image mode for RHEL
Image mode uses OSTree as a back end, and enables composefs for storage by default. As a result, you can install third-party content in derived container images that write into /opt for example, because the /opt and /usr local paths are plain directories, and not symbolic links into /var.
When you install third-party content to /opt, the third-party components might also attempt to write to subdirectories within /opt during runtime, what can create potential conflicts.
12.1. Overview of physical and logical root with /sysroot Copy linkLink copied to clipboard!
When a bootc system is fully booted, it is similar to an environment created by chroot, that is, the operating system changes the apparent root directory for the current running process and its children. The physical host root filesystem is mounted at /sysroot. The chroot filesystem is called a deployment root.
The remaining filesystem paths are part of a deployment root which is used as a final target for the system boot. The system uses the ostree=kernel argument to find the deployment root.
/usr-
It is preferred to keep all operating system content in
/usr, but not strictly required. Directories such as/binwill work as symbolic links to/usr/bin. This layout creates a separation of operating system and host specific resources.
When composefs is enabled, /usr is not different from /. Both directories are part of the same immutable image, so you do not need to perform a full UsrMove with a bootc system.
/usr/local-
With bootc systems, you can create custom container images as the default entrypoint. Because of that, the base images configure
/usr/localto be a regular directory, that is, the default directory.
The default filesystem layout has both /opt and /usr/local as regular directories, that is, they writable at build time and immutable at runtime. This differs from RHEL CoreOS, for example, which makes these symlinks into /var.
/etcThe
/etcdirectory contains mutable persistent state by default, but it supports enabling theetc.transient configoption. When the directory is in mutable persistent state, it performs a 3-way merge across upgrades:-
Uses the new default
/etcas a base -
Applies the diff between current and previous
/etcto the new/etcdirectory -
Retains locally modified files that are different from the default
/usr/etcof the same deployment in/etc.
-
Uses the new default
The ostree-finalize-staged.service executes these tasks during shutdown time, before creating the new boot loader entry.
This happens because many components of a Linux system ship default configuration files in the /etc directory. Even if the default package does not ship it, by default the software only checks for config files in /etc. package-based update systems with no distinct versions of /etc are populated only during the installation time, and will not be changed at any point after installation. This causes the /etc system state to be influenced by the initial image version and can lead to problems to apply a change, for example, to /etc/sudoers.conf, and requires external intervention. For more details about file configuration, see Building and testing RHEL bootc images.
/var-
For example, there is only one
/vardirectory. By default, the files and data placed in the/vardirectory are persistent until explicitly deleted, and available across different sessions and system restarts. You can turn the/varpartition or its subdirectories into a mount point, such as a temporary file system (TMPFS) or a network mount point. If you do not make a distinct partition for/var, the system performs a bind mount, and creates a single, shared and persistent/ostree/deploy/$stateroot/varin the/vardirectory, so that both directories share the same data across deployments.
By default, the content in /var acts as a volume, that is, the content from the container image is copied during the initial installation time, and is not updated thereafter.
The /var and the /etc directories are different. You can use /etc for relatively small configuration files, and the expected configuration files are often bound to the operating system binaries in /usr. The /var directory has arbitrarily large data, for example, system logs, databases, and by default, do not roll back if the operating system state is rolled back.
For example, making an update such as dnf downgrade postgresql should not affect the physical database in /var/lib/postgres. Similarly, making a bootc update or bootc rollback do not affect this application data.
Having /var separate also makes it work cleanly to stage new operating system updates before applying them, that is, updates are downloaded and ready, but only take effect on reboot. The same applies for Docker volume, as it decouples the application code from its data.
You can use this case if you want applications to have a pre-created directory structure, for example, /var/lib/postgresql. Use systemd tmpfiles.d for this. You can also use StateDirectory=<directory> in units.
- Other directories
-
There is no support to ship content in
/run,/procor other API Filesystems in container images. Apart from that, other top level directories such as/usr, and/opt, are lifecycled with the container image. /opt-
Because
bootcusescomposefs, the/optdirectory is read-only, alongside other top level directories such as/usr.
When a software needs to write to its own directory in /opt/exampleapp, a common pattern is to use a symbolic link to redirect to, for example, /var for operations such as log files:
RUN rmdir /opt/exampleapp/logs && ln -sr /var/log/exampleapp /opt/exampleapp/logs
RUN rmdir /opt/exampleapp/logs && ln -sr /var/log/exampleapp /opt/exampleapp/logs
Optionally, you can configure the systemd unit to launch the service to do these mounts dynamically. For example:
BindPaths=/var/log/exampleapp:/opt/exampleapp/logs
BindPaths=/var/log/exampleapp:/opt/exampleapp/logs
- Enabling transient root
-
To enable a software to transiently (until the next reboot) write to all top-level directories, including
/usrand/opt, with symlinks to/varfor content that should persist, you can enable transient root. To enable a fully transient writablerootfsby default, set the following option in/usr/lib/ostree/prepare-root.conf.
[root] transient = true
[root]
transient = true
This enables a software to transiently write to /opt, with symlinks to /var for content that must persist.
12.2. Version selection and bootup Copy linkLink copied to clipboard!
Image mode for RHEL uses GRUB by default, with exception to IBM Z® architectures. Each version of image mode for RHEL currently available on a system has a menu entry.
The menu entry references an OSTree deployment, which consists of a Linux kernel, an initramfs and a hash linking to an OSTree commit, which you can pass by using the ostree=kernel argument.
During bootup, OSTree reads the kernel argument to determine which deployment to use as the root filesystem. Each update or change to the system, such as package installation, addition of kernel arguments, creates a new deployment.
This enables rolling back to a previous deployment if the update causes problems.