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.