Skip to content
Merged
154 changes: 154 additions & 0 deletions src/docs/avocado-linux/guides/customizing-rootfs-initramfs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
sidebar_position: 8
title: 'Customizing the rootfs and initramfs'
description: 'Add packages to the Avocado rootfs and initramfs sysroots to customize the base root filesystem and early boot environment.'
---

Avocado builds runtime images from two base sysroots: the **rootfs** (the read-only root filesystem) and the **initramfs** (the early boot environment that runs before the rootfs is mounted). By default each sysroot installs a single meta-package that pulls in everything needed for a standard Avocado system. You can add extra packages to either sysroot to customize what ships on your device.

## Default behavior

When no `rootfs` or `initramfs` section is present in your `avocado.yaml`, the CLI installs the default meta-packages automatically:

| Sysroot | Default package |
| --------- | ----------------------- |
| rootfs | `avocado-pkg-rootfs` |
| initramfs | `avocado-pkg-initramfs` |

These meta-packages depend on the core set of packages needed for a functional Avocado system. You do not need to add anything to your config if the defaults are sufficient.

## Adding packages to the rootfs

To add packages to the rootfs, add a `rootfs` section with a `packages` map to your `avocado.yaml`:

```yaml
rootfs:
packages:
avocado-pkg-rootfs: '*'
strace: '*'
tcpdump: '>=4.0'
```

:::caution

When you specify `rootfs.packages`, the CLI installs **only** the packages you list — it does **not** automatically include `avocado-pkg-rootfs`. You must always include `avocado-pkg-rootfs` in the package list. Omitting it will produce a rootfs that is missing core Avocado system components.

:::

### Version constraints

Package values are version constraints passed to DNF:

| Value | Meaning |
| --------- | ------------------------------ |
| `'*'` | Any version (latest available) |
| `'1.2'` | Exact version `1.2` |
| `'>=4.0'` | Version 4.0 or newer |

## Adding packages to the initramfs

The initramfs works the same way. Add an `initramfs` section:

```yaml
initramfs:
packages:
avocado-pkg-initramfs: '*'
e2fsprogs: '*'
```

:::caution

As with the rootfs, when you specify `initramfs.packages` you must always include `avocado-pkg-initramfs`. The CLI installs only the packages you list.

:::

## Choosing a filesystem format

Both sysroots support configuring the output image filesystem:

```yaml
rootfs:
filesystem: erofs-lz4 # default
packages:
avocado-pkg-rootfs: '*'

initramfs:
filesystem: cpio.zst # default
packages:
avocado-pkg-initramfs: '*'
```

### Rootfs filesystem options

| Value | Description |
| ----------- | ------------------------------------- |
| `erofs-lz4` | Default. EROFS with LZ4HC compression |
| `erofs-zst` | EROFS with Zstandard compression |

### Initramfs filesystem options

| Value | Description |
| ---------- | ------------------------------------------------ |
| `cpio.zst` | Default. cpio archive with Zstandard compression |
| `cpio` | Uncompressed cpio archive |
| `cpio.lz4` | cpio archive with LZ4 compression |
| `cpio.gz` | cpio archive with gzip compression |

## Complete example

```yaml
sdk:
image: docker.io/avocadolinux/sdk:2024-edge

rootfs:
filesystem: erofs-lz4
packages:
avocado-pkg-rootfs: '*'
strace: '*'
vim-minimal: '*'

initramfs:
filesystem: cpio.zst
packages:
avocado-pkg-initramfs: '*'
e2fsprogs: '*'

extensions:
my-app:
version: '1.0.0'
types: [sysext]

runtimes:
dev:
extensions: [my-app]
packages:
avocado-runtime: '*'
```

## Build workflow

```bash
# Install all sysroots (SDK, rootfs, initramfs, extensions, runtimes)
avocado install

# Or install sysroots individually
avocado rootfs install
avocado initramfs install

# Build images
avocado rootfs image
avocado initramfs image

# Or build everything at once
avocado build
```

The `avocado install` and `avocado build` commands handle the rootfs and initramfs automatically as part of the full build pipeline. The individual `avocado rootfs` and `avocado initramfs` commands are useful for iterating on just the sysroot without rebuilding everything.

## Package removal

If you remove a package from the `packages` map, the CLI detects the removal on the next `install` and automatically cleans the sysroot before reinstalling. This is because DNF's installroot mode is additive-only — it cannot remove individual packages from an existing sysroot.

## Lock file

