Skip to content

Incus Integration

MetalSoft integrates with Incus in two ways:

  1. As a VM Pool provider (VM Management) Consult Managing a VM Pool for more details for more details
  2. As an application via the extensions mechanism, which deploys and manages the lifecycle (install, scale-out/scale-in, upgrade) of an Incus cluster on bare-metal nodes The extension definition and Ansible playbooks live in the Incus extension repository

The rest of this page covers the application extension.

  1. A MetalSoft controller running release 7.2 or newer, with the Ansible Runner capability enabled on the site controller. See Enabling the Ansible Runner Capability for more details.
  2. Bare-metal hosts prepared for the Incus deployment: at least one host with a healthy hardware status and a minimum of two network interfaces.
  3. The Incus OS templates registered at the target site: incus-ubuntu-22-04-cluster-node or incus-ubuntu-24-04-cluster-node (see the MetalSoft OS templates repository).
  4. A logical network profile labeled incus-mgmt at the target site. The extension attaches the cluster nodes to this network with DNS records provisioned per instance, so forward DNS resolution for the instance FQDNs must work.
  5. The extension’s site configuration saved on every target site (see below). Because the extension declares site-level configuration variables, a deployment fails with “Extension not enabled on site” until an operator opens the extension’s site config on each site and saves it — all variables ship with defaults, so this is a one-click save unless overrides are needed.
  1. Clone the repository containing the extension definition:
Terminal window
git clone https://github.com/metalsoft-io/metalsoft-extensions

The definition references an Ansible bundle and an execution environment image already hosted on repo.metalsoft.io, so no re-packaging is needed. If your sites use a different logical network profile, adjust infrastructure.logicalNetworks[].profileLabel (default incus-mgmt) before creating the extension.

  1. Create and publish the extension:
Terminal window
metalcloud-cli extension create "Incus" application "Incus cluster lifecycle management" --definition-source metalsoft-extensions/incus/extension.json
metalcloud-cli extension publish <id-of-created-extension>
  1. Enable the extension on the site level and save its configuration. After publishing, the extension must be activated per site on the site level configuration page. This is also where its configVars — the operator-set, site-level settings — are configured, and it must be done before the first deploy.

You should now be ready to deploy the Incus application from the Infrastructure Designer.

These settings are set once per site by an operator and apply to every Incus deployment at that site:

VariableTypeDefaultDescription
DNSResolversString1.1.1.1Comma-separated DNS resolver IPs handed to every cluster node (systemd-resolved).
branch_releaseStringstableZabbly package channel to install/track: daily, stable or lts-6.0.
images_auto_update_intervalInteger6Interval in hours at which cached images are auto-updated.
core_https_portInteger8443HTTPS port the Incus API listens on.
separate_api_and_cluster_trafficBooleanfalseWhen true, cluster traffic uses a dedicated port (API port + 1) instead of sharing the API address.
cluster_member_upgrade_enabledBooleanfalseWhen true, edit deployments apply OS/package upgrades to existing members one node at a time before scaling. Enable it before scaling out an aged cluster, or the new node’s newer Incus version fails the cluster join version check.
cluster_member_force_remove_enabledBooleanfalseWhen true, scale-in force-removes a member that stays offline after evacuation.
vars_debugging_enabledBooleanfalseWhen true, playbooks print the resolved extension variables for debugging.

Each deployment created from the Infrastructure Designer takes the following inputs:

InputTypeDefaultDescription
cluster_server_typeServerTypeServer type for the Incus cluster nodes.
cluster_instance_countInteger1Number of nodes (1–50). Changing it on an existing deployment triggers scale-out/scale-in.
cluster_node_os_templateOsTemplateOS template for the cluster nodes (Ubuntu).
cluster_enabledBooleantrueDeploy Incus in clustering mode.
install_uiBooleantrueInstall the Incus web UI.
storage_driverStringdirStorage backend for the default pool: dir, btrfs, lvm, lvmcluster, zfs, ceph, cephfs or cephobject.

After every successful deployment or edit the extension publishes the following outputs on the extension instance:

OutputDescription
cluster_api_urlhttps://<first node FQDN>:<core_https_port>
cluster_ui_urlSame as the API URL when install_ui is true, empty otherwise
cluster_membersComma-separated FQDNs of the current cluster members
cluster_member_countNumber of cluster members
cluster_storage_driverStorage driver of the default pool
incus_releaseZabbly channel the cluster tracks
browser_client_certificatePEM user (browser) client certificate trusted by the cluster
browser_client_certificate_keyPEM private key for the browser certificate (see security note below)

Browser access to the Incus UI (client certificate)

Section titled “Browser access to the Incus UI (client certificate)”

Each deployment generates a dedicated user client certificate on the first cluster member and registers it in the cluster-wide trust store. The PEM certificate and private key are published as the browser_client_certificate / browser_client_certificate_key outputs so a person can authenticate to the Incus web UI (cluster_ui_url):

  1. Copy the two output values into local files, keeping the BEGIN/END lines and line breaks intact: browser-client.crt and browser-client.key.
  2. Convert the pair to a PKCS#12 bundle (choose an export password — the browser asks for it at import):
Terminal window
openssl pkcs12 -export \
-in browser-client.crt \
-inkey browser-client.key \
-name "incus-browser-user" \
-out incus-browser-user.p12

If an older browser rejects the file, re-run with the additional -legacy flag. 3. Import the bundle into the browser’s certificate store (Firefox: Settings → Privacy & Security → Certificates → View Certificates… → Your Certificates → Import…). 4. Open the cluster_ui_url output. Accept the self-signed server certificate warning first, then select the imported certificate when the browser prompts for a client certificate (restart the browser if no prompt appears — it may cache a “no certificate” choice per host).

Edit the deployment’s cluster_instance_count. Scale-in nodes are evacuated and removed from the cluster before the infrastructure change (while they are still reachable), and scale-out nodes are installed and joined after it. When cluster_member_upgrade_enabled is true, existing members are upgraded one node at a time before new nodes join.

The extension’s Ansible playbooks run on the Site Controller inside an execution environment — a container image holding all the dependencies the playbooks need. The extension ships its own image, declared as an OciImage asset in the extension definition and selected by each Ansible task via the ee option, so no Site Controller configuration is required. To customize it, rebuild the image from the execution-environment.yml recipe in the extension repository and update the OciImage asset in the definition.