Installing Kubernetes
Choose how to run Kubernetes, kind, minikube, Docker Desktop, k3s or a managed cloud cluster, with an honest comparison of what each is good and bad at.
There is no single "install Kubernetes" step. There are several distributions aimed at different purposes, and picking the wrong one wastes a lot of time.
For learning, the answer is almost always kind or minikube. For production, it is almost always a managed cloud cluster.
The options
| Option | Good for | Runs where | Multi-node |
|---|---|---|---|
| kind | Learning, CI, testing | Docker containers | Yes, easily |
| minikube | Learning, add-ons, Ingress | VM or Docker | Yes |
| Docker Desktop | Quick single-node use | Its own VM | No |
| k3s | Edge, IoT, small servers | A real host | Yes |
| kubeadm | Learning the internals, self-managed production | Real machines | Yes |
| EKS / GKE / AKS | Production | Cloud | Yes |
For learning: kind or minikube
kind
Runs each Kubernetes node as a Docker container. It is the fastest to start and stop, which makes it the better choice for CI and for repeatedly throwing clusters away.
brew install kind # or: go install sigs.k8s.io/kind@latest
kind create cluster --name dev
kubectl get nodes
NAME STATUS ROLES AGE VERSION
dev-control-plane Ready control-plane 45s v1.31.2
A multi-node cluster is a short config file, which matters because single-node clusters hide every scheduling and affinity problem you will eventually meet:
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
kind create cluster --name dev --config kind-config.yaml
The main friction is that images must be loaded into the cluster explicitly, since it has no access to your local Docker images:
kind load docker-image myapp:dev --name dev
minikube
Older, more batteries-included. Its add-on system is the reason to prefer it. Ingress, metrics-server and a dashboard are one command each rather than a Helm install.
brew install minikube
minikube start --cpus=4 --memory=8192
minikube addons enable ingress
minikube addons enable metrics-server
minikube service payments-api --url # reach a NodePort Service
minikube tunnel # make LoadBalancer Services work
minikube dashboard
minikube tunnel is genuinely useful: it satisfies LoadBalancer Services, which otherwise sit at <pending> forever on any local cluster.
Which one?
kind if you want speed, multi-node, or CI. minikube if you want Ingress and metrics-server working with minimal setup.
Both are fine. Do not spend long deciding.
Docker Desktop
Kubernetes is a checkbox in its settings, which makes it the lowest-effort option if you already run Docker Desktop.
The limitations are real: single node only, a Kubernetes version tied to the Docker Desktop release, and it competes with your containers for the same VM resources. Fine for a quick look, limiting past that.
k3s
A certified Kubernetes distribution in a single binary under 100MB, with etcd swapped for SQLite by default and legacy cloud providers stripped out.
curl -sfL https://get.k3s.io | sh -
sudo k3s kubectl get nodes
Genuinely production-grade for edge deployments, IoT, and small servers. It is also a pleasant way to run a real cluster on a spare machine or a cheap VPS, and it includes Traefik and a load balancer implementation out of the box.
kubeadm
The official tool for building a cluster on real machines. You install a container runtime, run kubeadm init, install a CNI plugin, and join workers.
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml
kubeadm token create --print-join-command
Worth doing once. Installing the CNI by hand and watching CoreDNS go from Pending to Running teaches more about how clusters fit together than any amount of reading.
Worth being honest about as a production choice: you own etcd backups, certificate rotation, control plane upgrades and node patching. That is a real ongoing job.
Managed clusters
For production, use EKS, GKE or AKS unless you have a specific reason not to. The provider runs the control plane, backs up etcd, and handles its upgrades.
# AWS
eksctl create cluster --name production --region us-east-1 --nodes 3
# GCP
gcloud container clusters create-auto production --region us-central1
# Azure
az aks create --resource-group rg --name production --node-count 3
The control plane fee is small next to the cost of someone maintaining one. Note that you still own the worker nodes, the networking, add-on upgrades and access control. Managed means the control plane, not the whole cluster.
Resources you will actually need
Kubernetes is not light. A local cluster wants at least 2 CPUs and 4GB of RAM free, and 4 CPUs with 8GB makes a real difference once you install an ingress controller and a monitoring stack.
If Pods sit Pending with Insufficient cpu on a fresh local cluster, the cluster is too small rather than misconfigured:
minikube start --cpus=4 --memory=8192
After installing
kubectl cluster-info
kubectl get nodes
kubectl get pods -A # control plane components should be Running
All kube-system Pods Running means the cluster is healthy. CoreDNS stuck Pending on a kubeadm cluster means the CNI plugin has not been installed.
# Prove it works end to end
kubectl create deployment web --image=nginx:1.27
kubectl expose deployment web --port=80
kubectl port-forward service/web 8080:80
Explore further in this section
| Sub-topic | What you will learn |
|---|---|
| Installing kubectl | Install and configure the CLI |
| minikube | Set up minikube and its add-ons |
| kind | Multi-node clusters in Docker |
Quick reference
| Task | Command |
|---|---|
| kind cluster | kind create cluster --name dev |
| kind multi-node | kind create cluster --config kind-config.yaml |
| Load an image into kind | kind load docker-image <img> --name dev |
| minikube cluster | minikube start --cpus=4 --memory=8192 |
| minikube add-on | minikube addons enable ingress |
| Check health | kubectl get nodes && kubectl get pods -A |
| Cluster endpoint | kubectl cluster-info |
| Delete | kind delete cluster --name dev / minikube delete |
Key takeaways
- kind or minikube for learning; a managed cluster for production. The rest are for specific situations.
- kind is faster and better for CI; minikube's add-ons make Ingress and metrics-server easier.
- Create a multi-node local cluster. Single-node hides every scheduling problem you will eventually meet.
- kind needs
kind load docker-image: it cannot see your local Docker images. minikube tunnelis what makesLoadBalancerServices work locally.- Give it 4 CPUs and 8GB.
Insufficient cpuon a fresh cluster usually means it is too small. - kubeadm once, for understanding. Self-managing production means owning etcd, certificates and upgrades.
Check your understanding
ImagePullBackOff on a local image
You build myapp:dev locally and deploy it to a kind cluster. The Pod reports ImagePullBackOff even though docker images lists it. Why?
A pending LoadBalancer locally
A LoadBalancer Service on minikube shows EXTERNAL-IP as pending indefinitely. What is the explanation?
Frequently Asked Questions
What is the easiest way to install Kubernetes for learning?
kind or minikube. kind runs each node as a Docker container and starts in well under a minute, making it ideal for throwing clusters away and recreating them. minikube is a little slower but has an add-on system that installs Ingress, metrics-server and a dashboard with one command each. Either is a good choice, and both are far more appropriate for learning than building a cluster with kubeadm.
What is the difference between kind and minikube?
kind creates nodes as Docker containers, which makes it very fast and well suited to CI pipelines, and multi-node clusters are a few lines of config. minikube typically runs in a VM or Docker and provides curated add-ons, so getting Ingress or metrics-server working takes one command rather than a Helm install. kind requires kind load docker-image to make local builds available; minikube offers minikube tunnel to make LoadBalancer Services function. Both are fine. Choose on whether you value speed or bundled add-ons.
Should I use Docker Desktop's built-in Kubernetes?
It is a reasonable low-effort option if you already run Docker Desktop, since enabling it is a checkbox. The limitations are that it is single-node, its Kubernetes version is tied to the Docker Desktop release, and it shares resources with your containers. For anything beyond a quick look. Particularly anything involving scheduling, node affinity or multi-node behaviour. Kind or minikube will serve you better.
Can I run Kubernetes in production without a cloud provider?
Yes. kubeadm builds a conformant cluster on your own machines, and k3s is a certified lightweight distribution that runs well on small servers and edge hardware. Be clear about what you take on: etcd backups, certificate rotation, control plane upgrades, node patching, and the networking and storage integrations a cloud provider supplies. For most teams the managed control plane fee is smaller than the engineering time it replaces.
How much memory and CPU does a local cluster need?
At least 2 CPUs and 4GB of RAM free, and 4 CPUs with 8GB is a much better experience once you add an ingress controller or a monitoring stack. Kubernetes control plane components alone consume a meaningful share of a small allocation. If Pods sit Pending with Insufficient cpu on a freshly created cluster, the cluster is undersized rather than misconfigured. Restart it with more resources.
Why are my CoreDNS Pods stuck in Pending after kubeadm init?
No CNI plugin is installed. kubeadm init deliberately leaves the choice of network plugin to you, and without one Pods cannot be assigned addresses, so CoreDNS cannot start. Apply a CNI such as Calico, Flannel or Cilium and CoreDNS moves to Running within a minute. If you passed --pod-network-cidr to kubeadm init, make sure the plugin's configuration uses the same range.