Installed package versions are recorded in `avocado.lock` after each successful install. This ensures reproducible builds — subsequent installs will pin to the same versions unless you run `avocado unlock` to allow updates.
4 changes: 1 addition & 3 deletions src/docs/avocado-linux/guides/hardware-in-the-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ runtimes:
- my-app
# highlight-added-end
packages:
avocado-img-bootfiles: '*'
avocado-img-rootfs: '*'
avocado-img-initramfs: '*'
avocado-runtime: '*'

sdk:
image: avocadolinux/sdk:apollo-edge
Expand Down
3 changes: 1 addition & 2 deletions src/docs/avocado-linux/guides/sideloading.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ Installing:
... snip ...

Installed:
avocado-img-bootfiles-1.0-r0.avocado_raspberrypi4 avocado-img-initramfs-1.0-r0.avocado_raspberrypi4
avocado-img-rootfs-1.0-r0.avocado_raspberrypi4
avocado-runtime-1.0-r0.avocado_raspberrypi4

Complete!
[SUCCESS] Successfully installed packages for runtime 'dev'
Expand Down
107 changes: 101 additions & 6 deletions src/docs/avocado-linux/references/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,23 +217,21 @@ runtimes:
- config
- app
packages:
avocado-img-bootfiles: '*'
avocado-img-rootfs: '*'
avocado-img-initramfs: '*'
avocado-runtime: '*'

prod:
extensions:
- avocado-bsp-{{ avocado.target }}
- config-prod
- app
packages:
avocado-img-bootfiles: '*'
avocado-img-rootfs: '*'
avocado-img-initramfs: '*'
avocado-runtime: '*'
```

This pattern enables you to include development tools, debugging utilities, and verbose logging in `dev` while keeping `prod` minimal and secure.

The rootfs and initramfs images are built automatically from their respective package sysroots during `avocado runtime build`. See [rootfs and initramfs](#rootfs-and-initramfs) for details.

## Building extensions

Extensions are built using the Avocado CLI. For complete build command options, see the [ext build command](../tools/avocado-cli/commands/ext/build) documentation.
Expand Down Expand Up @@ -760,6 +758,103 @@ Extensions integrate with Avocado's SDK for declarative package selection, custo

Learn how to leverage these capabilities with [hardware-in-the-loop development](../guides/hardware-in-the-loop).

## Rootfs and initramfs

Avocado builds the root filesystem (rootfs) and initial RAM filesystem (initramfs) images from RPM packages during `avocado runtime build`. These are top-level, config-wide concepts — all runtimes produced from a single `avocado.yaml` share the same rootfs and initramfs.

### Configuration

The `rootfs` and `initramfs` sections are optional top-level keys in `avocado.yaml`. When omitted, they default to their respective base packages:

```yaml
# Optional — these are the defaults if omitted
rootfs:
packages:
avocado-pkg-rootfs: '*'

initramfs:
packages:
avocado-pkg-initramfs: '*'
```

You can add additional packages to customize the base system and configure the image format:

```yaml
rootfs:
filesystem: erofs.lz4 # default
packages:
avocado-pkg-rootfs: '*'
my-custom-base-package: '*'

