Vanilla (Kind)
Kind (Kubernetes in Docker) runs upstream Kubernetes clusters using Docker containers as nodes. It is fast (30–60 s), needs only Docker, and uses standard kind.yaml files with no vendor lock-in. On the Hetzner provider, Vanilla clusters run upstream Kubernetes with kubeadm on Hetzner Cloud servers instead of Kind. For common workflows and use cases, see Use Cases.
Quick Start
Section titled “Quick Start”Requires Docker (installation prerequisites).
ksail project init --name my-cluster --distribution Vanilla --control-planes 1 --workers 2ksail cluster createksail cluster info && kubectl get nodes # verifyksail cluster delete # cleanupksail project init creates ksail.yaml (KSail config) and kind.yaml (Kind cluster config).
Configuration
Section titled “Configuration”Basic Configuration
Section titled “Basic Configuration”The ksail.yaml file controls your cluster:
# yaml-language-server: $schema=https://raw.githubusercontent.com/devantler-tech/ksail/main/schemas/ksail-config.schema.jsonapiVersion: ksail.io/v1alpha1kind: Clusterspec: cluster: distribution: Vanilla distributionConfig: kind.yamlKind-Specific Configuration
Section titled “Kind-Specific Configuration”Customize Kind behavior in kind.yaml:
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes: - role: control-plane # Port mapping for accessing services extraPortMappings: - containerPort: 80 hostPort: 8080 protocol: TCP - role: worker - role: workerLoadBalancer Support
Section titled “LoadBalancer Support”Enable LoadBalancer services with Cloud Provider KIND:
apiVersion: ksail.io/v1alpha1kind: Clusterspec: cluster: distribution: Vanilla loadBalancer: EnabledWhen enabled, KSail installs Cloud Provider KIND, which creates cpk-* Docker containers as LoadBalancer proxies and assigns external IPs. See LoadBalancer Configuration for details.
Registry Mirrors
Section titled “Registry Mirrors”KSail enables docker.io, ghcr.io, quay.io, and registry.k8s.io mirrors by default. The --mirror-registry flag uses replace semantics: any values you provide completely replace the full default list, so omitting a registry removes it. To customize mirrors while keeping the defaults, include all four:
ksail project init --name my-cluster --distribution Vanilla \ --mirror-registry 'docker.io=https://registry-1.docker.io' \ --mirror-registry 'ghcr.io=https://ghcr.io' \ --mirror-registry 'quay.io=https://quay.io' \ --mirror-registry 'registry.k8s.io=https://registry.k8s.io'Troubleshooting
Section titled “Troubleshooting”1. Cluster Creation Fails
Section titled “1. Cluster Creation Fails”Symptom: ksail cluster create fails with Docker errors.
docker ps # Verify Docker is runningdf -h # Check disk spacedocker system prune -fksail cluster create2. Nodes Not Ready
Section titled “2. Nodes Not Ready”Symptom: kubectl get nodes shows NotReady status.
kubectl describe node <node-name>kubectl get pods -n kube-system | grep ciliumkubectl rollout restart daemonset/cilium -n kube-system3. LoadBalancer Stuck in Pending
Section titled “3. LoadBalancer Stuck in Pending”Symptom: LoadBalancer service never gets EXTERNAL-IP. Ensure loadBalancer: Enabled is set in ksail.yaml, then run ksail cluster update. See LoadBalancer Configuration.
4. Port Already in Use
Section titled “4. Port Already in Use”Symptom: address already in use error during cluster creation. List and delete conflicting Kind clusters:
kind get clusterskind delete cluster --name <conflicting-cluster>5. Out of Memory or Disk Space
Section titled “5. Out of Memory or Disk Space”Symptom: Cluster creation fails with resource errors.
ksail project init --name my-cluster --distribution Vanilla --control-planes 1 --workers 0# WARNING: removes ALL unused images and volumes — can affect other Docker projectsdocker system prune -a --volumesAdvanced Topics
Section titled “Advanced Topics”Multi-Node Clusters
Section titled “Multi-Node Clusters”Create production-like topologies:
ksail project init --name multi-node --distribution Vanilla --control-planes 3 --workers 5Kubernetes Version Selection
Section titled “Kubernetes Version Selection”Set the node image in kind.yaml to pin a Kubernetes version. Check Kind release notes for available images. Edit the nodes: section of the generated kind.yaml:
# kind.yaml (partial — nodes: section)nodes: - role: control-plane image: kindest/node:v1.35.1 - role: worker image: kindest/node:v1.35.1Custom CNI
Section titled “Custom CNI”Override the default CNI:
ksail project init --name my-cluster --distribution Vanilla --cni CalicoPort Mappings
Section titled “Port Mappings”Expose services on host ports. Edit the nodes: section of the generated kind.yaml:
# kind.yaml (partial — nodes: section)nodes: - role: control-plane extraPortMappings: - containerPort: 30080 # NodePort service hostPort: 8080 protocol: TCPAccess services at http://localhost:8080.
Storage Configuration
Section titled “Storage Configuration”Enable persistent storage:
ksail project init --name my-cluster --distribution Vanilla --csi EnabledImage Verification
Section titled “Image Verification”Enable containerd image signature verification via the io.containerd.image-verifier.v1.bindir plugin:
ksail project init --name my-cluster --distribution Vanilla --image-verification EnabledThis injects a containerdConfigPatches entry into kind.yaml that activates the plugin at bin_dir = "/opt/image-verifier/bin" on every node. Verification only runs when verifier binaries (e.g., Cosign, Notation) are pre-installed in a custom Kind node image at that path — if the directory is absent or empty, image pulls proceed without verification.
Requirements:
- containerd 2.x (Kind
v0.31.0+/kindest/node:v1.35.1+) - Custom Kind node image with verifier binaries pre-installed at
/opt/image-verifier/bin
Integration with Native Kind
Section titled “Integration with Native Kind”The kind.yaml generated by ksail project init is standard Kind config — use it directly without KSail:
kind create cluster --config kind.yamlkind export kubeconfig