Talos Linux is a minimal, immutable operating system designed specifically for running Kubernetes. It provides enhanced security through API-driven configuration with no shell access, automatic updates, and a reduced attack surface. This guide shows you how to use Talos with KSail for local development (Docker provider), cloud deployments (Hetzner Cloud provider), or managed clusters through Sidero Omni (Omni provider).
Talos is ideal for security-focused production workloads, GitOps workflows, and multi-cloud deployments requiring immutable infrastructure. It’s not suitable for quick prototyping or scenarios requiring shell access—use Vanilla or K3s instead.
[!NOTE]
Omni generates the kubeconfig context name (e.g., <account>-<cluster>), which differs from the admin@<name> convention used by Docker and Hetzner Talos clusters. After creation, retrieve the context name from your kubeconfig and set it in ksail.yaml:
Check Docker status (docker ps, docker network ls), verify HCLOUD_TOKEN for Hetzner, or try cleaning up and retrying with ksail cluster delete && ksail cluster create.
Verify MetalLB is enabled in ksail.yaml (loadBalancer: Enabled), check MetalLB pods (kubectl get pods -n metallb-system), and verify IP pool exists (kubectl get ipaddresspools -n metallb-system). On macOS, Docker runs in a Linux VM so MetalLB virtual IPs are not routable from the host—use extraPortMappings instead (see Port Mappings (Docker Provider)).
Check ~/.talos/config exists, verify node IPs with kubectl get nodes -o wide, and use explicit node IP with talosctl -n <node-ip> --talosconfig ~/.talos/config get members.
On macOS, Docker runs in a Linux VM, so MetalLB virtual IPs are not directly accessible from the host. For Talos clusters using the Docker provider only, use extraPortMappings in ksail.yaml to expose container ports on the host (Hetzner and Omni Talos clusters do not use Docker port mappings):
# Partial snippet — add to your existing ksail.yaml
spec:
cluster:
distribution: Talos
talos:
extraPortMappings:
- containerPort: 80
hostPort: 8080
protocol: TCP
- containerPort: 443
hostPort: 8443
protocol: TCP
Access services at http://localhost:<hostPort> (for the example above, http://localhost:8080). Ports are applied to the first control-plane node only—in multi-control-plane clusters, additional control-plane nodes do not receive port mappings to avoid Docker host port collisions. See the Declarative Configuration reference for the full field specification.
ksail cluster update reconciles the Talos OS version automatically: it follows the latest supported version when spec.cluster.talos.version is unset, or reconciles toward the pinned version when it is set (also overridable per run with --distribution-version). The same field governs ksail cluster create.
Terminal window
# Follow the latest supported Talos version
ksailclusterupdate
# Pin a specific Talos OS version
ksailclusterupdate--distribution-versionv1.13.3
KSail performs a rolling upgrade, one node at a time:
Worker nodes are upgraded one at a time
Control-plane nodes are upgraded one at a time after all workers complete
For each node, KSail selects the upgrade API based on the node’s running Talos version — nodes on Talos 1.13+ use the LifecycleService/ImageService APIs, while older nodes (for example 1.12.x) use the legacy MachineService upgrade API — then triggers the upgrade and waits for the node to be ready before proceeding.
[!NOTE]
Omni-managed clusters are excluded from KSail-driven upgrades — Omni handles OS upgrades externally through its own cluster lifecycle management.
Talos 1.13 introduced ImageVerificationConfig, which enforces machine-wide container image signature verification before any image is pulled. KSail can scaffold a starter configuration:
Terminal window
ksailclusterinit\
--distributionTalos\
--image-verificationEnabled
This generates talos/cluster/image-verification.yaml with a default skip-all rule and commented examples. The file is a valid Talos config document that KSail applies alongside your MachineConfig during cluster creation.
# Talos ImageVerificationConfig (Talos 1.13+)
# Rules are evaluated in order; the first matching rule applies.
apiVersion: v1alpha1
kind: ImageVerificationConfig
rules:
# Default: skip verification for all images.
# Remove or modify this rule and add specific verification rules below.
- image: "*"
skip: true
# Example: Verify registry.k8s.io images using keyless (Cosign/OIDC) verification
# Example: Verify images from a private registry using a public key
# - image: "my-registry.example.com/*"
# publicKey:
# certificate: |
# -----BEGIN CERTIFICATE-----
# <your PEM-encoded certificate here>
# -----END CERTIFICATE-----
# Example: Deny all images from an untrusted registry
# - image: "untrusted-registry.example.com/*"
# deny: true
Edit the file to enforce your signature policy, then run ksail cluster create.
[!NOTE]
For Talos, --image-verification Enabled scaffolds a native ImageVerificationConfig document and requires Talos 1.13+. For earlier Talos versions, omit the flag or use --image-verification Disabled.
[!NOTE]
The Vanilla (Kind) distribution also supports --image-verification Enabled via containerd config patches — see Vanilla Image Verification.
Talos 1.9 introduced the EnvironmentConfig resource as the preferred way to set environment variables for system services (kubelet, containerd, etc.). The legacy .machine.env field in MachineConfig is deprecated and will be removed in Talos 1.13.
KSail does not generate .machine.env in any scaffolded patches. If you need to set environment variables (e.g. HTTP proxy settings, custom kubelet flags via env), create an EnvironmentConfig document in your Talos patches directory:
apiVersion: v1alpha1
kind: EnvironmentConfig
environment:
HTTP_PROXY: "http://proxy.example.com:8080"
HTTPS_PROXY: "http://proxy.example.com:8080"
NO_PROXY: "10.0.0.0/8,192.168.0.0/16,localhost"
Place the file under your talos/ patches directory (e.g. talos/cluster/environment.yaml) and KSail will apply it alongside other config documents during cluster creation.
[!NOTE]
Do not use .machine.env in custom patches — it is deprecated and will stop working in Talos 1.13+. Use EnvironmentConfig instead.