In the previous chapters we agreed on why we need a local Kubernetes and what "production-like" means. Now for the lay of the land. There are a lot of tools around local Kubernetes development, and at first it's easy to drown: k3d, kind, minikube, Helm, Kustomize, Tilt, Skaffold, Telepresence, k9s... It sounds like an incantation. In reality, each one handles its own little piece, and once you sort them onto shelves, the picture becomes simple.

This chapter is an overview. We won't configure anything by hand here (we'll start doing that in chapter 4); instead, we'll figure out who does what and why, for our running example — the myapp service (an HTTP API on Python 3.12 + FastAPI, port 8080, depending on PostgreSQL) — we ultimately chose k3d + Tilt.

Two approaches: a local cluster vs. connecting to a remote one

Before comparing specific utilities, it's important to understand that there are two fundamentally different ways to get an "almost-production" development loop.

Approach 1: all of Kubernetes on your machine. You spin up a full (if small) cluster locally — via k3d, kind, minikube, Docker Desktop, or Rancher Desktop — and deploy your service into it using the same manifests that will go to production. Everything is local; nothing depends on the network or on shared staging environments. This is the path of our article.

Approach 2: your local code connects to a remote cluster. Here the cluster lives somewhere on staging, and you "plug" your locally running process into it — as if it were running right inside a Pod. This way you don't have to keep the whole cluster on your laptop, and your service can see the real neighboring services on staging. There's a separate class of tools for this: Telepresence, mirrord, Gefyra.

A quick word about them, because you'll surely hear of them:

  • Telepresence builds a VPN/tunnel to the cluster, installs a Traffic Manager and a sidecar into it, and can intercept a service's traffic and route it to your local process. It requires root privileges on your local machine (it brings up a system daemon) and modifies the cluster.
  • mirrord works differently: it injects itself into your local process through mechanisms like LD_PRELOAD/DYLD_INSERT_LIBRARIES and intercepts libc calls (network, files, environment variables), swapping them out for "as if I were inside the Pod." It needs neither root nor containerization of your code — a kubeconfig is enough. By default it runs in mirror mode (it mirrors traffic, which is safe for a shared staging environment), but it can also steal.
  • Gefyra uses a VPN, works without root, but only for code packaged in a Docker container, and it does not swap out files or environment variables.

The differences are conveniently summarized in the canonical breakdown on the kubernetes.io blog: only Telepresence needs root; swapping files and env is supported by Telepresence and mirrord (Gefyra does not); and only mirrord can handle several local processes at once. For details on mirrord itself, see the official MetalBear site (note: the old mirrord.dev address now redirects there).

1# Approach 2 in practice (for general understanding; we don't use it in this article):
2telepresence connect
3telepresence intercept myapp --port 8080      # requires root
4# or without root:
5mirrord exec --target pod/myapp -- uvicorn app:app --port 8080

This second approach is wonderful, but it has its own price: you need a live remote cluster, its upkeep, and network access — and for a beginner that's an extra layer of magic. So from here on we focus on approach 1 — everything local.

Docker and kubectl — the foundation

Two tools sit at the base of everything else, and without them the stack simply won't start.

Docker is the container engine. Here's an important point that surprises many: local clusters run their Kubernetes nodes not on "bare metal" and not in the cloud, but as ordinary Docker containers on your machine. That's how k3d, kind, minikube with the docker driver, and Docker Desktop all work. In other words, a Kubernetes node is a container with Kubernetes running inside it, and inside that run your Pods. No Docker (or compatible runtime) — no cluster.

kubectl is the official Kubernetes CLI and your main channel of communication with the cluster. Through it you apply manifests, check state, read logs, forward ports, and shell into Pods:

1kubectl apply -f deployment.yaml          # apply a manifest
2kubectl get pods -n myapp                  # list Pods in the myapp namespace
3kubectl logs -f deploy/myapp -n myapp      # logs in real time
4kubectl port-forward svc/myapp 8080:8080 -n myapp   # forward a port to localhost
5kubectl exec -it deploy/myapp -n myapp -- sh        # shell inside a Pod

One more important detail: kubectl has Kustomize built in (more on it below) — you can invoke it with the -k flag:

1kubectl apply -k ./overlays/dev

All the accelerators (Tilt, Skaffold) and visual utilities like k9s work on top of kubectl — under the hood they call the same Kubernetes API. So kubectl is worth knowing, even if in day-to-day work you'll live inside Tilt.

Local clusters: k3d, kind, minikube, Docker Desktop, Rancher Desktop

