Skip to content
DRAFT

Talos Kubernetes Cluster on IncusOS

Create a three-node Talos Kubernetes cluster on a remote IncusOS server using task tc:instantiate. The task creates the VMs, applies Talos config, bootstraps etcd, and retrieves kubeconfig.

Prerequisites

  • IncusOS server installed and running (see IncusOS Server)
  • Incus CLI on your machine, remote configured
  • Workspace initialized and context set (see Initialize Workspace)
  • At least 8GB RAM and 100GB storage on the IncusOS host for 3 VMs
  • Network with DHCP for the VMs

Step 1: Create or Set the Context

First, navigate to your workspace directory. Then either create a new context or switch to an existing one:

To create a new context (e.g., for a new environment or project):

cd /path/to/your/workspace
windsor init <context>

To use an existing context (if you already have a context defined):

cd /path/to/your/workspace
windsor context set <context>

Cluster configuration will be read from contexts/<context>/windsor.yaml for whichever context is active.

Step 2: Configure Environment

Get a schematic ID from Talos Image Factory (or use an empty schematic for default image).

Add to contexts/<context>/windsor.yaml:

environment:
  CONTROL_PLANE_VM: "talos-cp"
  WORKER_0_VM: "talos-worker-0"
  WORKER_1_VM: "talos-worker-1"
  TALOS_IMAGE_SCHEMATIC_ID: "<from-factory.talos.dev>"
  TALOS_IMAGE_VERSION: "v1.12.0"
  TALOS_IMAGE_ARCH: "metal-amd64"
  STORAGE_POOL: "local"

Leave CONTROL_PLANE_IP, WORKER_0_IP, WORKER_1_IP empty for a new cluster. The instantiate task will create the VMs, get DHCP IPs, update your config, and continue with Talos.

Optional: PHYSICAL_INTERFACE (default eno1), CONTROL_PLANE_MEMORY/WORKER_MEMORY (default 2GB), CONTROL_PLANE_CPU/WORKER_CPU (default 2).

Step 3: Talos Image

Download and import the Talos image so it exists on the remote:

task incus:download-talos-image
task incus:import-talos-image -- talos-${TALOS_IMAGE_VERSION}-metal-amd64

Instantiate will warn if the image is missing but will not fail.

Step 4: Verify Remote

incus remote list
incus list <remote-name>:
windsor env | grep INCUS_REMOTE_NAME

Step 5: Create the Cluster

task tc:instantiate -- <remote-name> [<cluster-name>] [--keep]
  • <remote-name> (required): Incus remote (e.g. nuc)
  • <cluster-name> (optional): Cluster name (default: test-cluster)
  • --keep: Do not destroy cluster after creation (use for real deployments)

Instantiate will: verify remote, check no existing cluster VMs, ensure image, generate tfvars, create 3 VMs, wait for them, get IPs from Terraform, update windsor.yaml, regenerate tfvars, apply Talos config, bootstrap etcd, and retrieve kubeconfig. This takes several minutes.

Step 6: Verify Cluster

kubectl get nodes -o wide
kubectl get pods -A -o wide
task talos:health-controlplane
task talos:health-worker

Managing the Cluster

task tc:list
incus list $INCUS_REMOTE_NAME:
incus start $INCUS_REMOTE_NAME:<vm-name>
incus stop $INCUS_REMOTE_NAME:<vm-name>
incus restart $INCUS_REMOTE_NAME:<vm-name>
incus console $INCUS_REMOTE_NAME:<vm-name>

Destroying the Cluster

task tc:destroy

This removes all cluster VMs and their data. Talos image and physical network are not deleted.

Troubleshooting

  • VMs not booting: Check Talos image alias matches talos-${TALOS_IMAGE_VERSION}-metal-amd64; see IncusOS Server for network (Step 8).
  • No IPs: Ensure physical network has instances role; wait 3–5 minutes for DHCP.
  • Bootstrap fails: Ensure control plane is up; run talosctl --nodes <control-plane-ip> version.
  • Resource errors: Lower CONTROL_PLANE_MEMORY/WORKER_MEMORY (min 2GB per VM).