Skip to content

Declarative Configuration

KSail uses declarative YAML configuration files for reproducible cluster setup. This page describes ksail.yaml — the project-level configuration file that defines your cluster’s desired state.

Each KSail project includes a ksail.yaml file describing the cluster and workload configuration. Run ksail cluster init to generate this file, which can be committed to version control and shared with your team.

The configuration file uses the ksail.io/v1alpha1 API version and follows the Cluster kind schema. It defines:

  • Cluster settings: distribution, networking, components
  • Connection details: kubeconfig path, context, timeouts
  • Workload configuration: manifest directory, validation preferences
  • Editor preferences: for interactive workflows

KSail supports environment variable expansion in all string configuration values using the ${VAR_NAME} syntax. This enables:

  • Secure credential management: Keep sensitive values out of version control
  • Environment-specific configuration: Use different values per environment (dev/staging/prod)
  • Dynamic path resolution: Reference user-specific or system-specific paths

Basic syntax: ${VARIABLE_NAME} — Reference an environment variable. If not set, expands to an empty string and logs a warning.

Default value syntax: ${VARIABLE_NAME:-default} — Use a default value if the variable is not set. No warning is logged when using defaults.

spec:
editor: "${EDITOR:-vim}" # Uses 'vim' if EDITOR is not set
cluster:
connection:
kubeconfig: "${HOME}/.kube/config"
context: "${KUBE_CONTEXT:-kind-kind}"
distributionConfig: "${CONFIG_DIR:-configs}/kind.yaml"
localRegistry:
registry: "${REGISTRY:-localhost:5000}"
vanilla:
mirrorsDir: "${MIRRORS_DIR:-mirrors}"
talos:
config: "${TALOS_CONFIG_PATH:-~/.talos/config}"
hetzner:
sshKeyName: "${HCLOUD_SSH_KEY}"
workload:
sourceDirectory: "${WORKLOAD_DIR:-k8s}"
chat:
model: "${CHAT_MODEL:-gpt-4o}"
SyntaxVariable SetVariable Not Set
${VAR}Uses valueEmpty string + warning
${VAR:-default}Uses valueUses default (no warning)
${VAR:-}Uses valueEmpty string (no warning)

Environment variables are expanded in:

  1. ksail.yaml — All supported string fields (see below)
  2. Distribution configskind.yaml, k3d.yaml file contents
  3. Talos patches — All YAML patch files in talos/cluster/, talos/control-planes/, talos/workers/

This means you can use ${VAR} syntax inside your Kind, K3d, or Talos configuration files too:

# kind.yaml - Environment variables are expanded before parsing
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."${REGISTRY:-localhost:5000}"]
endpoint = ["http://${REGISTRY:-localhost:5000}"]
# talos/cluster/registry.yaml - Environment variables are expanded
machine:
registries:
mirrors:
docker.io:
endpoints:
- http://${REGISTRY:-localhost:5000}

Environment variable expansion works in these string fields:

General:

  • spec.editor - Editor command
  • spec.cluster.connection.kubeconfig - Kubeconfig path
  • spec.cluster.connection.context - Kubernetes context name
  • spec.cluster.distributionConfig - Distribution config path
  • spec.cluster.localRegistry.registry - Registry specification (including credentials)
  • spec.workload.sourceDirectory - Workload manifest directory
  • spec.chat.model - Chat model name

Distribution-specific:

  • spec.cluster.vanilla.mirrorsDir - Mirror configuration directory
  • spec.cluster.talos.config - Talos configuration path

Provider-specific:

  • spec.cluster.hetzner.sshKeyName - SSH key name
  • spec.cluster.hetzner.networkName - Network name
  • spec.cluster.hetzner.placementGroup - Placement group name
