ce-infra/docs/incus/research.md

7.4 KiB

Incus Research Notes

Research conducted 2026-03-17. Incus development moves fast — verify against latest docs before implementing.

Incus Version & Status

  • Latest: Incus 6.22 (February 28, 2026)
  • LTS: Incus 6.0 (5 years support)
  • Release cadence: Monthly feature releases
  • Debian 13 (Trixie): Native packages available (apt install incus)

OCI Container Support

  • Added in: Incus 6.3 (July 2024) — 18+ months mature
  • How it works: Pulls Docker/OCI images from registries, converts them, runs natively
  • Setup: incus remote add docker https://docker.io --protocol=oci
  • Usage: incus launch docker:postgres:16-alpine my-postgres
  • Dependencies: skopeo and umoci (included in Debian packages)
  • Maturity: Stable for production use, actively improved each release

System Containers vs OCI Containers

Aspect System Containers OCI Containers
Purpose Full OS simulation Single application
Init systemd (runs until stopped) Entrypoint process only
Image size 150-500MB per container Smaller, layered
RAM overhead ~50-100MB more than OCI Comparable to Docker
Use case Legacy apps, multi-process, full sysadmin Microservices, pre-built images

Networking

Managed Bridges

  • Incus creates bridges with dnsmasq for DHCP + DNS
  • Containers get DNS entries for their instance name automatically
  • Container-to-container by name works out of the box
  • Default bridge: incusbr0 (created during incus admin init)

Port Forwarding — Proxy Devices

# Single port
incus config device add container http proxy \
  listen=tcp:0.0.0.0:80 connect=tcp:127.0.0.1:80

# Port range
incus config device add container ports proxy \
  listen=tcp:0.0.0.0:8080-9000 connect=tcp:127.0.0.1:8080-9000

# UDP (for HTTP/3)
incus config device add container h3 proxy \
  listen=udp:0.0.0.0:443 connect=udp:127.0.0.1:443

Network Forwards (alternative to proxy devices)

incus network forward create <network_name> <listen_address>

Storage

Pool Backends

Backend Pros Cons
dir Simple, no setup Slower, no snapshots
zfs Fast snapshots, dedup, compression Complex setup
btrfs CoW, snapshots Less tooling than ZFS
lvm Reliable, mature Block-level only

Volume Operations

# Create volume
incus storage volume create <pool> <name>

# Attach to container
incus config device add <container> <device-name> disk \
  pool=<pool> source=<volume-name> path=<mount-path>

# Mount host directory into container
incus config device add <container> <device-name> disk \
  source=/host/path path=/container/path

Ansible Integration

Connection Plugin (community.general.incus)

  • Exec commands inside containers without SSH
  • Install: ansible-galaxy collection install community.general
  • Usage: ansible_connection: community.general.incus
  • Variables: ansible_incus_remote, ansible_incus_project, ansible_host

Inventory Plugin (community.general.incus_inventory)

  • Auto-discovers running Incus instances
  • Dynamic inventory source

Third-Party: kmpm.incus Collection

  • Dedicated modules: incus_instance, incus_network, incus_profile
  • Status: Beta/WIP, actively maintained
  • Install: ansible-galaxy collection install git+https://github.com/kmpm/ansible-collection-incus.git

Practical Approach for This Project

Use ansible.builtin.command with incus CLI directly. Simpler, more transparent, easier to debug than collections. Connection plugin useful for exec-inside-container tasks.

Incus Initialization (Preseed)

Non-interactive setup via incus admin init --preseed:

config: {}
networks:
  - config:
      ipv4.address: auto
      ipv4.nat: "true"
      ipv6.address: none
    name: incusbr0
    type: bridge
storage_pools:
  - config:
      source: /var/lib/incus/storage-pools/default
    name: default
    driver: dir
profiles:
  - config: {}
    devices:
      eth0:
        name: eth0
        network: incusbr0
        type: nic
      root:
        path: /
        pool: default
        type: disk
    name: default

Environment Variables in OCI Containers

Pass via --config flags at launch time:

incus launch docker:postgres:16-alpine gitea-db \
  --config environment.POSTGRES_DB=gitea \
  --config environment.POSTGRES_USER=gitea \
  --config environment.POSTGRES_PASSWORD=secretpass

Update existing container:

incus config set gitea-db environment.POSTGRES_PASSWORD=newpass
incus restart gitea-db

Backup & Restore

Snapshots (fast, local only)

incus snapshot create <instance> <snapshot-name>
incus snapshot restore <instance> <snapshot-name>
incus snapshot list <instance>

Exports (portable, for off-site backup)

incus export <instance> backup.tar.gz --optimized-storage
incus import backup.tar.gz <new-instance-name>

Volume Exports

incus storage volume snapshot <pool> <volume> <snapshot-name>
incus storage volume export <pool> <volume> volume-backup.tar.gz
incus storage volume import <pool> volume-backup.tar.gz <new-volume-name>

Database Dumps (same pattern as Docker)

incus exec gitea-db -- pg_dump -U gitea gitea > gitea-db.sql
incus exec outline-db -- pg_dump -U outline outline > outline-db.sql

6.22 Enhancements

  • Direct backup streaming (no temporary disk files)
  • Disk-only snapshot restore (revert storage without config)

Auto-Start / Restart Policy

# Start container on host boot
incus config set <container> boot.autostart true

# Set start order (lower = earlier)
incus config set <container> boot.autostart.priority 10

# Start delay (seconds, for dependency ordering)
incus config set <container> boot.autostart.delay 5

No automatic restart on crash (unlike Docker's restart: unless-stopped). Options:

  • Accept manual restart for crashes (rare)
  • Add a systemd watchdog timer on the host
  • Use incus monitor to watch for state changes

Running Docker Inside Incus (for Gitea Runner)

If needed for the runner:

incus launch images:debian/13/cloud gitea-runner-host
incus config set gitea-runner-host security.nesting true
incus exec gitea-runner-host -- apt install docker.io
# Then run act_runner inside this system container

Cloud-init Support

System containers with /cloud images support cloud-init:

incus launch images:debian/13/cloud my-container \
  --config cloud-init.user-data="#cloud-config
packages:
  - curl
  - git
"

Note: Cloud-init runs only on first boot. Not applicable to OCI containers.

Sources