Runtime persistent changes

Applying changes to Elemental images in runtime or “how to install a package in an immutable OS at runtime?”

Elemental and derivatives are immutable systems. That means that any change in the running OS will not persist after a reboot.

While configurations can be persisted, there are occasions where installing a custom package or provide additional persistent files in the end system is needed.

We will see here a way to install packages, drivers, or apply any modification we might want to do in the OS image during runtime, without any need to rebuild the derivative container image. This will let any user (and not derivative developer) to apply any needed customization and to be able to persist across upgrades.

Transient changes

To apply transient changes, it’s possible to boot a Elemental derivative in read/write mode by specifying rd.cos.debugrw see here for more details. This allows to do any change and will persist into the active/passive booting system (does NOT apply for recovery). Altough this methodology should be only considered for debugging purposes.

Persist changes with Cloud init files

Elemental allows to apply a set of commands, or cloud-init steps, during upgrade, deploy, install and reset in the context of the target image, in RW capabilities. This allows to carry on changes during upgrades on the target image without the need to re-build or have a custom derivative image.

All the configuration that we want to apply to the system will run each time we do an upgrade, a reset or an installation on top of the new downloaded image (in case of upgrade) or the image which is the target system.

Between the available stages in the cloud-init there are after-upgrade-chroot, after-install-chroot, after-reset-chroot and after-deploy-chroot, for example, consider the following cloud-init file:

stages:
name: "Install something"
stages:
   after-upgrade-chroot:
     - commands:
        - zypper in -y ...
   after-reset-chroot:
     - commands:
        - zypper in -y ...
   after-deploy-chroot:
     - commands:
        - zypper in -y ...
   after-install-chroot:
     - commands:
        - zypper in -y ...

It will run the zypper in -y ... calls during each stage, in the context of the target system, allowing to customize the target image with additional packages.

When running the cloud-init steps the /oem partition and /usr/local will be mounted to COS_OEM and COS_PERSISTENT respectively, allowing to load extra data (e.g. rpm files, or configuration).

Example

If an user wants to install an additional package in the running system, and keep having that persistent across upgrades, he can copy the following file (install.yaml) inside the /oem folder, or /usr/local/cloud-config:

stages:
name: "Install something"
stages:
   after-upgrade-chroot:
     - commands:
        - zypper in -y vim

and run elemental upgrade.

It will automatically upgrade the system with the changes above included.


Last modified August 31, 2023: More documentation work (#1819) (2360815df)