initramfs:
filesystem: cpio.zst # default
Comment on lines +784 to +790
packages:
avocado-pkg-initramfs: '*'
```

The `filesystem` property can also be set by a BSP extension, allowing per-platform defaults. Include the `rootfs` or `initramfs` section from your BSP extension to inherit platform-specific filesystem formats:

```yaml
extensions:
avocado-bsp-{{ avocado.target }}:
source:
type: package
include:
- rootfs
- initramfs
- provision_profiles.*
```

### Filesystem formats

The `filesystem` property controls the image format and compression algorithm used for the rootfs and initramfs images.

**Rootfs formats:**

| Value | Description |
| ----------- | ------------------------------------------------------------------------------ |
| `erofs.lz4` | EROFS with LZ4 compression (default). Fast decompression, good for boot speed. |
| `erofs.zst` | EROFS with Zstandard compression. Better compression ratio. |

**Initramfs formats:**

| Value | Description |
| ---------- | ------------------------------------------------------------------------------- |
| `cpio.zst` | CPIO archive with Zstandard compression (default). Requires `CONFIG_RD_ZSTD=y`. |
| `cpio.lz4` | CPIO archive with LZ4 compression. Requires `CONFIG_RD_LZ4=y`. |
| `cpio.gz` | CPIO archive with gzip compression. Widest kernel support. |
| `cpio` | Uncompressed CPIO archive. No kernel decompression config required. |

:::tip
Compressed formats require kernel decompression support built in. For example, `erofs.zst` requires `CONFIG_EROFS_FS_ZIP_ZSTD=y` and `cpio.zst` requires `CONFIG_RD_ZSTD=y`. BSP extensions can set the filesystem format per-platform to match the kernel's decompression capabilities. See the [custom kernel guide](../guides/custom-kernel) for kernel configuration details.
:::

### How it works

During `avocado sdk install`, package sysroots are created for both rootfs and initramfs alongside the SDK. These sysroots contain the installed RPM packages and serve as the base for image creation:

- `$AVOCADO_PREFIX/rootfs/` — rootfs sysroot (also used for extension RPM deduplication)
- `$AVOCADO_PREFIX/initramfs/` — initramfs sysroot

During `avocado runtime build`, these sysroots are copied to temporary work directories where post-processing is applied:

1. **Usrmerge symlinks** — `/bin` → `usr/bin`, `/sbin` → `usr/sbin`, `/lib` → `usr/lib`
2. **Systemd presets** — service units are enabled via preset files
3. **Machine ID** — an empty `/etc/machine-id` is created for stateless systemd on read-only rootfs
4. **Linker cache** — `ld.so.cache` is generated for the read-only rootfs
5. **OS identity** — `AVOCADO_OS_BUILD_ID` is injected into `/usr/lib/os-release`
6. **Image creation** — rootfs is packaged using the configured filesystem format (default: `erofs.lz4`), initramfs as cpio (default: `cpio.zst`)

The shared sysroots are never modified — work copies ensure extensions continue to prime correctly from the rootfs RPM database.

### Relationship to extensions

Extensions overlay the rootfs at runtime via systemd-sysext and systemd-confext. The rootfs provides the immutable base system, while extensions deliver user-defined functionality. Extension RPM deduplication uses the rootfs sysroot's RPM database to avoid duplicating packages already present in the base system.

### Cleaning

`avocado sdk clean` removes both the rootfs and initramfs sysroots along with the SDK. Use `avocado runtime clean` to remove built images for a specific runtime.

## Security and composition

Extensions maintain security through:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"label": "Connect",
"collapsible": true,
"collapsed": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"label": "Auth",
"collapsible": true,
"collapsed": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
```
Login to the Connect platform

Usage: avocado connect auth login [OPTIONS]

Options:
--url <URL> API URL (defaults to https://connect.peridio.com or AVOCADO_CONNECT_URL env var)
--profile <PROFILE> Profile name (defaults to "default")
--token <TOKEN> Use an existing API token instead of browser login
--runs-on <USER@HOST> Run command on remote host using local volume via NFS (format: user@host)
--nfs-port <NFS_PORT> NFS port for remote execution (auto-selects from 12050-12099 if not specified)
--sdk-arch <ARCH> SDK container architecture for cross-arch emulation via Docker buildx/QEMU (aarch64 or x86-64)
-h, --help Print help

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
```
Logout from the Connect platform

Usage: avocado connect auth logout [OPTIONS]

Options:
--profile <PROFILE> Profile name (defaults to the active default profile)
--runs-on <USER@HOST> Run command on remote host using local volume via NFS (format: user@host)
--nfs-port <NFS_PORT> NFS port for remote execution (auto-selects from 12050-12099 if not specified)
--sdk-arch <ARCH> SDK container architecture for cross-arch emulation via Docker buildx/QEMU (aarch64 or x86-64)
-h, --help Print help

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
```
Show current auth status

Usage: avocado connect auth status [OPTIONS]

Options:
--profile <PROFILE> Profile name (defaults to the active default profile)
--runs-on <USER@HOST> Run command on remote host using local volume via NFS (format: user@host)
--nfs-port <NFS_PORT> NFS port for remote execution (auto-selects from 12050-12099 if not specified)
--sdk-arch <ARCH> SDK container architecture for cross-arch emulation via Docker buildx/QEMU (aarch64 or x86-64)
-h, --help Print help

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"label": "Claim Tokens",
"collapsible": true,
"collapsed": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
```
Create a new claim token

Usage: avocado connect claim-tokens create [OPTIONS] --name <NAME>

Options:
--org <ORG> Organization ID (or set connect.org in avocado.yaml)
--name <NAME> Token name
--cohort-id <COHORT_ID> Cohort ID to assign claimed devices to
--max-uses <MAX_USES> Maximum number of times this token can be used
--no-expiration Disable expiration (default: expires in 24h)
-C, --config <CONFIG> Path to avocado.yaml configuration file [default: avocado.yaml]
--profile <PROFILE> Profile name (defaults to the active default profile)
--runs-on <USER@HOST> Run command on remote host using local volume via NFS (format: user@host)
--nfs-port <NFS_PORT> NFS port for remote execution (auto-selects from 12050-12099 if not specified)
--sdk-arch <ARCH> SDK container architecture for cross-arch emulation via Docker buildx/QEMU (aarch64 or x86-64)
-h, --help Print help

```
Loading
Loading