Tools Used in Kubernetes · minikube

minikube

minikube is the oldest and most complete way to run a real Kubernetes cluster on a laptop: point it at a driver — a container, or a full virtual machine — and minikube start hands back a single-node cluster with a genuine kube-apiserver, etcd, kubelet, and container runtime, all reachable through your ordinary kubeconfig like any other cluster. What sets it apart from lighter alternatives is how much of "a real cluster" it's willing to simulate: an addon system that installs an actual ingress controller or metrics-server with one command, minikube tunnel faking a cloud load balancer's external IP, a dashboard, multiple named profiles running side by side, and a broad menu of drivers so the same workflow works whether Docker, Podman, VirtualBox, or a Linux hypervisor is what's actually available on the machine in front of you. This page covers the driver model, the commands you'll actually type, the addon and image-loading tricks that make local development pleasant, the gotchas that catch people once, and where minikube fits next to kind and the rest of the local-cluster landscape.

☺ Explain it like I'm 10

Real Kubernetes is usually a whole fleet of computers working as a team — a control room, and a bunch of worker computers taking orders from it. minikube takes that entire fleet and squeezes it down to fit on one single computer, usually tucked inside one virtual machine or one container so it can't make a mess of anything else on your laptop. It's not a pretend version with fake buttons — it's the actual control room and the actual worker, just both living in one box instead of spread across a whole building. That's why everything you practice on it — the commands, the YAML, the way things break — carries over directly to a giant real cluster later. You're not learning a toy; you're learning the real thing, shrunk down to one desk.

🦥Your host for this topic: Sol the Sloth — Sol never assumes there's room to spare, and a one-node minikube VM has less room than anything else in this course. Every driver choice and every --memory flag is Sol thinking it through slowly before turning the dial up.

What minikube actually is

☺ Like you're 10: One command builds a little box on your machine, puts a whole working cluster inside it, and quietly points your normal kubectl at that box.

minikube is a kubernetes/minikube project — one of the oldest pieces of the Kubernetes ecosystem, dating back to 2016, well before kind or any of the container-based alternatives existed. Its defining idea hasn't changed since: pick a driver (what minikube uses to create an isolated environment), and minikube start provisions a single node inside it running the full control plane — kube-apiserver, etcd, kube-scheduler, kube-controller-manager — plus kubelet and a container runtime, co-located on that same node acting as both control plane and worker. It then writes a context into your kubeconfig (named minikube by default) so every kubectl command you already know works against it unmodified. Nothing about the API you're talking to is scaled down or faked; what's scaled down is the number of machines it's spread across.

◆ Key idea

"Local cluster" describes a category of tools, not one tool. minikube's specific bet is breadth and realism: more drivers, more addons, a dashboard, load-balancer emulation, multi-node support — closer to what a cloud-managed cluster feels like to operate, at the cost of being heavier and slightly slower to start than a container-only alternative. kind's bet is the opposite: minimal surface, containers-as-nodes only, built primarily to test Kubernetes itself in CI, and it starts and tears down fast enough to run in a matrix of dozens per pipeline. Neither bet is wrong — they're optimizing for different afternoons.

The driver model: a container, or a real VM

☺ Like you're 10: You tell minikube what kind of box to build the cluster inside — a lightweight container, or a fuller virtual machine — and it uses whatever's actually installed on your computer.

Every other decision on this page sits downstream of one choice: which driver builds the isolated environment minikube's single node lives in. Drivers split into two families with genuinely different isolation properties, not just different install steps.

DriverFamilyPlatformWorth knowing
dockerContainermacOS, Linux, WindowsThe default almost everywhere Docker is already installed; fastest to start; the node is a container, so it shares the host kernel rather than running its own
podmanContainerLinux (experimental elsewhere)Same container-driver tradeoffs as docker, for environments standardized on Podman instead
virtualboxFull VMmacOS, Linux, WindowsThe traditional cross-platform default before container drivers matured; slower to start, but a genuinely separate kernel
hyperkit / qemuFull VMmacOSApple Silicon generally wants qemu or docker; hyperkit is Intel-Mac-oriented and effectively unmaintained on ARM
kvm2Full VMLinuxNative Linux virtualization; needs /dev/kvm and the user in the right group — a common first-run permission snag
hypervFull VMWindowsRequires Hyper-V enabled, which can conflict with other virtualization software (including some VirtualBox versions) running at the same time
noneBare hostLinux onlyNo isolation at all — kubelet and the runtime run directly on your host as root; fast, but see the gotcha below before reaching for it
sshRemoteAny reachable Linux hostProvisions the node over SSH onto a machine you already have — a spare box or a cloud VM, not actually "local" at all