This is the very "box" that myapp will go into. All of the options give you a real Kubernetes API — the difference is in startup speed, resource appetite, and feature set.

  • k3d is a wrapper that runs k3s (a minimalist, certified Kubernetes distribution from Rancher/SUSE) inside Docker. The fastest startup and minimal memory consumption, with a handy built-in registry. Ideal for everyday development. An important caveat: k3d is a community project, not an official Rancher/SUSE product (its documentation says so explicitly).
  • kind (Kubernetes IN Docker) runs upstream Kubernetes, with nodes also as Docker containers and bootstrapping via kubeadm. It's CNCF-certified, supports multi-node and HA, and can build Kubernetes from source. It was created primarily for testing Kubernetes itself and for CI/conformance.
  • minikube is Kubernetes in a virtual machine or with a docker driver, with a large set of addons. The classic choice for learning and experimenting.
  • Docker Desktop ships a built-in single-node Kubernetes that you enable with a single checkbox. Convenient if you already have Docker Desktop installed, but with the caveat of "limited configuration options": there's less flexibility (multi-node, fine-grained tuning) than with k3d/kind.
  • Rancher Desktop is a GUI application built on k3s, aimed at native local development and testing in Kubernetes, including Helm charts.
1# This is how a cluster is created in the different tools (details in chapter 5):
2k3d cluster create dev                              # k3s in Docker, our choice
3kind create cluster --config kind-config.yaml      # multi-node for CI/conformance
4minikube start                                       # K8s in a VM/docker, for learning

Which to choose? The consensus of 2025–2026 material (for example, the oneuptime overview) boils down to this: kind or k3d give the best balance of speed and capabilities for development. Specific startup and RAM figures for the tools wander from one benchmark to another, so treat them as rough guidance: k3d usually starts very fast and uses little memory — which is exactly why it's pleasant to recreate the cluster constantly.

Helm and Kustomize — the format of production manifests

Remember the central idea of chapter 2: a local cluster is valuable because it accepts the same manifests as production — unlike docker-compose, which doesn't structurally match them. And in what form do those production manifests usually live? Most often — in Helm or Kustomize.

Helm is the Kubernetes package manager. Your application is packaged into a chart: a directory with Chart.yaml, values.yaml, and a templates/ folder. The manifests in templates/ are Go templates (with the Sprig function library) into which values from .Values are substituted. Helm gives you SemVer versioning, the concept of a release (an installed instance of a chart), rollbacks, dependency management, and chart repositories. According to CNCF data, around 75% of organizations use Helm, and in November 2025 Helm 4 was released — with native server-side apply. The chart structure is described in detail in the official Helm documentation.

1helm install myapp ./chart -f values.yaml -n myapp   # install the chart as a release
2helm upgrade myapp ./chart -n myapp                  # upgrade
3helm rollback myapp 1 -n myapp                       # roll back to revision 1

Kustomize is a different approach, without templates. You write base manifests (base) and apply overlays on top of them — patches for a specific environment (dev/staging/prod) via strategic merge or JSON 6902. There are ConfigMap/Secret generators. Kustomize, as we've already seen, is built into kubectl (apply -k). But it has no packaging, versioning, or rollback — for GitOps and rollbacks on top of Kustomize, people usually add ArgoCD or Flux.

1kubectl apply -k ./overlays/dev    # apply the overlay for dev

In practice, Helm and Kustomize don't fight to the death; they often complement each other: Helm to package and distribute the application, Kustomize to tidily edit manifests per environment. For myapp we'll work with manifests in detail in chapter 7.

Inner-loop accelerators: Tilt, Skaffold, DevSpace (and where Okteto/Garden fit)

The bare loop of "edit code → build image → push → deploy → look" in Kubernetes is excruciatingly slow. Inner-loop accelerators solve this pain — they automate building, updating, and watching for changes.

  • Tilt (OSS, Apache-2.0) automates the watch → build → update loop. The main feature is Live Update: syncing changed files directly into the running container without a full image rebuild. The configuration is described in a Tiltfile (essentially code in Starlark, a Python-like language), and there's a clear web UI — a big plus for a beginner. For details, see the Tilt documentation.
  • Skaffold (from Google, OSS) is a build/push/deploy pipeline with file sync, a skaffold debug command (deploy with an attached debugger), and profiles. It can deploy via kubectl, Helm, Kustomize, and even Cloud Run. It works client-side. See the Skaffold documentation.
  • DevSpace (an OSS CLI) emphasizes bidirectional file sync, hot reload, and dev containers right inside the cluster; the config is devspace.yaml. Also client-side. See the DevSpace documentation.

How that Live Update in Tilt is built — three building blocks (reference):

