Case StudyInfrastructureSelf-HostingCloud#Kubernetes#Platform engineering#UAT#Production#Infrastructure as code

A small Kubernetes platform that can grow without becoming a maze

A compact platform built around clear boundaries, separate UAT and production environments, repeatable releases and recovery that has been tested rather than assumed.

Architecture diagram separating public application workloads, platform operations, data and recovery across UAT and production
Applications and operational services have clear homes. UAT and production use the same operating model but keep their data and credentials separate.

Small platforms rarely start as platforms. A first application lands on one server, monitoring follows on another, and six months later nobody remembers which backup covers what. This environment was designed before that pattern had a chance to settle in.

The brief was modest but serious: host internal services and automations, keep UAT away from production, limit public exposure and make recovery practical. Copying a hyperscale architecture would only have added machinery. The useful question was much simpler: can someone understand what is running, where it belongs and how to recover it when something fails?

Draw the boundaries before choosing the tools

Application workloads and operational services live in separate areas. The applications serve traffic. The operational side handles deployment, monitoring, automation and the services needed to keep the platform under control.

That boundary prevents a busy application from quietly consuming the capacity used to observe it. It also gives every new workload an obvious home. During an incident, fewer ambiguous dependencies means less time spent reconstructing the platform from memory.

Use the same operating model in UAT and production

UAT and production run on separate infrastructure and never share application data or credentials. Their deployment model is deliberately similar, so UAT exercises the same assumptions that matter later: routing, storage, configuration, migrations and health checks.

The two environments do not need identical capacity. They do need the same shape. Otherwise a successful UAT test proves very little about the production release.

Release diagram showing one immutable artefact moving from build to UAT evidence and production
The artefact moves forward. Environment data and credentials do not.

Build once, then promote the same artefact

Each release produces an immutable container image. That exact image is deployed to UAT, tested through the public path and then promoted to production. Rebuilding between environments would introduce a new variable at the point where confidence matters most.

The infrastructure definitions record the intended image and configuration. A change can be reviewed before deployment, and rollback has a known target instead of a vague instruction to restore the previous version.

Design recovery alongside deployment

A healthy workload says nothing about whether its data can be recovered. Persistent data follows a separate backup path, and releases that can alter data start with a verified backup. Restore procedures are written down and exercised.

The finished platform is intentionally compact. It can take on more services without hiding them inside an unlabelled collection of servers, and it stays understandable when the person operating it is under pressure.

← All field notes