The container drivers (docker, podman) are the practical default on a modern laptop: they start in seconds because there's no operating system to boot, only a container image to run. What you give up is kernel-level isolation — the node's kernel is your host's kernel, mediated only by container namespacing, which is a materially different isolation boundary than a VM's own kernel. For day-to-day manifest practice that distinction rarely matters. It starts to matter the moment you're testing something kernel-adjacent — a CNI plugin doing its own network namespace tricks, a workload that wants specific sysctls, or a CKS-style scenario probing container escape — where a full VM driver behaves closer to a real worker node.

minikube start --driver=… container driver VM driver host kernel — shared node container kube-apiserver · etcd kubelet container runtime docker · podman hypervisor guest kernel — its own node VM kube-apiserver · etcd kubelet container runtime VirtualBox · HyperKit · KVM2 · Hyper-V same single node, same real control plane — different isolation boundary
⚠ Watch out

The driver is fixed the moment a profile is created — minikube start --driver=X a second time against an existing, undeleted profile with a different driver fails or silently ignores the flag depending on version. If you need to switch drivers, delete the profile first (minikube delete -p <name>) and start fresh; there's no in-place driver migration.

Standing up and tearing down a cluster

☺ Like you're 10: One command builds it, one shows you if it's healthy, one pauses it, one deletes it completely — and you can keep several separate ones around at once.

A profile is minikube's name for one independent cluster — the default profile is literally named minikube, and -p <name> on any command targets a different one, letting you run a CKAD-practice cluster and a completely separate one for a side project at the same time, each with its own driver, version, and addons.

# bring up a cluster sized for real work, not the bare-minimum default
$ minikube start --driver=docker --cpus=4 --memory=8192 --kubernetes-version=v1.31.0

# a second, independent cluster alongside it
$ minikube start -p cks-practice --driver=docker --nodes=2 --kubernetes-version=v1.29.0

$ minikube status                          # is everything actually Running, or just started
$ minikube status -p cks-practice
$ kubectl config get-contexts              # both profiles show up as separate contexts
$ minikube profile list                    # every profile, its driver, and its status

$ minikube stop                            # shut the node down, keep the disk state
$ minikube start                           # resume where you left off — fast, no re-provisioning
$ minikube delete                          # tear it down completely, disk included
$ minikube delete --all --purge            # nuke every profile and cached images/ISOs

--nodes adds worker nodes to the same profile — useful for practicing scheduling, taints, and pod anti-affinity against something that isn't trivially one node, though only the first node runs the control plane; it isn't a true highly-available multi-control-plane setup. --kubernetes-version pins an exact upstream version, which matters more than it looks: the CKA and CKAD blueprints are versioned against a specific Kubernetes release each exam cycle, and practicing against a version that's drifted a full minor release away can mean a flag or field behaves slightly differently than what you'll actually see on exam day.

Addons: real components, one command away

☺ Like you're 10: minikube keeps a shelf of ready-to-install extras — an ingress controller, a dashboard, metrics — and flipping one on is a single command, not a manifest you have to go find yourself.

An addon is a maintained, opinionated install of a real component — not a minikube-specific stub. Enabling ingress installs the actual ingress-nginx controller; enabling metrics-server installs the actual upstream metrics-server that HPA reads from. This is the single biggest thing separating minikube from a bare kind cluster: kind hands you nodes and nothing else, and you install everything yourself; minikube ships a curated shelf of the components you'd otherwise have to go find, version-pin, and apply by hand.

