Incus
While Flatcar proposes Containerd and Docker by default, Incus can be used to run containers. The goal of this guide is not to re-write the Incus documentation but to give key aspects of Incus usage on Flatcar.
Installing Incus
Incus is provided as an official Systemd sysext Flatcar extension. To install it automatically at boot:
---
# config.yaml
# butane < config.yaml > config.json
variant: flatcar
version: 1.1.0
storage:
files:
- path: /etc/flatcar/enabled-sysext.conf
contents:
inline: |
incus
Once the instance booted, incus
command is available and incus.{socket,service}
are started. Note: the core
user is added by default to the incus-admin
group.
core@localhost ~ $ systemd-sysext status
HIERARCHY EXTENSIONS SINCE
/opt none -
/usr flatcar-incus Fri 2025-05-16 08:43:36 UTC
core@localhost ~ $ incus --version
6.0.3
core@localhost ~ $ userdbctl groups-of-user core
USER GROUP
core docker
core docker
core incus-admin
core portage
core systemd-journal
core systemd-journal
core wheel
core wheel
8 memberships listed.
Initialize Incus
Before using Incus, it must be initialized using one of those two ways:
- Via CLI - Ideal for testing and quick setups.
- Using a pre-seed file - Recommended for automation and repeatable deployments.
The CLI can output the pre-seed file at the end of the manual initialization. Once done, it is possible to use pre-seed file from Butane:
---
# config.yaml
# butane < config.yaml > config.json
variant: flatcar
version: 1.1.0
storage:
files:
- path: /etc/flatcar/enabled-sysext.conf
contents:
inline: |
incus
- path: /etc/incus/pre-seed.yaml
contents:
inline: |
config: {}
networks:
- config:
ipv4.address: auto
ipv6.address: auto
description: ""
name: incusbr0
type: ""
project: default
storage_pools:
- config:
size: 5GiB
description: ""
name: default
driver: btrfs
profiles:
- config: {}
description: "Flatcar profile"
devices:
eth0:
name: eth0
network: incusbr0
type: nic
root:
path: /
pool: default
type: disk
name: default
projects: []
cluster: null
systemd:
units:
- name: incus-admin-init.service
enabled: true
contents: |
[Unit]
Description=incus admin init
After=systemd-sysext.service
Requires=systemd-sysext.service
[Service]
StandardInput=file:/etc/incus/pre-seed.yaml
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/incus admin init --preseed
[Install]
WantedBy=multi-user.target
Using Incus
Once Incus is installed and initialized, Incus documentation can be consulted to learn how to operate containers.
core@localhost ~ $ incus launch images:ubuntu/22.04 ubuntu-01
Launching ubuntu-01
core@localhost ~ $ incus list
+-----------+---------+----------------------+------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+-----------+---------+----------------------+------+-----------+-----------+
| ubuntu-01 | RUNNING | 10.126.29.162 (eth0) | | CONTAINER | 0 |
+-----------+---------+----------------------+------+-----------+-----------+
core@localhost ~ $ incus exec ubuntu-01 cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.5 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
Using Incus and ZFS
ZFS is provided as a Systemd sysext Flatcar extension as well, it fits perfectly with Incus as a storage driver. This configuration can be used to deactivate Docker and Containerd and enable Incus runtime using ZFS storage.
---
# config.yaml
# butane < config.yaml > config.json
variant: flatcar
version: 1.1.0
storage:
files:
- path: /etc/flatcar/enabled-sysext.conf
contents:
inline: |
incus
zfs
- path: /etc/incus/pre-seed.yaml
contents:
inline: |
config: {}
networks:
- config:
ipv4.address: auto
ipv6.address: auto
description: ""
name: incusbr0
type: ""
project: default
storage_pools:
- config:
size: 5GiB
description: "Incus ZFS pool"
name: default
driver: zfs
profiles:
- config: {}
description: ""
devices:
eth0:
name: eth0
network: incusbr0
type: nic
root:
path: /
pool: default
type: disk
name: default
projects: []
cluster: null
links:
- path: /etc/extensions/docker-flatcar.raw
target: /dev/null
overwrite: true
- path: /etc/extensions/containerd-flatcar.raw
target: /dev/null
overwrite: true
systemd:
units:
- name: incus-admin-init.service
enabled: true
contents: |
[Unit]
Description=incus admin init
After=systemd-sysext.service
Requires=systemd-sysext.service
[Service]
StandardInput=file:/etc/incus/pre-seed.yaml
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/incus admin init --preseed
[Install]
WantedBy=multi-user.target
Incus will now use ZFS pool to store images and containers:
core@localhost ~ $ incus storage list
+---------+--------+----------------+---------+---------+
| NAME | DRIVER | DESCRIPTION | USED BY | STATE |
+---------+--------+----------------+---------+---------+
| default | zfs | Incus ZFS pool | 1 | CREATED |
+---------+--------+----------------+---------+---------+
core@localhost ~ $ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
default 4.50G 592K 4.50G - - 1% 0% 1.00x ONLINE -