spec:
cluster:
localRegistry:
# Expand registry credentials from environment variables
registry: "${REGISTRY_USER}:${REGISTRY_PASS}@${REGISTRY_HOST:-ghcr.io}/myorg/myrepo"
Terminal window
export REGISTRY_USER="github-user"
export REGISTRY_PASS="ghp_secrettoken123"
# REGISTRY_HOST not set, defaults to ghcr.io
ksail cluster create
spec:
cluster:
connection:
context: "${CLUSTER_NAME:-kind-kind}"
distributionConfig: "${ENV:-dev}/kind.yaml"
workload:
sourceDirectory: "${ENV:-dev}/k8s"
Terminal window
# Development (using defaults)
ksail cluster create
# Production (override with environment variables)
export ENV="prod"
export CLUSTER_NAME="prod-cluster"
ksail cluster create

Example: Distribution Config with Variables

Section titled “Example: Distribution Config with Variables”

Environment variables also work inside distribution configuration files:

kind.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: ${INGRESS_PORT:-80}
hostPort: ${HOST_PORT:-8080}
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."${MIRROR_REGISTRY:-docker.io}"]
endpoint = ["http://${REGISTRY:-localhost:5000}"]
talos/cluster/registry.yaml
machine:
registries:
mirrors:
docker.io:
endpoints:
- http://${REGISTRY:-localhost:5000}
# yaml-language-server: $schema=https://raw.githubusercontent.com/devantler-tech/ksail/main/schemas/ksail-config.schema.json
apiVersion: ksail.io/v1alpha1
kind: Cluster
spec:
cluster:
distribution: Vanilla
distributionConfig: kind.yaml

This minimal configuration creates a Vanilla cluster (implemented with Kind) using defaults for all other settings.

# yaml-language-server: $schema=https://raw.githubusercontent.com/devantler-tech/ksail/main/schemas/ksail-config.schema.json
apiVersion: ksail.io/v1alpha1
kind: Cluster
spec:
editor: code --wait
cluster:
distribution: Vanilla
distributionConfig: kind.yaml
connection:
kubeconfig: ~/.kube/config
context: kind-kind
timeout: 5m
cni: Cilium
# CSI "Default" uses the distribution × provider's default behavior:
# - K3s: includes local-path-provisioner by default
# - Vanilla and Talos × Docker: no CSI installed; use Enabled if needed
# - Talos × Hetzner: includes Hetzner CSI driver by default
csi: Default
metricsServer: Enabled
certManager: Enabled
policyEngine: Kyverno
localRegistry: Enabled
gitOpsEngine: Flux
localRegistryOptions:
hostPort: 5050
workload:
sourceDirectory: k8s
validateOnPush: true
FieldTypeRequiredDescription
apiVersionstringYesMust be ksail.io/v1alpha1
kindstringYesMust be Cluster
specobjectYesCluster and workload specification (see below)

The spec field is a Spec object that defines editor, cluster, and workload configuration.

FieldTypeDefaultDescription
editorstringEditor command for interactive workflows
clusterClusterSpecCluster configuration (distribution, components)
workloadWorkloadSpecWorkload manifest configuration

Editor command used by KSail for interactive workflows like ksail cipher edit or ksail workload edit.

Examples: code --wait, vim, nano

If not specified, KSail falls back to standard editor environment variables (SOPS_EDITOR, KUBE_EDITOR, EDITOR, VISUAL) or system defaults (vim, nano, vi).

FieldTypeDefaultDescription
distributionenumVanillaKubernetes distribution to use
providerenumDockerInfrastructure provider (Docker, Hetzner)
distributionConfigstring(see below)Path to distribution-specific configuration
connectionConnectionCluster connection settings
cnienumDefaultContainer Network Interface
csienumDefaultContainer Storage Interface
metricsServerenumDefaultInstall metrics-server
certManagerenumDisabledInstall cert-manager
policyEngineenumNonePolicy engine to install
localRegistryLocalRegistryRegistry configuration (see below)
gitOpsEngineenumNoneGitOps engine to install
mirrorRegistries[]stringMirror registry specifications
kindobjectKind-specific options (Vanilla distribution)
k3dobjectK3d-specific options (K3s distribution)
talosobjectTalos-specific options
hetznerobjectHetzner Cloud provider options
ciliumobjectCilium CNI options
calicoobjectCalico CNI options
fluxobjectFlux GitOps options
argocdobjectArgoCD GitOps options
helmobjectHelm tool options (reserved)
kustomizeobjectKustomize tool options (reserved)