$ minikube addons list                          # everything available, and its current state
$ minikube addons enable ingress                # real ingress-nginx controller
$ minikube addons enable metrics-server         # feeds `kubectl top` and HPA
$ minikube addons enable dashboard               # the Kubernetes web dashboard
$ minikube addons enable registry                 # an in-cluster image registry on :5000
$ minikube addons disable dashboard

$ minikube dashboard                              # open the dashboard addon in a browser, with auth wired up

Two addons are on by default and easy to forget exist: storage-provisioner (a hostPath-backed default StorageClass, so a plain PersistentVolumeClaim just works without any CSI setup of your own) and default-storageclass, which marks it as the cluster's default. That's genuinely convenient for practice manifests, and genuinely misleading if you forget it's hostPath under the hood and assume a PVC that binds instantly on minikube will behave identically against a real cloud CSI driver, where provisioning is asynchronous and can fail for reasons hostPath never will.

Building images straight into the cluster

☺ Like you're 10: Normally you'd have to push an image to the internet before a cluster can use it. minikube lets you build directly into its own private Docker, so the cluster already has the image the second the build finishes.

The single most useful minikube-specific trick for local development is minikube docker-env (or the driver-agnostic minikube image subcommands). It points your shell's docker client at the Docker daemon running inside the minikube node instead of your host's daemon — so a normal docker build produces an image that's already present on the cluster, with no registry, no push, and no pull required.

# point this shell's docker client at minikube's internal daemon
$ eval $(minikube docker-env)

$ docker build -t checkout:dev .
$ docker images | grep checkout                 # confirm it landed inside the node, not on the host

# undo it for the rest of this shell session when you're done
$ eval $(minikube docker-env -u)

# the driver-agnostic equivalent — works with podman too, and doesn't touch your shell env
$ minikube image build -t checkout:dev .
$ minikube image load checkout:dev              # load an image you already built on the host instead

Two things have to be true for a Deployment to actually pick up an image loaded this way. First, the tag has to match exactly what's in spec.containers[].imagecheckout:dev is a different string than checkout:latest as far as the kubelet is concerned. Second, imagePullPolicy can't be left at its default: an unqualified tag other than latest defaults to IfNotPresent already, which is what you want, but a tag of latest defaults to Always — and Always means the kubelet tries to pull from a registry every time, ignoring the perfectly good image already sitting on the node, and fails with ErrImagePull the instant there's no network path to one. Set imagePullPolicy: Never explicitly on anything you're loading this way and it stops being ambiguous.

⚠ Watch out

Images loaded via docker-env or minikube image load live only inside that profile's node — they vanish the moment you minikube delete that profile, and they were never anywhere your host's own docker images could see them (unless you built with a plain host-side docker build and then explicitly minikube image loaded it in). Treat it as a fast local-dev loop, not a substitute for actually pushing to a registry once code is meant to go anywhere beyond your own machine.

Reaching services: NodePort, port-forward, and tunnel

☺ Like you're 10: A single-node cluster doesn't have a real cloud sitting next to it to hand out external IPs, so minikube has to fake that part convincingly, and there's more than one way it does it.

minikube service is the fastest path to a NodePort Service — it resolves the node's IP and the allocated NodePort and either opens it in a browser or prints the URL. A LoadBalancer-type Service is a harder problem: there's no real cloud provider around to hand out an external IP, so by default it sits at <pending> forever. minikube tunnel solves that specifically — it runs a small process that routes traffic from a real, locally-addressable IP on your host to the cluster's LoadBalancer Services, and updates their status.loadBalancer.ingress field to match, which is the same field Services & the CNI covers a real cloud controller populating.

$ minikube service checkout --url               # fastest path to a NodePort Service's URL
$ kubectl port-forward svc/checkout 8080:80      # the universal fallback, works on any Service type

# LoadBalancer Services need this running in its own terminal, in the foreground
$ minikube tunnel
$ kubectl get svc checkout                       # EXTERNAL-IP now populated instead of 

$ minikube ip                                     # the node's own address, handy for NodePort access without the wrapper
$ minikube ssh                                     # a shell inside the node itself
⚠ Watch out

