I wanted to learn a bit more about distributed systems, and after reading more of the 500 lines or less book, I wanted to have a crack at a mini version of K8S.
cmd/apiserver cmd/scheduler cmd/controller cmd/kubelet
(stores live (HTTP client) (HTTP client) (HTTP client +
here only) namespace runtime)
| | | |
+------ HTTP ------+------- HTTP ------+------- HTTP ------+
All components communicate through the API server over HTTP. cmd/miniku runs everything in a single process for convenience.
Miniku uses a Linux namespace-based container runtime. This way containers are isolated using kernel namespaces (PID, MNT, UTS) with pivot_root into an Alpine rootfs.
Requires sudo to run (namespace creation needs CAP_SYS_ADMIN).
Note: PodSpec.Image currently maps to Alpine minirootfs regardless of the image name specified.
> sudo go run ./cmd/miniku/Then in another terminal
> curl -X POST 127.0.0.1:8080/replicasets -d '{"name":"test","desiredCount":4,"selector":{"app":"test"},"template":{"image":"alpine","command":["/bin/sh","-c","while true; do sleep 1; done"]}}'
{"name":"test","desiredCount":4,"currentCount":0,"selector":{"app":"test"},"template":{"name":"","image":"alpine","command":["/bin/sh","-c","while true; do sleep 1; done"]}}
> curl 127.0.0.1:8080/replicasets
[{"name":"test","desiredCount":4,"currentCount":4,"selector":{"app":"test"},"template":{"name":"","image":"alpine","command":["/bin/sh","-c","while true; do sleep 1; done"]}}]
> curl 127.0.0.1:8080/pods
# pods with status "Running", each with a container IDNow our binary logs the following:
2026/02/04 15:27:54 scheduler: assigning pod test-d3950207 to node node-2
2026/02/04 15:27:54 scheduler: assigning pod test-3852c037 to node node-2
2026/02/04 15:27:54 scheduler: assigning pod test-50e73e92 to node node-1
2026/02/04 15:27:54 scheduler: assigning pod test-76e8a1ac to node node-1Very nice!
- API server (expose desired state)
- kubelet (afaik this is just an agent/worker that lives on a node)
- controller/manager (reconciliation loops for "uptime guarantees" and all that jazz.)
- rediscover (on restart, find matching containers and re-assign)
- scheduler (this will require multiple kubelets)
TODO
| Pod Status | Container State | Action |
|---|---|---|
| Pending | doesn't exist | Create container, update pod to Running |
| Pending | running | Just update pod to Running (recovered?) |
| Running | running | Nothing - we're converged |
| Running | exited | Update pod to Failed |
| Running | doesn't exist | Weird state - maybe re-create or mark Failed |
(heartbeat)
Kubelet ─────────────> NodeStore
|
V
NodeController ("is heartbeat stale?")
|
V
NotReady if stale
This project is purely for my own education. That means no LLM's, which also means it's not going to be production-ready code. The Pod spec is purposefully simple (name, img, state) because I do not need anything else for my goals. Turns out that was a lie