Kubernetes distribution to use for the local cluster. See Distributions for detailed information about each distribution.

Valid values:

  • Vanilla (default) – Standard upstream Kubernetes (implemented with Kind)
  • K3s – Lightweight Kubernetes (implemented with K3d)
  • TalosTalos Linux in Docker containers or Hetzner Cloud servers

Infrastructure provider for running cluster nodes. See Providers for more details.

Valid values:

  • Docker (default) – Run nodes as Docker containers (local development)
  • Hetzner – Run nodes on Hetzner Cloud servers (requires HCLOUD_TOKEN)

Path to the distribution-specific configuration file or directory. This tells KSail where to find settings like node counts, port mappings, and distribution-specific features.

Default values by distribution:

  • Vanillakind.yaml
  • K3sk3d.yaml
  • Talostalos/ (directory)

See Distribution Configuration below for details on each format.

FieldTypeDefaultDescription
kubeconfigstring~/.kube/configPath to kubeconfig file
contextstring(derived)Kubeconfig context name
timeoutdurationTimeout for cluster operations

Context defaults by distribution:

  • Vanillakind-kind
  • K3sk3d-k3d-default
  • Talosadmin@talos-default

Timeout format: Go duration string (e.g., 30s, 5m, 1h)

Container Network Interface to install. See CNI for more details.

Valid values:

  • Default – Uses the distribution’s built-in CNI (kindnetd for Vanilla, flannel for K3s)
  • Cilium – Installs Cilium for advanced networking and observability
  • Calico – Installs Calico for network policies

Container Storage Interface to install. See CSI for more details.

Valid values:

  • Default – Uses the distribution × provider’s default behavior:
    • K3s: includes local-path-provisioner
    • Vanilla/Talos × Docker: no CSI
    • Talos × Hetzner: includes Hetzner CSI driver
  • Enabled – Explicitly installs CSI driver (local-path-provisioner for local clusters, Hetzner CSI for Talos × Hetzner)
  • Disabled – Disables CSI installation (for K3s, this disables the default local-storage)

Whether to install metrics-server for resource metrics.

Valid values:

  • Default (default) – Uses distribution’s default behavior (K3s includes metrics-server; Vanilla and Talos do not)
  • Enabled – Install metrics-server
  • Disabled – Skip installation

When metrics-server is enabled on Vanilla or Talos, KSail automatically:

  1. Configures kubelet certificate rotation (serverTLSBootstrap: true)
  2. Installs kubelet-csr-approver to approve certificate requests
  3. Deploys metrics-server with secure TLS communication

Whether to install cert-manager for TLS certificate management.

Valid values:

  • Enabled – Install cert-manager
  • Disabled (default) – Skip installation

Policy engine to install for enforcing security, compliance, and best practices. See Policy Engines for more details about Kyverno and Gatekeeper.

Valid values:

  • None (default) – No policy engine
  • Kyverno – Install Kyverno for Kubernetes-native policy management
  • Gatekeeper – Install OPA Gatekeeper for OPA-based policy enforcement

Registry configuration for GitOps workflows. Supports local Docker registries or external registries with authentication.

Format: [user:pass@]host[:port][/path]

Examples:

  • localhost:5050 – Local Docker registry
  • ghcr.io/myorg/myrepo – GitHub Container Registry
  • ${USER}:${PASS}@ghcr.io:443/myorg – With credentials from environment variables