minikube tunnel has to keep running in its own terminal — it's not a background daemon started once and forgotten, and closing that terminal (or the laptop sleeping) silently drops the routing. If a LoadBalancer Service that worked five minutes ago is suddenly unreachable, check whether the tunnel process is still alive before suspecting anything about the Service itself. On macOS and Linux it also needs elevated privileges to bind low, routable ports, so expect a password prompt.

Gotchas and failure modes

☺ Like you're 10: Almost every minikube surprise traces back to one root cause: it's genuinely one small machine, and it's easy to ask it for more than it actually has.

The default resource allocation is stingier than you think. A bare minikube start with no flags picks conservative CPU and memory defaults meant to work on nearly any laptop — comfortably enough for a handful of small Pods, not enough for a realistic multi-service practice setup, which starts producing Pending Pods stuck on unsatisfiable resource requests, not obviously-labeled OOM errors. Pass --cpus and --memory explicitly for anything beyond a quick smoke test, and remember the container drivers are additionally capped by whatever memory Docker Desktop itself has been given — raising minikube's flag past Docker Desktop's own VM memory ceiling doesn't help.

hostPath storage is not portable. The default StorageClass backing a PVC on minikube is hostPath under the hood — convenient, instant, and completely unlike the asynchronous, sometimes-fails, sometimes-a-different-zone behavior of a real cloud CSI driver. Manifests that only ever get tested against minikube's default storage can hide bugs that only show up the first time they run against real CSI-backed storage in a cloud cluster.

The none driver skips isolation entirely. It runs kubelet and the container runtime directly on your Linux host as root, with no VM and no container boundary between the cluster and the rest of your machine — genuinely faster, and genuinely a wider blast radius if anything scheduled on it is untrusted. It's a reasonable choice inside an already-isolated CI runner that gets thrown away after the job; it's a poor default on a personal laptop.

Version drift between minikube's bundled Kubernetes and what you're studying against. minikube start defaults to whatever version that minikube release ships, which is not necessarily the version currently listed on the CKA/CKAD/CKS blueprints — always pass --kubernetes-version explicitly when the point of the exercise is exam fidelity, and confirm the current expected version on the official Linux Foundation page before you rely on it, since the certifying body updates it independently of any single minikube release.

🦥 Sol's-eye view

"The first time I gave a demo cluster four services, a queue, and a database, I didn't touch a single flag — just minikube start and went. Half the Pods sat in Pending the whole meeting and I spent it insisting the manifests were fine, because nothing said 'out of memory' anywhere I was looking; they just... never scheduled. It wasn't a bug in anything I wrote. It was four services asking for more room than the default VM had to give. Now the very first thing I type is --cpus and --memory, sized honestly for what I'm about to run — the same slow arithmetic I'd do for a real node, just done once, up front, instead of guessed at wrong in front of an audience."

minikube vs. kind vs. the rest

☺ Like you're 10: A few tools all solve "run Kubernetes on my laptop" — they just disagree on how much realism to trade for speed.

Treat this as "which afternoon are you having," not "which tool is objectively better" — the honest answer changes with the task.

ToolNode modelBest whenCosts you
minikubeContainer or full VM, per your driver choiceLearning end to end, exam practice, anything that wants an addon-installed ingress/dashboard/registry or a fake LoadBalancer IP without hand-installing itSlower to start than a pure-container tool; VM drivers add real overhead
kindContainers-as-nodes only, via DockerCI, multi-node topology testing, spinning many disposable clusters fast — its own reason for existing is testing Kubernetes itselfNo addon system and no LoadBalancer emulation of its own; you install everything you want beyond bare nodes
k3dContainers running k3s (a lightweight Kubernetes distribution) instead of full upstream componentsThe fastest possible spin-up, or resource-constrained CI runners where even minikube's footprint is too muchk3s isn't byte-for-byte identical to upstream Kubernetes in every corner — rarely matters for learning, occasionally matters for exact API-server flag behavior
Docker Desktop's built-in KubernetesA single node inside Docker Desktop's own VMAbsolute lowest-friction "just click a checkbox" start, if Docker Desktop is already installed and licensed for your useOne fixed cluster, no profiles, no addon system, version tied to whatever Docker Desktop currently ships
A real cloud cluster (EKS/GKE/AKS, or the substrate covered on the PE course)Actually multiple real machinesAnything where the substrate itself is what you're testing — real cloud LoadBalancers, real multi-zone scheduling, real IAM integrationCosts real money by the hour, and is overkill for practicing a Deployment spec

