Getting Started with K3s (K3d)
K3s is a lightweight, certified Kubernetes distribution designed for resource-constrained environments. KSail uses K3d to run K3s clusters in Docker containers, giving you fast cluster creation with batteries-included defaults like a built-in load balancer, local storage provisioner, and metrics server.
What is K3s (K3d)?
Section titled βWhat is K3s (K3d)?βK3s is a minimal Kubernetes distribution that bundles everything needed into a single binary. K3d wraps K3s in Docker containers so you can run full clusters locally. Together they offer:
- Minimal footprint: Single-binary K3s uses less memory and CPU than upstream Kubernetes
- Batteries included: ServiceLB, local-path-provisioner, and metrics-server are built in
- Fast cluster creation: Clusters ready in 15β30 seconds
- Docker-only: Runs entirely in Docker containers (no VM overhead)
- Multi-node support: Simulate production topologies locally
- Native configuration: Uses standard
k3d.yamlfiles (no lock-in)
When to Use K3s
Section titled βWhen to Use K3sβK3s (K3d) is ideal for:
- Quick local development: Fast iteration without heavyweight infrastructure
- Resource-constrained machines: Laptops or CI runners with limited CPU/RAM
- CI/CD pipelines: Ephemeral test clusters that start in seconds
- Edge and IoT prototyping: K3s targets resource-constrained deployments by design
- Multi-node testing: Simulate production topologies with workers
When NOT to Use K3s
Section titled βWhen NOT to Use K3sβConsider alternatives if you need:
- 100% upstream compatibility: K3s omits some alpha/beta APIs; Vanilla (Kind) uses unmodified Kubernetes
- Production immutability: Talos offers immutable infrastructure and enhanced security
- Virtual cluster isolation: VCluster provides tenant isolation without separate nodes
- Cloud deployments: Talos supports Hetzner Cloud; K3s currently only supports Docker locally
Quick Start
Section titled βQuick StartβCreate your first K3s cluster in under 30 seconds.
Prerequisites
Section titled βPrerequisitesβ- Docker Desktop or Docker Engine installed and running
docker pscommand works
Step 1: Initialize Project
Section titled βStep 1: Initialize Projectβksail cluster init \ --name my-cluster \ --distribution K3s \ --control-planes 1 \ --workers 2This creates:
ksail.yamlβ KSail configurationk3d.yamlβ K3d-specific cluster configuration
Step 2: Create Cluster
Section titled βStep 2: Create Clusterβksail cluster createKSail will:
- Generate K3d configuration from
ksail.yaml - Create Docker containers as Kubernetes nodes
- Install K3s inside the containers
- Configure kubectl context
- Apply additional components (cert-manager, policy engine, etc.) if configured
Expected output:
β Creating K3s cluster with K3d...β Cluster ready!
Cluster: my-clusterNodes: 3 (1 control plane, 2 workers)Provider: DockerStep 3: Verify Cluster
Section titled βStep 3: Verify Clusterβ# Check cluster infoksail cluster info
# View nodeskubectl get nodes
# Expected output:# NAME STATUS ROLES AGE VERSION# k3d-my-cluster-server-0 Ready control-plane,master 2m v1.31.x+k3s1# k3d-my-cluster-agent-0 Ready <none> 2m v1.31.x+k3s1# k3d-my-cluster-agent-1 Ready <none> 2m v1.31.x+k3s1Step 4: Deploy Sample Application
Section titled βStep 4: Deploy Sample Applicationβ# Create a deploymentkubectl create deployment nginx --image=nginx
# Expose as LoadBalancer (K3s ServiceLB assigns an IP automatically)kubectl expose deployment nginx --port=80 --type=LoadBalancer
# Verify β EXTERNAL-IP should appear within a few secondskubectl get svc nginxStep 5: Cleanup
Section titled βStep 5: Cleanupβ# Delete cluster and all resourcesksail cluster deleteConfiguration
Section titled βConfigurationβBasic Configuration
Section titled βBasic ConfigurationβThe ksail.yaml file controls your cluster:
apiVersion: ksail.io/v1alpha1kind: Clusterspec: cluster: name: my-cluster distribution: K3s provider: Docker controlPlanes: 1 workers: 2K3d-Specific Configuration
Section titled βK3d-Specific ConfigurationβCustomize K3d behavior in k3d.yaml:
apiVersion: k3d.io/v1alpha5kind: Simplemetadata: name: my-clusterservers: 1 # control-plane nodesagents: 2 # worker nodesports: - port: 8080:80@loadbalancer # Map host port 8080 to cluster port 80 - port: 8443:443@loadbalancer # Map host port 8443 to cluster port 443options: k3s: extraArgs: - arg: --disable=traefik # Disable built-in Traefik ingress nodeFilters: - server:*Built-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.
Common Use Cases
Section titled βCommon Use Casesβ1. Fast Local Development
Section titled β1. Fast Local DevelopmentβScenario: Develop a microservices application with rapid restart cycles.
# Single-node cluster (fastest startup)ksail cluster init --name dev --distribution K3s --workers 0ksail cluster create
# Deploy applicationkubectl apply -f k8s/
# Hot reload: rebuild image and restartdocker build -t my-app:dev .kubectl rollout restart deployment/my-appWhy K3s: Sub-30-second cluster startup, low memory footprint, built-in LoadBalancer.
2. CI/CD Integration Testing
Section titled β2. CI/CD Integration TestingβScenario: Run integration tests in ephemeral clusters on shared GitHub Actions runners.
# CI pipeline scriptksail cluster init --name ci-test --distribution K3sksail cluster create
# Run tests against the clusterkubectl apply -f test-manifests/./run-integration-tests.sh
# Cleanupksail cluster deleteWhy K3s: Fast creation, low resource usage ideal for constrained CI runners.
3. GitOps Testing (Flux/ArgoCD)
Section titled β3. GitOps Testing (Flux/ArgoCD)βScenario: Test GitOps configurations locally before production deployment.
# Initialize with GitOps and a local registryksail cluster init \ --name gitops-test \ --distribution K3s \ --gitops-engine Flux \ --local-registry
# Create, push manifests, and reconcileksail cluster createksail workload pushksail workload reconcile
# Verify reconciliationkubectl get kustomizations -AWhy K3s: Built-in storage and load balancer means fewer extra components to install.
4. Multi-Node Topology Testing
Section titled β4. Multi-Node Topology TestingβScenario: Test pod scheduling, node affinity, and high-availability patterns.
# 3-node cluster (1 control plane + 2 workers)ksail cluster init \ --name topology-test \ --distribution K3s \ --control-planes 1 \ --workers 2
ksail cluster create
# Label nodes and test affinitykubectl label nodes k3d-topology-test-agent-0 zone=us-east-1akubectl label nodes k3d-topology-test-agent-1 zone=us-east-1bWhy K3s: Worker nodes can be added/removed in-place with ksail cluster update.
Architecture
Section titled βArchitectureβCluster Components
Section titled βCluster Componentsβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Docker Host ββ ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ β K3d Load Balancer (Docker Container) β ββ β β’ Routes traffic to control-plane nodes β ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ ββ βββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ β Control Plane Node (Docker Container) β ββ β β’ k3s server process (includes all control- β ββ β plane components in one binary) β ββ β β’ etcd (embedded) β ββ β β’ ServiceLB (Klipper-LB) β ββ β β’ local-path-provisioner β ββ β β’ metrics-server β ββ βββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ ββ ββββββββββββββββββββ ββββββββββββββββββββ ββ β Worker Node 1 β β Worker Node 2 β ββ β β’ k3s agent β β β’ k3s agent β ββ β β’ containerd β β β’ containerd β ββ ββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββHow It Works
Section titled βHow It Worksβ- K3d Load Balancer: A dedicated container routes kubectl and API traffic to control-plane nodes
- Single Binary: K3s bundles all Kubernetes control-plane components into one process
- Embedded etcd: No separate etcd cluster needed for single-node or HA setups
- ServiceLB: Klipper-LB allocates node ports to back LoadBalancer services
- Storage: local-path-provisioner uses host-path volumes on the node
KSail Integration
Section titled βKSail Integrationβ- Provisioner:
pkg/svc/provisioner/cluster/k3d/wraps the K3d SDK - Infrastructure: Docker provider manages container lifecycle (start/stop)
- Configuration: Generates
k3d.yamlfromksail.yamldeclaratively - Installers: CNI (Cilium/Calico replaces default Flannel), cert-manager, policy engines
Distribution Comparison
Section titled βDistribution Comparisonβ| Feature | Vanilla (Kind) | K3s (K3d) | Talos | VCluster |
|---|---|---|---|---|
| Kubernetes Type | Upstream | Lightweight | Upstream | Virtual |
| Resource Usage | Medium | Low | Medium | Very Low |
| Startup Time | 30β60s | 15β30s | 60β90s | 10β20s |
| LoadBalancer | Cloud Provider KIND | ServiceLB (built-in) | MetalLB / hcloud-ccm | Host cluster LB |
| Storage | local-path (optional) | local-path (built-in) | Hetzner CSI / local-path | Host cluster storage |
| Metrics Server | Optional | Built-in | Optional | Host cluster |
| Production Ready | β Local only | β Local only | β Docker + Cloud | β Virtual only |
| Multi-Node | β Yes | β Yes | β Yes | β Single pod |
| Shell Access | β Docker exec | β Docker exec | β No shell | β kubectl exec |
| Worker Scale | Recreate | In-place | In-place | N/A |
| GitOps Support | β Full | β Full | β Full | β Full |
| Best For | Upstream K8s, testing | Quick dev, CI/CD | Production, security | Multi-tenancy |
Troubleshooting
Section titled βTroubleshootingβ1. Cluster Creation Fails
Section titled β1. Cluster Creation FailsβSymptom: ksail cluster create fails with Docker errors.
Solutions:
# Check Docker is runningdocker ps
# Check available disk spacedf -h
# Clean up unused containers and networksdocker system prune
# Retry cluster creationksail cluster create2. Nodes Not Ready
Section titled β2. Nodes Not ReadyβSymptom: kubectl get nodes shows NotReady status.
Solutions:
# Check node conditionskubectl describe node <node-name>
# Check system podskubectl get pods -n kube-system
# Restart K3d clusterksail cluster deleteksail cluster create3. LoadBalancer Stuck in Pending
Section titled β3. LoadBalancer Stuck in PendingβSymptom: LoadBalancer service never gets EXTERNAL-IP.
K3s uses ServiceLB (Klipper-LB) which binds to host ports. Ensure the port is not already in use:
# Check existing port bindingsdocker ps --format "table {{.Names}}\t{{.Ports}}" | grep k3d
# Use different ports in k3d.yamlports: - port: 9080:80@loadbalancer4. Port Already in Use
Section titled β4. Port Already in UseβSymptom: address already in use error during cluster creation.
Solutions:
# List existing K3d clustersk3d cluster list
# Delete conflicting clusterk3d cluster delete <cluster-name>
# Or initialize with a different nameksail cluster init --name my-cluster-2 --distribution K3s5. Out of Memory or Disk Space
Section titled β5. Out of Memory or Disk SpaceβSymptom: Cluster creation fails with resource errors.
Solutions:
# Reduce node count (K3s uses very little memory per node)# Edit ksail.yaml:spec: cluster: controlPlanes: 1 workers: 0 # Single-node cluster
# Clean up Dockerdocker system prune
# Increase Docker resources (Docker Desktop β 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:
# ksail.yaml β increase workersspec: cluster: workers: 4ksail cluster update # Adds/removes worker containers without recreationDisabling Built-in Components
Section titled βDisabling Built-in ComponentsβRemove K3s default components you donβt need:
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βReplace the default Flannel CNI with Cilium:
spec: cluster: cni: Cilium# k3d.yaml β disable built-in Flanneloptions: k3s: extraArgs: - arg: --flannel-backend=none nodeFilters: ["server:*"] - arg: --disable-network-policy nodeFilters: ["server:*"]Kubernetes Version
Section titled βKubernetes VersionβK3s version is determined by the K3d image. Pin a specific version in k3d.yaml:
image: rancher/k3s:v1.31.0-k3s1See K3d image tags for available versions.
Port Mappings
Section titled βPort MappingsβExpose services on host ports:
ports: - port: 8080:80@loadbalancer # HTTP - port: 8443:443@loadbalancer # HTTPS - port: 30080:30080@agent:0 # NodePort on first workerCluster Lifecycle Management
Section titled βCluster Lifecycle Managementβ# Stop cluster (preserves state)ksail cluster stop
# Start stopped clusterksail cluster start
# Scale workers in-placeksail cluster update # Apply changed worker count from ksail.yaml
# List all K3s clustersksail cluster list
# Get cluster detailsksail cluster infoIntegration with Native K3d
Section titled βIntegration with Native K3dβKSail generates standard k3d.yaml files:
# Use K3d CLI directlyk3d cluster create --config k3d.yaml
# List K3d clustersk3d cluster listNo vendor lock-in β configurations are portable and KSail can interact with any K3d cluster accessible via your kubeconfig.
Next Steps
Section titled βNext StepsβExplore KSail Features
Section titled βExplore KSail Featuresβ- GitOps Integration: Bootstrap Flux or ArgoCD
- Secret Management: Encrypt secrets with SOPS
- AI Chat: Interactive cluster management with GitHub Copilot
- VSCode Extension: Manage clusters from your editor
Try Other Distributions
Section titled βTry Other Distributionsβ- Vanilla (Kind): Upstream Kubernetes for maximum compatibility
- Talos: Immutable infrastructure for production
- VCluster: Virtual clusters for multi-tenancy
Learn More
Section titled βLearn Moreβ- Installation Guide: Install KSail on your system
- CLI Flags: Comprehensive command documentation
- Configuration Reference: Detailed YAML options
- LoadBalancer Configuration: LoadBalancer options for K3s
- Contributing: Contribute to KSail development