K3s (K3d)
K3s is a lightweight, certified Kubernetes distribution for resource-constrained environments. K3d runs K3s clusters in Docker containers — each node is a container, with a dedicated load balancer container routing traffic to control planes — providing fast 15–30 s cluster creation with batteries-included defaults (ServiceLB, local-path-provisioner, metrics-server), standard k3d.yaml files, and no vendor lock-in.
K3s (K3d) is ideal for quick local development, CI/CD pipelines with ephemeral clusters, resource-constrained machines or CI runners, and multi-node topology testing.
Quick Start
Section titled “Quick Start”Requires Docker (installation prerequisites).
ksail cluster init --name my-cluster --distribution K3s --control-planes 1 --workers 2ksail cluster createksail cluster info && kubectl get nodes # verifyksail cluster delete # cleanupksail cluster init creates ksail.yaml (KSail config) and k3d.yaml (K3d cluster config).
Configuration
Section titled “Configuration”Basic Configuration
Section titled “Basic Configuration”# yaml-language-server: $schema=https://raw.githubusercontent.com/devantler-tech/ksail/main/schemas/ksail-config.schema.jsonapiVersion: ksail.io/v1alpha1kind: Clusterspec: cluster: distribution: K3s distributionConfig: k3d.yamlK3d-Specific Configuration
Section titled “K3d-Specific Configuration”apiVersion: k3d.io/v1alpha5kind: Simpleservers: 1 # control-plane nodesagents: 2 # worker nodesports: - port: 8080:80@loadbalancerBuilt-in Components
Section titled “Built-in Components”K3s includes these components by default—KSail does not reinstall them:
| Component | Notes |
|---|---|
| ServiceLB (Klipper-LB) | LoadBalancer support via host ports |
| local-path-provisioner | Dynamic PersistentVolume provisioning |
| Metrics Server | kubectl top and HPA support |
| CoreDNS | Cluster DNS |
| Traefik | Ingress controller (can be disabled) |
Registry Mirrors
Section titled “Registry Mirrors”Configure registry mirrors to avoid rate limits. KSail enables docker.io, ghcr.io, quay.io, and registry.k8s.io mirrors by default. Override with --mirror-registry flags:
ksail cluster init --name my-cluster --distribution K3s \ --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'K3d injects registry configuration so all nodes use your mirrors automatically.
Troubleshooting
Section titled “Troubleshooting”1. Cluster Creation Fails
Section titled “1. Cluster Creation Fails”Symptom: ksail cluster create fails with Docker errors.
docker ps # Check Docker is runningdf -h # Check available disk spacedocker system prune -f # WARNING: removes unused containers, networks, images, and build cacheksail 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-systemksail cluster delete && ksail cluster create3. LoadBalancer Stuck in Pending
Section titled “3. LoadBalancer Stuck in Pending”K3s uses ServiceLB (Klipper-LB), which binds to host ports. Ensure the port is not already in use and update ports in k3d.yaml (e.g., 9080:80@loadbalancer) if needed.
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep k3d4. Port Already in Use
Section titled “4. Port Already in Use”Symptom: address already in use error during cluster creation.
k3d cluster listk3d cluster delete <cluster-name># Or initialize with a different name:ksail cluster init --name my-cluster-2 --distribution K3s5. Out of Memory or Disk Space
Section titled “5. Out of Memory or Disk Space”Reduce node count in ksail.yaml (workers: 0 for a single-node cluster) and run docker system prune. Increase Docker Desktop resources under Settings → Resources.
Advanced Topics
Section titled “Advanced Topics”Worker Node Scaling
Section titled “Worker Node Scaling”Unlike Vanilla (Kind), K3s supports in-place worker node scaling. Update agents in k3d.yaml and run ksail cluster update to add or remove worker containers without recreation.
Disabling Built-in Components
Section titled “Disabling Built-in Components”options: k3s: extraArgs: - arg: --disable=traefik # Remove Traefik ingress nodeFilters: ["server:*"] - arg: --disable=servicelb # Remove ServiceLB (use MetalLB instead) nodeFilters: ["server:*"]Custom CNI
Section titled “Custom CNI”spec: cluster: cni: CiliumWhen cni: Cilium is set, KSail automatically passes --flannel-backend=none, --disable-network-policy, and --disable=traefik to the K3s server. Traefik is disabled because Cilium installs Gateway API CRDs (e.g. backendtlspolicies.gateway.networking.k8s.io) that conflict with Traefik’s CRD ownership, causing the K3s helm-install-traefik pod to enter CrashLoopBackOff. You do not need to add these flags manually in k3d.yaml.
Kubernetes Version
Section titled “Kubernetes Version”K3s version is determined by the K3d image. Pin a specific version in k3d.yaml (see K3d image tags):
image: rancher/k3s:v1.35.3-k3s1Port Mappings
Section titled “Port Mappings”ports: - port: 8080:80@loadbalancer # HTTP - port: 8443:443@loadbalancer # HTTPS - port: 30080:30080@agent:0 # NodePort on first workerIntegration with Native K3d
Section titled “Integration with Native K3d”KSail generates standard k3d.yaml files—use K3d CLI directly (k3d cluster create --config k3d.yaml) if needed. No vendor lock-in: configurations are portable and KSail can interact with any K3d cluster accessible via your kubeconfig.