For this course's own purposes the practical guidance is simple: reach for minikube when you want the fullest local approximation of a real cluster — addons, dashboard, a fake LoadBalancer, exam-style practice against a pinned version — and reach for kind when you specifically need several disposable multi-node clusters fast, or you're automating cluster creation inside CI the way a DevOps pipeline would. Note too that none of these are the actual environment the CKA, CKAD, or CKS exam runs on — the Linux Foundation provisions a remote, browser-based cluster for the exam itself, so a local tool is a rehearsal space for the commands and the muscle memory, not a simulation of exam-day infrastructure; confirm exam-environment specifics on the official Linux Foundation page before you rely on any detail beyond that.

🎬 At the Pod Squad
🦥

Sol the Sloth: Before we start anything — how many services are we actually running today?

🦫

Benny the Beaver: Four. Plus the queue, plus the database I'm about to build locally with docker-env.

🦥

Sol the Sloth: Then the default four-Pod-sized VM isn't enough room. --cpus=4 --memory=8192, before anyone applies a single manifest.

👺

Gizmo the Gremlin: Or skip the VM headache entirely — --driver=none, runs right on the host, no waiting around. 🤑

🐢

Timmy the Turtle: On a shared laptop, no. none runs kubelet as root with zero isolation from everything else on that machine — that's not a shortcut, that's a wide-open door.

🦊

Foxy: And once it's up — the checkout Service has been <pending> for ten minutes. Something's wrong with the LoadBalancer.

🦥

Sol the Sloth: Nothing's wrong with it. There's no cloud sitting next to a laptop to hand out an IP — that's what minikube tunnel is for, and it has to actually be running, in its own terminal, the whole time.

🐢 Timmy's checkpoint

1. What are the two driver families minikube supports, and what's the real isolation difference between them? 2. Why does a Deployment sometimes ignore an image you just loaded with minikube docker-env, and what field fixes it? 3. Why does a LoadBalancer-type Service sit at <pending> on minikube by default, and what command changes that? 4. Name two things minikube's addon system gives you that a bare kind cluster doesn't install for you. 5. What's the actual risk of the none driver, specifically? 6. Why should you pass --kubernetes-version explicitly when practicing for the CKA or CKAD? 7. In one sentence, when would you reach for minikube over kind, and when the reverse?

Check your answers
  1. Container drivers (docker, podman) run the node as a container sharing the host's kernel; VM drivers (virtualbox, hyperkit/qemu, kvm2, hyperv) run it inside a genuinely separate guest kernel behind a hypervisor. Container drivers start faster; VM drivers give a real, separate kernel boundary.
  2. Because the tag in spec.containers[].image has to match exactly what was loaded, and because a latest tag defaults imagePullPolicy to Always, which makes the kubelet try to pull from a registry instead of using the image already on the node. Setting imagePullPolicy: Never explicitly fixes it.
  3. There's no real cloud provider next to a laptop to hand out an external IP, so the field that would normally get populated by a cloud controller just never does. minikube tunnel, kept running in its own terminal, routes traffic from a real local IP to the Service and populates status.loadBalancer.ingress to match.
  4. An addon-installed real ingress controller (ingress-nginx) and metrics-server are the two most commonly reached for — a bare kind cluster has neither installed and leaves that entirely to you, along with the dashboard and in-cluster registry addons.
  5. It runs kubelet and the container runtime directly on the host as root, with no VM or container isolation boundary between the cluster and the rest of the machine — a much wider blast radius than any other driver, and Linux-only.
  6. Because minikube's default Kubernetes version is whatever that minikube release ships, not necessarily the version the exam blueprint is currently pinned to — practicing against a drifted version risks a flag or field behaving slightly differently than what actually shows up on exam day.
  7. Reach for minikube for the fullest local approximation of a real cluster — addons, a fake LoadBalancer, exam-style practice; reach for kind when you need several fast, disposable, multi-node clusters, especially inside CI.