GitOps engine to install for continuous deployment workflows. See GitOps for more details about Flux and ArgoCD. When set to Flux or ArgoCD, KSail scaffolds a GitOps CR (FluxInstance or ArgoCD Application) into your source directory at gitops/flux/flux-instance.yaml or gitops/argocd/application.yaml.

Valid values:

  • None (default) – No GitOps engine
  • Flux – Install Flux CD and scaffold FluxInstance CR
  • ArgoCD – Install Argo CD and scaffold Application CR

Advanced configuration options are direct fields under spec.cluster. See Schema Support for the complete structure.

Talos options (spec.cluster.talos):

  • controlPlanes – Number of control-plane nodes (default: 1)
  • workers – Number of worker nodes (default: 0)
  • config – Path to talosconfig file (default: ~/.talos/config)
  • iso – Cloud provider ISO/image ID for Talos Linux (default: 122630 for x86)

Hetzner options (spec.cluster.hetzner):

  • controlPlaneServerType – Server type for control-plane nodes (default: cx23)
  • workerServerType – Server type for worker nodes (default: cx23)
  • location – Datacenter location: fsn1, nbg1, hel1 (default: fsn1)
  • networkName – Private network name (default: <cluster>-network)
  • networkCidr – Network CIDR block (default: 10.0.0.0/16)
  • sshKeyName – SSH key name for server access (optional)
  • tokenEnvVar – Environment variable for API token (default: HCLOUD_TOKEN)

Kind options (spec.cluster.kind):

  • mirrorsDir – Directory for containerd host mirror configuration
FieldTypeDefaultDescription
sourceDirectorystringk8sDirectory containing Kubernetes manifests
validateOnPushbooleanfalseValidate manifests before pushing to registry

KSail references distribution-specific configuration files to customize cluster behavior. The path to these files is set via spec.cluster.distributionConfig.

Vanilla (implemented with Kind) Configuration

Section titled “Vanilla (implemented with Kind) Configuration”

Default: kind.yaml

The Vanilla distribution is configured via a YAML file following the Kind configuration schema. This allows you to customize:

  • Node images and versions
  • Extra port mappings
  • Extra mounts
  • Networking settings

Documentation: Kind Configuration

Example:

kind.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000

Default: k3d.yaml

The K3s distribution is configured via a YAML file following the K3d configuration schema. This allows you to customize:

  • Server and agent counts
  • Port mappings
  • Volume mounts
  • Registry configurations

Documentation: K3d Configuration

Example:

k3d.yaml
apiVersion: k3d.io/v1alpha5
kind: Simple
servers: 1
agents: 2
ports:
- port: 8080:80
nodeFilters:
- loadbalancer

Default: talos/ directory

Talos uses a directory structure for Talos machine configuration patches. Each directory contains YAML patch files that modify the Talos machine configuration.

Documentation: Talos Configuration Reference

Directory structure and examples:

talos/cluster/kubelet.yaml
# Patches applied to all nodes
machine:
kubelet:
extraArgs:
max-pods: "250"
talos/control-planes/api.yaml
# Patches for control-plane nodes only
machine:
kubelet:
extraArgs:
feature-gates: "EphemeralContainers=true"
talos/workers/custom.yaml
# Patches for worker nodes only
machine:
sysctls:
net.core.somaxconn: "65535"

Use spec.cluster.talos to configure node counts:

spec:
cluster:
distribution: Talos
distributionConfig: talos
talos:
controlPlanes: 3
workers: 2

KSail provides a JSON Schema for IDE validation and autocompletion. Reference it at the top of your ksail.yaml:

# yaml-language-server: $schema=https://raw.githubusercontent.com/devantler-tech/ksail/main/schemas/ksail-config.schema.json
apiVersion: ksail.io/v1alpha1
kind: Cluster
spec:
# ...

IDEs with YAML language support (like VS Code with the Red Hat YAML extension) will provide:

  • Field autocompletion
  • Inline documentation
  • Validation errors for invalid values
  • Enum suggestions for fields like distribution, cni, etc.