Talos
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. KSail runs Talos for local development (Docker provider), cloud deployments (Hetzner Cloud provider), or managed clusters through Sidero Omni (Omni provider), configuring machine state through modular native Talos patches referenced by spec.cluster.distributionConfig.
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. For help choosing between distributions, see the distributions overview.
Quick Start
Section titled “Quick Start”Local Development with Docker
Section titled “Local Development with Docker”Create a Talos cluster on your local machine using Docker containers as nodes.
Prerequisites
Section titled “Prerequisites”Docker installed and running (see Docker Provider).
Step 1: Initialize Project
Section titled “Step 1: Initialize Project”ksail project init \ --name talos-dev \ --distribution Talos \ --provider Docker \ --control-planes 1 \ --workers 2Step 2: Create Cluster
Section titled “Step 2: Create Cluster”ksail cluster createStep 3: Verify Cluster
Section titled “Step 3: Verify Cluster”ksail cluster infokubectl get nodeskubectl get pods -AStep 4: Cleanup
Section titled “Step 4: Cleanup”ksail cluster deleteProduction Deployment on Hetzner Cloud
Section titled “Production Deployment on Hetzner Cloud”Create a production-ready Talos cluster on Hetzner Cloud infrastructure.
Prerequisites
Section titled “Prerequisites”A Hetzner Cloud account and API token. See Hetzner Provider for full setup.
Step 1: Configure API Token
Section titled “Step 1: Configure API Token”export HCLOUD_TOKEN=your-hetzner-api-tokenStep 2: Initialize Project
Section titled “Step 2: Initialize Project”ksail project init \ --name talos-prod \ --distribution Talos \ --provider Hetzner \ --control-planes 1 \ --workers 2Step 3: Create Cluster
Section titled “Step 3: Create Cluster”ksail cluster createStep 4: Verify Cluster
Section titled “Step 4: Verify Cluster”ksail cluster infokubectl get nodes -o widekubectl get pods -n kube-system | grep hcloud-csiStep 5: Cleanup
Section titled “Step 5: Cleanup”ksail cluster deleteManaged Deployment via Sidero Omni
Section titled “Managed Deployment via Sidero Omni”Create a Talos cluster managed through Sidero Omni, which handles machine lifecycle and cluster orchestration via a SaaS API.
Prerequisites
Section titled “Prerequisites”A Sidero Omni account with service account key and registered machines. See Omni Provider for full setup.
Step 1: Configure Credentials
Section titled “Step 1: Configure Credentials”export OMNI_SERVICE_ACCOUNT_KEY=your-base64-encoded-service-account-keyStep 2: Initialize Project
Section titled “Step 2: Initialize Project”ksail project init \ --name talos-omni \ --distribution Talos \ --provider Omni \ --control-planes 1 \ --workers 2Step 3: Add the Omni Endpoint
Section titled “Step 3: Add the Omni Endpoint”The scaffolder does not create an omni: block in ksail.yaml. You must add spec.provider.omni.endpoint manually:
spec: provider: omni: endpoint: "https://<account>.omni.siderolabs.io:443"Step 4: Create Cluster
Section titled “Step 4: Create Cluster”ksail cluster createStep 5: Cleanup
Section titled “Step 5: Cleanup”ksail cluster deleteConfiguration
Section titled “Configuration”KSail Configuration
Section titled “KSail Configuration”The ksail.yaml file controls the cluster. For Talos, spec.cluster.distributionConfig points at a directory of machine-config patches rather than a single file:
# yaml-language-server: $schema=https://raw.githubusercontent.com/devantler-tech/ksail/main/schemas/ksail-config.schema.jsonapiVersion: ksail.io/v1alpha1kind: Clusterspec: cluster: distribution: Talos distributionConfig: talos # directory of modular Talos patches (default) provider: Docker # Docker (local), Hetzner, or OmniConventionally the directory is named talos for production and talos-local for a local cluster, so a single repository can carry one patch set per environment. See Multi-Environment Workflows and the Reference Architecture for the layered, multi-cluster shape.
Modular Machine-Config Patches
Section titled “Modular Machine-Config Patches”KSail manages Talos machine configuration as a directory of small, native patches split by the node role they target — not one monolithic config file. Each file is a standard Talos machine-config patch (the same format you could apply with talosctl), so there is no lock-in and you have access to every Talos config option. ksail project init scaffolds this directory; ksail cluster create and ksail cluster update load every patch from it, classify the impact (in-place, reboot-required, or wipe-required), and apply them with the matching Talos SDK mode.
Patches live in three role-scoped subdirectories:
talos/ # spec.cluster.distributionConfig (talos-local for local)├── cluster/ # applied to ALL nodes│ ├── disable-default-cni.yaml # hand CNI to KSail (e.g. Cilium)│ ├── oidc.yaml # OIDC issuer / API server auth│ ├── disk-encryption.yaml # STATE/EPHEMERAL partition encryption│ ├── image-verification.yaml # ImageVerificationConfig (Talos 1.13+)│ └── sysctls.yaml # machine.sysctls, install image, extensions├── control-planes/ # applied to control-plane nodes only│ └── ingress-firewall-rules.yaml # control-plane firewall rules└── workers/ # applied to worker nodes only ├── node-labels.yaml # machine.nodeLabels └── storage.yaml # disk / storage preparationOne concern per file keeps configuration isolated and reviewable. The filenames above are illustrative — add, rename, or remove patches to suit your cluster. For the full patch-authoring workflow and the ksail.yaml fields it replaces, see Talos Native Patches; for a worked partition-encryption example, see Talos Disk Encryption. The directory also fits the broader Project Structure conventions.
Version Pinning
Section titled “Version Pinning”Production clusters commonly pin versions for reproducibility. Set them in ksail.yaml (or override per run with --kubernetes-version / --distribution-version):
# Partial snippet — add to your existing ksail.yamlspec: cluster: distribution: Talos kubernetesVersion: v1.35.1 # Kubernetes version talos: version: v1.13.3 # Talos OS version (unset = latest supported) extensions: # Image Factory schematic (optional) - siderolabs/iscsi-tools - siderolabs/util-linux-tools - siderolabs/qemu-guest-agentspec.cluster.talos.extensions builds an Image Factory schematic so system extensions (for example iscsi-tools for storage, or qemu-guest-agent on cloud providers) are baked into the boot image. On the Hetzner provider you additionally pin an image/ISO id — see the Hetzner Provider page. See the CLI flag reference for every init/create/update flag.
Use Cases
Section titled “Use Cases”See Use Cases for practical workflow examples with Talos.
Common Talos API Operations
Section titled “Common Talos API Operations”talosctl -n <node-ip> get machineconfig # View configurationtalosctl -n <node-ip> version # Check Talos versiontalosctl -n <node-ip> logs # System logsArchitecture
Section titled “Architecture”Talos node architecture varies by provider. See the Docker Provider, Hetzner Provider, and Omni Provider pages for details.
Distribution Comparison
Section titled “Distribution Comparison”See the Support Matrix for a full breakdown of feature and component compatibility across all distributions.
Troubleshooting
Section titled “Troubleshooting”Cluster Creation Fails
Section titled “Cluster Creation Fails”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.
Nodes Not Ready
Section titled “Nodes Not Ready”- Check CNI pods are running:
kubectl get pods -n kube-systemand look for your CNI pods, e.g.cilium-orcalico-. - Verify Talos health:
talosctl -n <node-ip> health. - Reinstall CNI with
ksail cluster update.
LoadBalancer Not Working (Docker)
Section titled “LoadBalancer Not Working (Docker)”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)).
Cannot Access Talos API
Section titled “Cannot Access Talos API”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.
Advanced Topics
Section titled “Advanced Topics”Custom Node Counts
Section titled “Custom Node Counts”Adjust control plane and worker nodes in your existing ksail.yaml (requires distribution: Talos):
# Partial snippet — add to your existing ksail.yamlspec: cluster: distribution: Talos controlPlanes: 3 # HA setup workers: 5Node Autoscaling (Hetzner)
Section titled “Node Autoscaling (Hetzner)”On the Hetzner provider, KSail can run the Kubernetes Cluster Autoscaler so worker nodes scale with demand. Configure pools under spec.cluster.autoscaler.node:
# Partial snippet — add to your existing ksail.yaml (Talos + Hetzner)spec: cluster: distribution: Talos autoscaler: node: enabled: true expander: LeastWaste # single value, or a priority list e.g. [LeastNodes, LeastWaste] (Price is not supported for Hetzner) maxNodesTotal: 10 # cap across all pools pools: - name: workers serverType: cpx21 # Hetzner server type min: 1 max: 5See the Hetzner Provider page for the autoscaler prerequisites and the CLI flag reference for the corresponding flags.
Port Mappings (Docker Provider)
Section titled “Port Mappings (Docker Provider)”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.yamlspec: cluster: distribution: Talos talos: extraPortMappings: - containerPort: 80 hostPort: 8080 protocol: TCP - containerPort: 443 hostPort: 8443 protocol: TCPAccess 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.
Persistent Storage (Hetzner)
Section titled “Persistent Storage (Hetzner)”For cloud volumes, use the hcloud-volumes storage class installed automatically by the Hetzner Provider.
Talos Upgrades
Section titled “Talos Upgrades”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.
# Follow the latest supported Talos versionksail cluster update
# Pin a specific Talos OS versionksail cluster update --distribution-version v1.13.3KSail 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.
For manual upgrades outside of KSail, see the Talos upgrade docs.
Image Verification (Talos 1.13+)
Section titled “Image Verification (Talos 1.13+)”Talos 1.13 introduced ImageVerificationConfig, which enforces machine-wide container image signature verification before any image is pulled. KSail can scaffold a starter configuration:
ksail project init \ --distribution Talos \ --image-verification EnabledThis 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: v1alpha1kind: ImageVerificationConfigrules: # 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 # - image: "registry.k8s.io/*" # keyless: # issuer: "https://accounts.google.com" # subject: "krel-trust@k8s-releng-prod.iam.gserviceaccount.com" # 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: trueEdit the file to enforce your signature policy, then run ksail cluster create.
See the Talos image verification docs for the full rule schema.
Environment Variables (EnvironmentConfig)
Section titled “Environment Variables (EnvironmentConfig)”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), add an EnvironmentConfig document as a new patch in your machine-config directory (see Configuration):
apiVersion: v1alpha1kind: EnvironmentConfigenvironment: 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 in the cluster/ subdirectory so it applies to all nodes (e.g. talos/cluster/environment.yaml); KSail loads it alongside the other patches during cluster creation.
GitOps Integration
Section titled “GitOps Integration”Enable Flux or ArgoCD for declarative workload management—see GitOps Workflows.