Cloud-config Reference
Node OS images build using the Elemental Toolkit are expected
to be initialized and configured by using yip. Yip is a small utility to
apply a set of actions and configurations to the system described with yaml files. Yip is integrated and consumed
as a library within the elemental client binary (see elemental run-stage --help
). Yip groups the configurations
and actions to apply in arbitrary stages, for instance the elemental run-stage network
command call would only
apply defined actions and configuration for the stage named network
. Note from Yip perspective stages can be run at
any time as they are simply grouping a set of actions under an arbitrary name.
Elemental Toolkit integrates five predefined stages into the OS boot process.
-
pre-rootfs
: this stage runs on early boot inside the init ram disk, just before mounting the root device (typically at/sysroot
). This stage can be used to define first-boot steps that are required before mounting the root device. A good example is expanding the root device partition. Executed as part of theinitrd-root-device.target
. -
rootfs
: this stage runs on early boot inside the init ram disk, just after mounting the root device (typically at/sysroot
). This stage can be used to define first-boot steps like creating new partitions. Ephemeral and persistent paths are typically defined at this stage. Executed as part of theinitrd-root-fs.target
. -
initramfs
: this stage runs inside the init ram disk too, but on a later stage just before switching root. This stage runs in a chrooted environment to the actual root device. This stage is handy to set some system parameters that might be relevant to systemd after switching root. For instance, additional systemd unit files could be added here before the systemd from the actual root is executed. Executed as part of theinitrd.target
. -
fs
: this stage is the first one executed after switching root and it is executed as part of thesysinit.target
which runs once all all local filesystems and mountpoints defined in fstab are mounted and ready. -
network
: this stage is executed as part of themulti-user.target
and after thenetwork-online.target
is reached. This stage can be used to run actions and configurations that require network connectivity. For instance this stage is used to run the very first node registration and and installation from a live ISO. -
boot
: this stage is executed as part of themulti-user.target
and before thegetty.target
. This is the default stage to run cloud-config data provided using the supported cloud-init syntax. See cloud-init compatibility section.
By default, elemental
reads the yaml configuration files from the following paths in order: /system/oem
, /oem
and /usr/local/cloud-config
.
In Elemental Operator, all kubernetes resources including a cloud-config
field can be expressed in either yip or
cloud-init compatible syntax. This includes resources such as MachineRegistration
, SeedImage
, and ManagedOSImage
.
In contrast to similar projects such as Cloud Init, Yip does not keep records or caches of executed stages and steps, all stages and its associated configuration is executed at every boot.
Elemental client cloud-config hooks​
In addition to the defined cloud-config stages at boot described in the previous section the Elemental client also
honors some specific stages, referenced as hooks, to customize the behavior of these subcommands: install
,
upgrade
, reset
and build-disk
. Each of these subcommands has it's own set of four different cloud-config stages executed at
analog phases of the specific subcommand execution.
Hooks are essetially a way to provide permanent changes to system that can't be easily expressed as part of an OCI container or that
are not easily achievable with the elemental
client configuration options. A good example could be handling the firmware in EFI
partition for Raspberry Pi devices.
Note most hooks are executed in the host environment with privileges, so they are potentially destructive operations. In most cases regular cloud-config operations at boot time are sufficient to setup the system. Also to include additional software in an image the preferred option is to build a derivative image and not abuse of hooks to install additional software.
Hook stages​
-
Before stages:
before-install
,before-upgrade
,before-reset
,before-disk
These stages are executed once the working directories and environment are prepared but before starting the actual action. Ininstall
,upgrade
andreset
steps this happens once all the associated partitions are created and mounted, but before stating the deployment of any image. -
After chrooted stages:
after-install-chroot
,after-upgrade-chroot
,after-reset-chroot
,after-disk-chroot
These stages are executed after deploying the target system into the working area into a chroot environment rooted to the actual deployed image. Since this happens in a chroot env the elemental client analyses the hooks present in the deployed image, not in the host. Only/oem
is shared with the host if available. -
After stages:
after-install
,after-upgrade
,after-reset
,after-disk
These stages are executed after deploying the target system into the working area from the host environment. At this stages all partitions are still mounted and available in RW mode. This particular set of stages analyses the hooks present in the host and into the equivalent set of paths chrooted to the deployed image. The hook however is not executed in a chroot environment. This is helpful to provideafter-*
hooks within the deployed image. -
Post stages:
post-install
,post-upgrade
,post-reset
,post-disk
These stages are executed at end before exiting the command and running a cleanup process. At this stage the image is already deployed and locked in a read-only subvolume or filesystem. Partitions are still mounted at this stage.
Note installation hooks are not applied as part of the MachineRegistartion.config.cloud-config.
In order to provide installation hooks they can be included as part of the SeedImage.cloud-config,
as they need to be present in the installation media.
The only exception is after-install-chroot
which can be provided as part of a
MachineRegistartion.config.cloud-config because the hook runs
in the deployed image chroot and by that time cloud-config is already installed into the system.
Configuration syntax​
Yip has its own syntax, it essentially requires to define stages and a list of steps for each stage. Steps are executed in order and each step can be a combination different action types (e.g run commands, create files, set hostname, etc.).
Consider the following example:
stages:
initramfs:
- name: "Setup users"
ensure_entities:
- path: /etc/shadow
entity: |
kind: "shadow"
username: "root"
password: "root"
boot:
- files:
- path: /tmp/script.sh
content: |
#!/bin/sh
echo "test"
permissions: 0777
owner: 1000
group: 100
- commands:
- /tmp/script.sh
In the above exaple there are two stages: initramfs
and boot
.
The initramfs
stage initializes a sample user.
The boot
stage includes two steps, one to create an executable script file and a second one
that actually runs the script.
Yip also supports *.before
and *.after
suffix modifiers to any given stage. For instance, running the network
stage
results into running first network.before
stages found in config files and then network
and finally network.after
.
See the full reference of applicable keys in steps documented in yip project itself.
Below is an example of the above configuration embedded in a MachineRegistration resource.
MachineRegistration example
apiVersion: elemental.cattle.io/v1beta1
kind: MachineRegistration
metadata:
name: my-nodes
namespace: fleet-default
spec:
config:
cloud-config:
name: "A registration driven config"
stages:
after-install-chroot:
- name: "Set serial console"
commands:
- grub2-editenv /oem/grubenv set extra_cmdline="console=ttyS0"
initramfs:
- name: "Setup users"
ensure_entities:
- path: /etc/shadow
entity: |
kind: "shadow"
username: "root"
password: "root"
boot:
- files:
- path: /tmp/script.sh
content: |
#!/bin/sh
echo "test"
permissions: 0777
owner: 1000
group: 100
- commands:
- /tmp/script.sh
elemental:
install:
reboot: true
device: /dev/sda
debug: true
machineName: my-machine
machineInventoryLabels:
element: fire
Compatibility with Cloud Init format​
A subset of the official cloud-config spec is implemented by yip.
More specific the supported cloud-init keys are: users
, ssh_authorized_keys
, runcmd
, hostname
and write_files
are implemented.
If a yaml file starts with #cloud-config
it is parsed as a standard cloud-init, associated it to the yip boot
stage.
For example:
#cloud-config
users:
- name: "bar"
passwd: "foo"
groups: "users"
homedir: "/home/foo"
shell: "/bin/bash"
ssh_authorized_keys:
- faaapploo
# Assigns these keys to the first user in users or root if there
# is none
ssh_authorized_keys:
- asdd
# Run these commands once the system has fully booted
runcmd:
- foo
# Write arbitrary files
write_files:
- encoding: b64
content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4
path: /foo/bar
permissions: "0644"
owner: "bar"
Below is an example of the above configuration embedded in a MachineRegistration resource.
MachineRegistration example
apiVersion: elemental.cattle.io/v1beta1
kind: MachineRegistration
metadata:
name: my-nodes
namespace: fleet-default
spec:
config:
cloud-config:
users:
- name: "bar"
passwd: "foo"
groups: "users"
homedir: "/home/foo"
shell: "/bin/bash"
ssh_authorized_keys:
- faaapploo
ssh_authorized_keys:
- asdd
runcmd:
- foo
write_files:
- encoding: b64
content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4
path: /foo/bar
permissions: "0644"
owner: "bar"
elemental:
install:
reboot: true
device: /dev/sda
debug: true
machineName: my-machine
machineInventoryLabels:
element: fire