Before running any workload we need a cluster. There are three broad routes, and which one you pick depends on what you are trying to do.
| Route | Examples | Best for |
|---|---|---|
| Local learning cluster | minikube, kind, k3s, Docker Desktop |
Learning, testing manifests, CI pipelines |
| Self-managed cluster | kubeadm, Kubespray, Talos |
On-premises, full control, bare metal |
| Managed cloud cluster | Amazon EKS, Google GKE, Azure AKS | Production without running the control plane |
Prerequisites
Whatever route you choose, you need the kubectl client installed (see the end of the previous chapter). Local clusters also need a driver to host the node, typically a container runtime or hypervisor:
- Docker (most common)
- Podman
- KVM / QEMU
- VirtualBox
Check what you have:
$ docker version
$ kubectl version --client
Local Clusters
minikube
minikube runs a single-node cluster (control plane and compute node on the same machine) inside a container or VM. It is the quickest way to get a working cluster and ships with handy add-ons.
Installing on Linux
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
$ sudo install minikube-linux-amd64 /usr/local/bin/minikube
$ minikube version
Starting the cluster
$ minikube start
By default it picks a driver automatically. You can be explicit:
$ minikube start --driver=docker
What minikube start does behind the scenes:
- Creates the node (a Docker container or VM)
- Downloads the Kubernetes component images (kube-apiserver, etcd, kube-scheduler ...)
- Bootstraps the control plane
- Writes a new entry into your ~/.kube/config so kubectl points at the new cluster
Verifying
$ kubectl cluster-info
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 1m v1.xx.x
Ready means the kubelet on that node is healthy and reporting to the kube-apiserver.
You can also see the components from Chapter 2 running as Pods in the kube-system namespace:
$ kubectl get pods -n kube-system
Expect to see etcd-minikube, kube-apiserver-minikube, kube-scheduler-minikube, kube-controller-manager-minikube, kube-proxy-xxxxx and coredns-xxxxx.
Useful minikube commands
$ minikube status # state of the cluster
$ minikube dashboard # opens the Web UI add-on
$ minikube addons list # list available add-ons
$ minikube addons enable metrics-server
$ minikube ssh # shell into the node
$ minikube stop # stop, keep the state
$ minikube delete # remove the cluster entirely
Multi-node with minikube
$ minikube start --nodes 3 -p multi
-p creates a separate profile so it does not clash with the default cluster.
kind (Kubernetes IN Docker)
kind runs every node as a Docker container. Because nodes are cheap containers, it is excellent for multi-node clusters and for CI.
$ go install sigs.k8s.io/kind@latest # or download the binary from the releases page
$ kind create cluster # single node named "kind"
A multi-node cluster is described in a config file:
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
$ kind create cluster --name demo --config kind-config.yaml
$ kubectl get nodes
$ kind delete cluster --name demo
Docker Desktop
Docker Desktop includes a single-node Kubernetes cluster. Enable it under Settings → Kubernetes → Enable Kubernetes. Convenient on Windows and macOS, but you get less control over the version and configuration than with minikube or kind.
Choosing between them
| Tool | Nodes | Notes |
|---|---|---|
minikube |
1 or many | Rich add-ons, built-in dashboard, good for learning |
kind |
Many | Fast to create and destroy, great for CI |
| Docker Desktop | 1 | Zero setup if you already use Docker Desktop |
k3s |
1 or many | Lightweight, runs well on small hardware / edge |
Self-Managed Cluster with kubeadm
kubeadm is the official tool for bootstrapping a production-style cluster on machines you provide. It installs the control plane components, but you are responsible for the machines, networking and upgrades.
What you need on every node
- A supported Linux distribution
- 2 GB RAM or more (2 CPUs on the control plane)
- Full network connectivity between nodes
- Swap disabled (the
kubeletexpects this by default) - A container runtime that implements the CRI (e.g.
containerdorCRI-O) kubeadm,kubeletandkubectlinstalled
$ sudo swapoff -a
$ sudo apt-get install -y kubelet kubeadm kubectl
$ sudo apt-mark hold kubelet kubeadm kubectl # avoid accidental upgrades
Bootstrapping the control plane
On the first control plane node:
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
At the end it prints two things you need:
- Commands to configure
kubectlfor your user - A
kubeadm join ...command with a token for the compute nodes
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
Installing a network plugin
Nodes stay NotReady until a Container Network Interface (CNI) plugin is installed. This is one of the add-on components from Chapter 2.
$ kubectl apply -f <cni-plugin-manifest.yaml> # Calico, Flannel, Cilium ...
Joining compute nodes
Run the join command on each compute node:
$ sudo kubeadm join <control-plane-ip>:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
Verify from the control plane:
$ kubectl get nodes
If the token expired (they last 24 hours), create a new one with
kubeadm token create --print-join-command.
Managed Kubernetes in the Cloud
As covered in Chapter 2, cloud providers run the control plane for you. You only create and pay for compute nodes (and sometimes a small fee for the control plane).
| Service | Provider | CLI |
|---|---|---|
| EKS | AWS | eksctl / aws eks |
| GKE | gcloud container |
|
| AKS | Azure | az aks |
Typical flow, using Azure as an example:
$ az group create --name k8s-demo --location southafricanorth
$ az aks create --resource-group k8s-demo --name demo-aks --node-count 2
$ az aks get-credentials --resource-group k8s-demo --name demo-aks
$ kubectl get nodes
The get-credentials step merges the cluster into your local kubeconfig, just like minikube start did.
Remember to delete the cluster when you finish, as compute nodes are billed per hour:
$ az group delete --name k8s-demo
kubeconfig and Contexts
kubectl knows which cluster to talk to from the kubeconfig file, ~/.kube/config by default. It holds three things:
- clusters: the API server address and its certificate authority
- users: credentials (client certificates, tokens, or exec plugins)
- contexts: a pairing of a cluster, a user and an optional default namespace
$ kubectl config get-contexts # list all contexts
$ kubectl config current-context # which one is active
$ kubectl config use-context minikube # switch cluster
$ kubectl config set-context --current --namespace=dev
When you have a local cluster and a cloud cluster on the same machine, always check the current context before running destructive commands.
Cleaning Up
| Tool | Command |
|---|---|
minikube |
minikube delete |
kind |
kind delete cluster --name demo |
kubeadm |
sudo kubeadm reset |
| Cloud | Delete the cluster / resource group |
Summary
- Use
minikubeorkindto learn; usekubeadmwhen you need to own the machines; use EKS / GKE / AKS when you want someone else to run the control plane. - A fresh cluster is verified with
kubectl cluster-infoandkubectl get nodes. - The control plane components are visible as Pods in the
kube-systemnamespace. kubectlfinds clusters through contexts in~/.kube/config.