Modern Kubernetes Is Delightfully Elegant and Almost Even Small
I spent an afternoon mapping every Kubernetes artifact that touches one production app — an agentic ITSM platform I run — and all of its dependencies. Postgres and pgvector, a workflow engine, a message bus, an identity stack, an object store, an LLM gateway, observability. I expected a sprawl. I expected YAML wallpaper.
Here is the entirety of what the app declares to run in prod:
- One
HelmRelease— a shared platform chart, a dated OCI image, a route, ten secrets bound throughenvFrom. - One Flux
Kustomizationto reconcile it. - One kustomize file that says
resources: [helmrelease.yaml].
Three files. The app is a chart reference, an image tag, and a route. Everything else — the database, the workflow engine, the message bus, identity, storage, tracing — is a shared platform service living in its own namespace, consumed by name. The app doesn't own a Postgres. It points at one.
The reputation is wrong
That's the elegant part, and it's worth saying plainly because the reputation of Kubernetes is the opposite. The reputation is a thousand CRDs and a certification exam and a manifest longer than your arm. The reality of running an app on a well-built cluster is closer to: pick a chart, ship an image, bind some secrets. The platform did the hard parts already, and it did them once, for everyone.
The concept set is tiny
List every Kubernetes kind a human has to think about to get this app to prod and it isn't a wall. It's:
- Flux source:
GitRepository,HelmRepository. - Flux reconcile:
Kustomization,HelmRelease. - Core:
Namespace,ServiceAccount,Secret,ConfigMap,Service,Deployment. - Networking: a Gateway
HTTPRoute, aNetworkPolicy.
That's the whole vocabulary. The dependency graph between them is beautiful too:
the cluster's own repo bootstraps Flux, Flux reconciles infrastructure
(networking, storage, the shared database), which unblocks platform (the
workflow engine, the bus, identity, observability), which unblocks tenants,
which unblocks apps. A layered chain where each tier reconciles only once the
one below it is healthy. You can read the cluster's boot order off the
dependsOn list. That isn't accidental complexity; that's a system that knows
what it wants.
And one in-house chart — kilter-app — does the last trick. It bakes in the
route, the network policy, the secret convention. Every app is an instance of it.
So an app isn't a folder of manifests; it's a chart version and an image tag.
The platform's opinions live in one place and propagate to everyone.
It's almost even small
Here's the "almost," and it's the interesting part.
Those three files reference a namespace, two service accounts, and ten secrets. I
went looking for them in the GitOps repo. They aren't there. None of them. The
namespace doesn't exist as a manifest. The service accounts don't. The ten
<app>-postgres, <app>-temporal, <app>-kafka secrets — the entire
environment the app runs in — are not committed anywhere.
They're synthesized at runtime by an operator. On deploy, a controller looks at
the shared services, provisions a database and a user for the app in the shared
Postgres, registers a workflow namespace, cuts a bucket and an object-store key,
and writes a per-app secret for each into the app's namespace. Then it commits
the HelmRelease into the Flux repo, and Flux takes it the rest of the way.
So the declared app is three files and ten concepts — genuinely small. The
running app depends on a controller that isn't in those files, doing work that
isn't in git. The elegance is real; the smallness is "almost," because there's a
hidden imperative layer holding it up. A git log of the prod repo will not tell
you how the app got its database.
Why that's a trade, not a bug
This was built on purpose, and I'd do it again. The operator is what gives the
deploy its Vercel feel: one command, image built and pushed, app live at its URL,
no kubectl or helm or flux on my laptop. The cost of that feel is that git
is co-authored by a machine instead of owned by a human. The reward is that I
don't hand-write ten secrets and a namespace and a service account and a database
migration per app. The platform does.
The honest version of the title, then, is: modern Kubernetes is delightfully elegant, and it would be small too, if the last mile of an app — its namespace, its identity, its credentials against every shared service — lived in git instead of being provisioned at runtime.
The path to actually small
The path is clear, and it isn't technical. Either commit the operator's outputs
so they're reviewed as the source instead of generated, or make the operator a
reconciler of a declared custom resource rather than a writer into the repo —
read a KilterApp CR, converge toward it, stop pushing. Either way the
declarative surface keeps its elegance; the seam closes. (That second option is
exactly the agent-native move: a
capability that drifts becomes a CRD plus a controller, addressable as text.)
The part I like most
The reason I could map this whole thing in an afternoon — the reason I'm confident the elegant layer is as small as it is — is that it's all text. GitRepositories, HelmReleases, namespaces, routes: files I can read, grep, diff, and reason about. The hidden layer is the one that isn't text yet. Which is exactly the argument for closing the seam by making it text too.
Modern Kubernetes is at its best when it's a small set of declarative files reconciled by a controller that reads them. It is almost there.
Where to go next
- Read why modern Kubernetes is the agentic substrate — the convergence that made this concept set canonical.
- See what makes a platform agent-native — why making the operator a reconciler is the right primitive.
- See the Kilter Platform — the shared chart that keeps an app to three files.
- Start your free trial — the full platform, 7 days, no card.