1# A snippet of the Tiltfile for myapp (details in chapter 8):
2docker_build(
3    'k3d-registry.localhost:5000/myapp',
4    '.',
5    live_update=[
6        sync('./app', '/code/app'),                                   # copy files into the container
7        run('pip install -r requirements.txt',                       # install dependencies...
8            trigger='requirements.txt'),                             # ...only if this file changed
9        fall_back_on('Dockerfile'),                                  # Dockerfile changes -> full rebuild
10    ],
11)

The idea: instead of "minutes" to rebuild the image, you get "seconds" to sync files into the live container. With FastAPI this pairs especially nicely with uvicorn --reload, which itself picks up changed .py files. Keep in mind: Live Update does not rebuild the image — it's a tool for a fast loop; the final production image is still built in full (that's exactly what fall_back_on on the Dockerfile/dependencies is for).

Separately — about two tools that are often mentioned in the same breath, even though they're about something else:

  • Okteto is about cloud dev environments: syncing your local code into a Pod of a remote/managed cluster. In spirit it's closer to the remote approach from section 3.1 than to a purely local accelerator.
  • Garden is graph-based automation: build/deploy/test are described as a dependency graph. It's useful for complex multi-service monorepos; for a single myapp it's overkill.

Of the local accelerators, Tilt, Skaffold, and DevSpace are the closest to us; Okteto and Garden solve adjacent problems. We'll go through Tilt in detail in chapter 8.

k9s and helper utilities

Once you have more than one Pod, constantly typing kubectl get/logs/describe gets tiring. This is where helper utilities come to the rescue.

k9s is a terminal-based UI for Kubernetes — essentially a "visual kubectl." It's a full-screen interface in the terminal with vim-style navigation, where you can see Pods, nodes, and Deployments in real time, and perform common operations with keystrokes. Among the frequent hotkeys (official site): l — logs, s — shell into a Pod, d — describe, Ctrl-d — delete, plus port-forward, scale, RBAC viewing, and :xray — a tree-style overview of related resources. It's very handy that k9s color-codes contexts — you can paint the production cluster red so you don't accidentally wreak havoc.

1k9s        # launch; then navigate with keys: :pods, :svc, :xray deploy, etc.

What else is worth knowing (we'll install these, but won't dig deep):

  • kubectx / kubens — quick switching of contexts and namespaces.
  • stern — stream logs from several Pods at once by selector.
  • krew — a plugin manager for kubectl.

These little things save you from drudgery; we'll cover setting up your workstation in chapter 4.

Why the article chose the k3d + Tilt combo

Let's bring it all together. Local Kubernetes development has two main pains: (1) you need a realistic cluster that accepts real production manifests, and (2) you need a fast edit→result loop. Our choice covers both.

k3d gives you a real Kubernetes API (via k3s) with very fast startup and modest memory consumption. That means we get parity with production manifests (Helm/Kustomize) rather than a docker-compose surrogate, and we don't turn the laptop into a space heater in the process. The cluster is cheap to recreate — and that's invaluable when you're learning and regularly breaking everything.

Tilt with Live Update compresses the inner loop from minutes to seconds, codifies the entire dev setup in a Tiltfile, deploys through real manifests, and — a particular bonus for a beginner — shows a clear web UI where you can see builds, logs, and resource state all in one place.

Together, k3d + Tilt cover both pains, are fully local, and are OSS and free. The alternatives are worthy: Skaffold and DevSpace solve a similar problem (if their style suits you better — give them a try); Telepresence and mirrord are a different, "remote" approach; Okteto and Garden are a platform and complex-graph automation, respectively. For a single myapp service that you're preparing for its first deploy, k3d + Tilt is the shortest and most understandable path.

At a glance

ToolRoleIn this series
DockerContainer engine; runs cluster nodesFoundation
kubectlOfficial CLI to the Kubernetes APIFoundation
k3dLocal cluster (k3s in Docker)Chosen
kind / minikubeAlternative local clustersAlternatives
Helm / KustomizeProduction manifest formatManifests
TiltInner-loop accelerator (Live Update)Chosen
Skaffold / DevSpaceAlternative acceleratorsAlternatives
Telepresence / mirrord / GefyraConnect local code to a remote clusterDifferent approach
k9s, kubectx/kubens, stern, krewHelper utilitiesConvenience

In the next chapter we'll set up the workstation: install everything needed and make sure the tools are in place.

Sources

Want help choosing your local Kubernetes tooling?
Not sure which local Kubernetes tools fit your team? I can help you pick the right stack and wire up a fast, production-like local setup.