Module 14.1: k3s - Lightweight Kubernetes for Edge
Цей контент ще не доступний вашою мовою.
Toolkit Track | Complexity:
[MEDIUM]| Time: 45-50 minutes
Overview
Section titled “Overview”k3s is Kubernetes that fits on a Raspberry Pi. Created by Rancher Labs (now SUSE), it packages all of Kubernetes into a ~60MB binary that runs on devices with as little as 512MB RAM. It’s not a toy—it’s a CNCF Sandbox project running production workloads at the edge of networks worldwide, from factory floors to retail stores to autonomous vehicles.
This module teaches you to deploy, configure, and operate k3s for edge and resource-constrained environments.
Prerequisites
Section titled “Prerequisites”- Kubernetes fundamentals (kubectl, deployments, services)
- Linux command-line basics
- Understanding of container runtimes (containerd)
- SSH access to at least one Linux machine (or VM)
What You’ll Be Able to Do
Section titled “What You’ll Be Able to Do”After completing this module, you will be able to:
- Deploy K3s clusters on edge devices and resource-constrained environments with automated installation
- Configure K3s with embedded etcd, Traefik ingress, and ServiceLB for production-ready lightweight clusters
- Implement multi-node K3s clusters with server and agent roles for HA edge deployments
- Evaluate K3s against standard Kubernetes for edge computing, IoT, and development environments
Why This Module Matters
Section titled “Why This Module Matters”Kubernetes is everywhere, but not everywhere can run Kubernetes.
Traditional Kubernetes requires:
- 2GB+ RAM for control plane
- Multiple machines for HA
- Complex etcd cluster management
- Significant operational overhead
Edge computing has different constraints:
- Limited RAM (512MB-2GB)
- Single nodes or small clusters
- Intermittent connectivity
- Minimal operational staff
k3s bridges this gap. It’s real Kubernetes—same APIs, same kubectl, same ecosystem—but packaged for environments where every megabyte matters.
Did You Know?
Section titled “Did You Know?”- Why “k3s”?: Kubernetes has 10 letters, often shortened to K8s (K + 8 letters + s). k3s has 5 letters—half of K8s, for “half the memory”
- Origin: Created by Rancher Labs founder Darren Shepherd in 2019
- Scale: Over 1 million nodes running k3s in production worldwide
- Certifications: k3s is CNCF certified Kubernetes—100% compatible
k3s Architecture
Section titled “k3s Architecture”k3s ARCHITECTURE DEEP DIVE─────────────────────────────────────────────────────────────────────────────
┌─────────────────────────────────────────────────────────────────────────────┐│ k3s Server Node ││ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ k3s Binary (~60MB) │ ││ │ │ ││ │ ┌──────────────────── Control Plane ───────────────────────┐ │ ││ │ │ │ │ ││ │ │ kube-apiserver kube-controller-manager kube-scheduler │ ││ │ │ ───────────────────────────────────────────────────────────── │ ││ │ │ tunnel-proxy (server) service-lb-controller │ ││ │ │ │ │ ││ │ └──────────────────────────────────────────────────────────┘ │ ││ │ │ ││ │ ┌──────────────────── Node Components ─────────────────────┐ │ ││ │ │ │ │ ││ │ │ kubelet kube-proxy containerd │ ││ │ │ │ │ ││ │ └──────────────────────────────────────────────────────────┘ │ ││ │ │ ││ │ ┌──────────────────── Bundled Components ──────────────────┐ │ ││ │ │ │ │ ││ │ │ Traefik CoreDNS Local Path Flannel │ ││ │ │ (Ingress) (DNS) (Storage) (CNI) │ ││ │ │ │ │ ││ │ │ ServiceLB Metrics Network Policy │ ││ │ │ (Load Balancer) Server Controller │ ││ │ │ │ │ ││ │ └──────────────────────────────────────────────────────────┘ │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ ││ ┌───────────────────────────────────────────────────────────────────────┐ ││ │ Datastore Options │ ││ │ │ ││ │ SQLite (default) │ etcd (HA) │ MySQL │ PostgreSQL │ ││ │ │ ││ └───────────────────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────────────────┘ │ ┌───────────────────────────┼───────────────────────────┐ │ │ │ ▼ ▼ ▼┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐│ k3s Agent Node │ │ k3s Agent Node │ │ k3s Agent Node ││ │ │ │ │ ││ ┌───────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────────┐ ││ │ k3s Binary │ │ │ │ k3s Binary │ │ │ │ k3s Binary │ ││ │ │ │ │ │ │ │ │ │ │ ││ │ kubelet │ │ │ │ kubelet │ │ │ │ kubelet │ ││ │ kube-proxy │ │ │ │ kube-proxy │ │ │ │ kube-proxy │ ││ │ containerd │ │ │ │ containerd │ │ │ │ containerd │ ││ │ flannel │ │ │ │ flannel │ │ │ │ flannel │ ││ └───────────────┘ │ │ └───────────────┘ │ │ └───────────────┘ ││ │ │ │ │ │└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
WHAT'S DIFFERENT FROM UPSTREAM K8S:─────────────────────────────────────────────────────────────────────────────
Removed:✗ Legacy, alpha, non-default features✗ In-tree cloud providers✗ In-tree storage drivers✗ Docker (uses containerd directly)
Added:✓ SQLite datastore (single node)✓ Embedded etcd (HA mode)✓ Tunnel proxy (agent communication)✓ ServiceLB (bare-metal load balancer)✓ Local Path Provisioner✓ Traefik Ingress Controller✓ Flannel CNI (by default)Installing k3s
Section titled “Installing k3s”Single Node Installation
Section titled “Single Node Installation”The fastest way to get started:
# Install k3s server (includes agent)curl -sfL https://get.k3s.io | sh -
# Check service statussudo systemctl status k3s
# Get kubeconfigsudo cat /etc/rancher/k3s/k3s.yaml
# Or use k3s kubectl directlysudo k3s kubectl get nodes
# Copy kubeconfig for regular usermkdir -p ~/.kubesudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/configsudo chown $USER ~/.kube/config
# Now use regular kubectlkubectl get nodesInstallation Options
Section titled “Installation Options”k3s supports many installation flags via environment variables:
# Install specific versioncurl -sfL https://get.k3s.io | INSTALL_K3S_VERSION="v1.28.5+k3s1" sh -
# Skip bundled componentscurl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik --disable servicelb" sh -
# Use different CNIcurl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--flannel-backend=none" sh -
# Enable secrets encryptioncurl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--secrets-encryption" sh -
# Custom data directorycurl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--data-dir=/opt/k3s" sh -Multi-Node Cluster
Section titled “Multi-Node Cluster”On the server node:
# Install server and get tokencurl -sfL https://get.k3s.io | sh -
# Get the node token (needed for agents)sudo cat /var/lib/rancher/k3s/server/node-tokenOn each agent node:
# Replace K3S_URL and K3S_TOKEN with actual valuescurl -sfL https://get.k3s.io | K3S_URL=https://server-ip:6443 K3S_TOKEN=your-node-token sh -
# Verify agent joinedkubectl get nodesHigh Availability Setup
Section titled “High Availability Setup”For production, deploy multiple server nodes:
HA k3s ARCHITECTURE─────────────────────────────────────────────────────────────────────────────
┌─────────────────────────────────────────┐ │ Load Balancer │ │ (HAProxy / cloud LB / DNS RR) │ │ api.k3s.example.com:6443 │ └─────────────────────┬───────────────────┘ │ ┌─────────────────────────┼─────────────────────────┐ │ │ │ ▼ ▼ ▼┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│ Server 1 │ │ Server 2 │ │ Server 3 ││ (init node) │◄───▶│ │◄───▶│ ││ │ │ │ │ ││ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ ││ │ embedded │◄─┼─────┼─▶│ embedded │◄─┼─────┼─▶│ embedded │ ││ │ etcd │ │ │ │ etcd │ │ │ │ etcd │ ││ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │└─────────────────┘ └─────────────────┘ └─────────────────┘
Option A: Embedded etcd (recommended for simplicity)Option B: External datastore (MySQL, PostgreSQL, etcd)Using embedded etcd (recommended):
# First server - initialize clustercurl -sfL https://get.k3s.io | sh -s - server \ --cluster-init \ --tls-san=api.k3s.example.com
# Get tokensudo cat /var/lib/rancher/k3s/server/token
# Second and third servers - join clustercurl -sfL https://get.k3s.io | sh -s - server \ --server https://first-server-ip:6443 \ --token <token-from-first-server> \ --tls-san=api.k3s.example.comUsing external datastore:
# All servers point to external datastorecurl -sfL https://get.k3s.io | sh -s - server \ --datastore-endpoint="mysql://user:password@tcp(host:3306)/k3s" \ --tls-san=api.k3s.example.com
# Or PostgreSQLcurl -sfL https://get.k3s.io | sh -s - server \ --datastore-endpoint="postgres://user:password@host:5432/k3s?sslmode=disable" \ --tls-san=api.k3s.example.comk3s Configuration
Section titled “k3s Configuration”Server Configuration File
Section titled “Server Configuration File”write-kubeconfig-mode: "0644"tls-san: - "api.k3s.example.com" - "192.168.1.100"cluster-cidr: "10.42.0.0/16"service-cidr: "10.43.0.0/16"cluster-dns: "10.43.0.10"flannel-backend: "vxlan"disable: - traefik # Use your own ingress controllersecrets-encryption: truekube-apiserver-arg: - "enable-admission-plugins=NodeRestriction,PodSecurityPolicy"kubelet-arg: - "max-pods=250"Agent Configuration File
Section titled “Agent Configuration File”# /etc/rancher/k3s/config.yaml (on agent nodes)server: https://api.k3s.example.com:6443token: your-node-tokennode-label: - "node-type=worker" - "region=us-east"kubelet-arg: - "max-pods=250"Disabling Default Components
Section titled “Disabling Default Components”Choose what you need:
# Disable all optional componentscurl -sfL https://get.k3s.io | INSTALL_K3S_EXEC=" \ --disable traefik \ --disable servicelb \ --disable local-storage \ --disable metrics-server \ " sh -
# Then install your preferred alternatives# Example: Install nginx-ingress instead of Traefikkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yamlStorage Options
Section titled “Storage Options”Local Path Provisioner (Default)
Section titled “Local Path Provisioner (Default)”k3s includes Local Path Provisioner for simple persistent storage:
# PVC using local-path StorageClassapiVersion: v1kind: PersistentVolumeClaimmetadata: name: my-dataspec: accessModes: - ReadWriteOnce storageClassName: local-path resources: requests: storage: 1Gi---apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: nginx volumeMounts: - name: data mountPath: /data volumes: - name: data persistentVolumeClaim: claimName: my-dataLonghorn (Distributed Storage)
Section titled “Longhorn (Distributed Storage)”For HA storage, install Longhorn:
# Install Longhornkubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml
# Wait for deploymentkubectl -n longhorn-system get pods -w
# Create StorageClasscat <<EOF | kubectl apply -f -kind: StorageClassapiVersion: storage.k8s.io/v1metadata: name: longhornprovisioner: driver.longhorn.ioparameters: numberOfReplicas: "2" staleReplicaTimeout: "2880" fromBackup: ""EOF
# Make Longhorn the defaultkubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'kubectl patch storageclass longhorn -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'Networking
Section titled “Networking”Service Load Balancer (ServiceLB)
Section titled “Service Load Balancer (ServiceLB)”k3s includes a built-in load balancer for bare metal:
# Exposes Service on node's external IPapiVersion: v1kind: Servicemetadata: name: my-servicespec: type: LoadBalancer ports: - port: 80 targetPort: 8080 selector: app: my-appServiceLB creates a DaemonSet that listens on the node ports:
# Check LoadBalancer serviceskubectl get svc
# See the ServiceLB podskubectl -n kube-system get pods | grep svclbTraefik Ingress Controller
Section titled “Traefik Ingress Controller”k3s bundles Traefik for ingress:
# Ingress using TraefikapiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: my-ingress annotations: traefik.ingress.kubernetes.io/router.entrypoints: web,websecurespec: rules: - host: myapp.example.com http: paths: - path: / pathType: Prefix backend: service: name: my-service port: number: 80Network Policies
Section titled “Network Policies”k3s supports network policies via its built-in controller:
# Allow only frontend to access backendapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: backend-policyspec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080Air-Gapped Installation
Section titled “Air-Gapped Installation”For environments without internet access:
# On a machine with internet access:
# 1. Download k3s binarywget https://github.com/k3s-io/k3s/releases/download/v1.28.5+k3s1/k3s
# 2. Download images archivewget https://github.com/k3s-io/k3s/releases/download/v1.28.5+k3s1/k3s-airgap-images-amd64.tar.gz
# 3. Download install scriptwget https://get.k3s.io -O install.sh
# Transfer all files to air-gapped machine, then:
# 4. Install imagessudo mkdir -p /var/lib/rancher/k3s/agent/images/sudo cp k3s-airgap-images-amd64.tar.gz /var/lib/rancher/k3s/agent/images/
# 5. Install binarysudo cp k3s /usr/local/bin/sudo chmod +x /usr/local/bin/k3s
# 6. Run install scriptchmod +x install.shINSTALL_K3S_SKIP_DOWNLOAD=true ./install.shUpgrading k3s
Section titled “Upgrading k3s”Manual Upgrade
Section titled “Manual Upgrade”# Check current versionk3s --version
# Download new versioncurl -sfL https://get.k3s.io | INSTALL_K3S_VERSION="v1.29.0+k3s1" sh -
# Restart servicesudo systemctl restart k3s
# Verify upgradek3s --versionkubectl get nodesAutomated Upgrades with system-upgrade-controller
Section titled “Automated Upgrades with system-upgrade-controller”# Install System Upgrade Controllerkubectl apply -f https://github.com/rancher/system-upgrade-controller/releases/latest/download/system-upgrade-controller.yaml
# Create upgrade plan for serverscat <<EOF | kubectl apply -f -apiVersion: upgrade.cattle.io/v1kind: Planmetadata: name: server-plan namespace: system-upgradespec: concurrency: 1 cordon: true nodeSelector: matchExpressions: - key: node-role.kubernetes.io/control-plane operator: In values: - "true" serviceAccountName: system-upgrade upgrade: image: rancher/k3s-upgrade channel: https://update.k3s.io/v1-release/channels/stableEOF
# Create upgrade plan for agentscat <<EOF | kubectl apply -f -apiVersion: upgrade.cattle.io/v1kind: Planmetadata: name: agent-plan namespace: system-upgradespec: concurrency: 2 cordon: true nodeSelector: matchExpressions: - key: node-role.kubernetes.io/control-plane operator: DoesNotExist prepare: args: - prepare - server-plan image: rancher/k3s-upgrade serviceAccountName: system-upgrade upgrade: image: rancher/k3s-upgrade channel: https://update.k3s.io/v1-release/channels/stableEOFMonitoring k3s
Section titled “Monitoring k3s”Built-in Metrics Server
Section titled “Built-in Metrics Server”k3s includes metrics-server for kubectl top:
# Check resource usagekubectl top nodeskubectl top pods -A
# Get detailed node metricskubectl describe node | grep -A 10 "Allocated resources"Prometheus Integration
Section titled “Prometheus Integration”# k3s exposes metrics on /metrics- job_name: 'k3s-server' static_configs: - targets: - 'server-ip:6443' scheme: https tls_config: insecure_skip_verify: true # Or provide certs bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
- job_name: 'k3s-agent' static_configs: - targets: - 'agent-ip:10250' scheme: https tls_config: insecure_skip_verify: trueWar Story: The Retail Edge
Section titled “War Story: The Retail Edge”A major retailer needed to run Kubernetes at 2,000 store locations:
The Challenge:
- 2,000 stores worldwide
- Each store has limited hardware (8GB RAM, 2 cores)
- Unreliable internet connectivity
- Zero on-site IT staff
- Need to run inventory management, point-of-sale, and analytics
Why Traditional K8s Failed:
- Minimum 2GB RAM just for control plane
- etcd cluster complexity
- Required 3 nodes minimum for HA
- Operational overhead impossible at scale
The k3s Solution:
# Per-store deploymentResources per store:- 1 x Dell Edge Gateway (8GB RAM, 4 cores)- k3s single-node mode- Local Path Provisioner for storage- Traefik for ingress
Workloads per store:- Inventory service (200MB)- POS API (150MB)- Analytics agent (100MB)- Local cache (Redis, 256MB)Total: ~700MB + OS + k3s ≈ 2GBHeadroom: 6GB for burstFleet Management:
# Rancher Fleet for GitOps at scaleapiVersion: fleet.cattle.io/v1alpha1kind: GitRepometadata: name: store-applications namespace: fleet-defaultspec: repo: https://github.com/company/store-apps branch: main paths: - releases targets: - name: all-stores clusterSelector: matchLabels: env: productionThe Results:
- Deployment time: 15 minutes per store (automated)
- Memory usage: 1.5GB average (with workloads)
- Uptime: 99.9% (offline-capable for 48 hours)
- Updates: Zero-touch via system-upgrade-controller
- Cost savings: $2M/year vs. traditional infrastructure
The Lesson: k3s makes Kubernetes viable where it previously wasn’t. The same APIs and tooling, but packaged for the real world.
Common Mistakes
Section titled “Common Mistakes”| Mistake | Problem | Solution |
|---|---|---|
| Using default token | Security vulnerability | Generate unique tokens per cluster |
| Not setting —tls-san | Certificate errors with LB | Include all access IPs/hostnames |
| Ignoring storage | Data loss on node failure | Use Longhorn or external storage |
| No HA setup | SPOF on single server | Deploy 3+ server nodes for production |
| Skipping upgrades | Security vulnerabilities | Use system-upgrade-controller |
| Not disabling swap | Kubelet issues | Disable swap on all nodes |
| Wrong flannel backend | Performance issues | Use wireguard for encrypted, vxlan for simple |
| No backup strategy | Cluster unrecoverable | Backup etcd/SQLite regularly |
Test your understanding of k3s:
1. What does k3s remove from upstream Kubernetes?
Answer: k3s removes: (1) Legacy, alpha, and non-default features, (2) In-tree cloud providers (AWS, GCP, Azure), (3) In-tree storage drivers, (4) Docker (uses containerd directly). These removals reduce the binary size by ~90% while maintaining full Kubernetes API compatibility.
2. What datastore options does k3s support?
Answer: k3s supports: (1) SQLite (default for single node), (2) Embedded etcd (for HA with —cluster-init), (3) External etcd cluster, (4) MySQL, (5) PostgreSQL. For single-node edge deployments, SQLite is perfect. For HA, embedded etcd is recommended for simplicity.
3. How do you join an agent node to an existing k3s cluster?
Answer: On the agent node, run: curl -sfL https://get.k3s.io | K3S_URL=https://server:6443 K3S_TOKEN=<token> sh -. The token is found at /var/lib/rancher/k3s/server/node-token on the server. The agent will automatically register with the cluster.
4. What is ServiceLB and why is it included in k3s?
Answer: ServiceLB (formerly Klipper) is a bare-metal load balancer included in k3s. When you create a LoadBalancer service, ServiceLB creates a DaemonSet that listens on the requested ports on each node. This provides LoadBalancer functionality without cloud provider integration or MetalLB—essential for edge deployments.
5. How do you disable bundled components in k3s?
Answer: Use the --disable flag: k3s server --disable traefik --disable servicelb --disable local-storage. Or in config.yaml: disable: [traefik, servicelb, local-storage]. This lets you use alternative components like nginx-ingress or MetalLB.
6. What's the difference between k3s server and k3s agent?
Answer: k3s server runs the control plane (API server, controller manager, scheduler) plus node components (kubelet, containerd). k3s agent runs only node components and connects to the server for cluster coordination. In single-node mode, the server is both control plane and worker. In multi-node mode, agents are dedicated workers.
7. How do you set up HA k3s with embedded etcd?
Answer: First server: k3s server --cluster-init. Get token from /var/lib/rancher/k3s/server/token. Additional servers: k3s server --server https://first-server:6443 --token <token>. Requires odd number of servers (3, 5, 7) for etcd quorum. All servers run both control plane and embedded etcd.
8. How do you perform air-gapped installation of k3s?
Answer: Download the k3s binary, airgap images tarball, and install script on an internet-connected machine. Transfer to air-gapped machine. Place images tarball in /var/lib/rancher/k3s/agent/images/. Place binary in /usr/local/bin/k3s. Run install script with INSTALL_K3S_SKIP_DOWNLOAD=true.
Hands-On Exercise: Deploy HA k3s Cluster
Section titled “Hands-On Exercise: Deploy HA k3s Cluster”Objective
Section titled “Objective”Deploy a high-availability k3s cluster with 3 server nodes and test failover.
Environment Setup
Section titled “Environment Setup”We’ll use Multipass for local VMs (or use any 3 Linux VMs/cloud instances):
# Install Multipass (macOS)brew install multipass
# Or on Ubuntusudo snap install multipass
# Create 3 server VMsfor i in 1 2 3; do multipass launch --name k3s-server-$i --cpus 2 --memory 2G --disk 10Gdone
# Create 2 agent VMsfor i in 1 2; do multipass launch --name k3s-agent-$i --cpus 2 --memory 2G --disk 10Gdone
# List VMs and get IPsmultipass listStep 1: Initialize First Server
Section titled “Step 1: Initialize First Server”# SSH into first servermultipass shell k3s-server-1
# Install k3s with cluster-initcurl -sfL https://get.k3s.io | sh -s - server \ --cluster-init \ --tls-san=$(hostname -I | awk '{print $1}')
# Get the join tokensudo cat /var/lib/rancher/k3s/server/token
# Get server IPhostname -I | awk '{print $1}'
# Exit shellexitStep 2: Join Additional Servers
Section titled “Step 2: Join Additional Servers”# Get SERVER_IP and TOKEN from step 1, then:
# Server 2multipass shell k3s-server-2curl -sfL https://get.k3s.io | sh -s - server \ --server https://SERVER_IP:6443 \ --token TOKENexit
# Server 3multipass shell k3s-server-3curl -sfL https://get.k3s.io | sh -s - server \ --server https://SERVER_IP:6443 \ --token TOKENexitStep 3: Join Agent Nodes
Section titled “Step 3: Join Agent Nodes”# Agent 1multipass shell k3s-agent-1curl -sfL https://get.k3s.io | K3S_URL=https://SERVER_IP:6443 K3S_TOKEN=TOKEN sh -exit
# Agent 2multipass shell k3s-agent-2curl -sfL https://get.k3s.io | K3S_URL=https://SERVER_IP:6443 K3S_TOKEN=TOKEN sh -exitStep 4: Verify Cluster
Section titled “Step 4: Verify Cluster”# From server-1multipass shell k3s-server-1
# Check all nodessudo k3s kubectl get nodes
# Check etcd memberssudo k3s etcd-snapshot ls
# Check system podssudo k3s kubectl get pods -A
exitStep 5: Deploy Test Application
Section titled “Step 5: Deploy Test Application”multipass shell k3s-server-1
# Create deploymentsudo k3s kubectl create deployment nginx --image=nginx --replicas=3
# Expose with LoadBalancersudo k3s kubectl expose deployment nginx --port=80 --type=LoadBalancer
# Check pods are distributed across agentssudo k3s kubectl get pods -o wide
# Get LoadBalancer IPsudo k3s kubectl get svc nginxStep 6: Test Failover
Section titled “Step 6: Test Failover”# From your host machine, stop a servermultipass stop k3s-server-1
# From server-2, check cluster healthmultipass shell k3s-server-2sudo k3s kubectl get nodes# Server-1 should show NotReady
# Check etcd is still functionalsudo k3s kubectl get pods -A
# Application should still workcurl http://LOADBALANCER_IP
exit
# Bring server-1 backmultipass start k3s-server-1
# Verify it rejoinsmultipass shell k3s-server-1sudo k3s kubectl get nodesSuccess Criteria
Section titled “Success Criteria”- 3 server nodes running with embedded etcd
- 2 agent nodes joined to cluster
- Application deployed across agent nodes
- Cluster survives server-1 failure
- Server-1 successfully rejoins after restart
Cleanup
Section titled “Cleanup”# Delete all VMsmultipass delete --purge k3s-server-1 k3s-server-2 k3s-server-3 k3s-agent-1 k3s-agent-2Key Takeaways
Section titled “Key Takeaways”- k3s is real Kubernetes: Same API, same kubectl, same ecosystem—just smaller
- Single binary simplicity: ~60MB contains everything needed
- Multiple datastore options: SQLite for single node, embedded etcd for HA
- Batteries included: Traefik, CoreDNS, Local Path, ServiceLB bundled
- Disable what you don’t need: Customize by removing bundled components
- ServiceLB for bare metal: LoadBalancer services work without cloud provider
- Air-gap friendly: Download artifacts once, deploy anywhere
- Upgrade with care: Use system-upgrade-controller for rolling upgrades
- HA requires 3+ servers: Odd numbers for etcd quorum (3, 5, 7)
- Edge native: Built for resource-constrained, distributed environments
Next Module
Section titled “Next Module”Continue to Module 14.2: k0s — Zero-dependency Kubernetes with even cleaner architecture.
“k3s doesn’t make Kubernetes simpler—it makes Kubernetes small enough to fit where you need it.”