Skip to content
Technology choices

Technology choices

A stack list tells you what is installed. It does not tell you what the alternative was, or what the choice cost — which is the part worth reading if you are deciding whether to copy any of it.

Versions are not here on purpose; they belong in the technology stack reference, where each one cites the file that pins it.

The principles behind the picks

Prefer the boring option, except where boring means unsupported. Most choices here are conventional. The exceptions are deliberate and each has a decision record.

Prefer an operator with a CRD to a Helm chart with a values file. A CRD is an API that other things can compose against; a values file is a configuration blob that only its own chart understands.

Prefer open source without a licence cliff. Several picks below are about avoiding a rug-pull rather than about technical merit.

Pay for a choice once. Where a component is load-bearing, it is worth being deliberate; where it is replaceable, it is not worth agonising over.

The decisions with records

ChoiceOverWhyRecord
KCL for compositionspatch-and-transform, Go templatesReadable conditionals and loops; testable before deployADR-0001
EKS Pod IdentityIRSASimpler trust policies, better audit trail, no OIDC managementADR-0002
vLLM production stackKServeFewer moving parts for the serving case actually neededADR-0003
S3 Files for model weightsalternatives evaluated in the recordAccess pattern and cost fitADR-0004
GKE Standard with self-managed CiliumAutopilot, Dataplane V2Keeps one CNI across cloudsADR-0005
ComputeClass on GCPKarpenterThe GCP Karpenter provider is not production-readyADR-0006
Cloud-shaped platform APIs, neutral developer APIsone abstraction for bothPortability where it pays, honesty where it doesn’tADR-0007

The ones without records

Not every choice needed an ADR. The short reasoning:

Flux over Argo CD. Flux’s controllers compose as CRDs and its dependsOn model expresses the ordering this platform needs. Argo CD would also have worked; this is a preference, not a verdict.

Cilium over the VPC CNI. eBPF datapath, kube-proxy replacement, network policy and Gateway API from one component instead of four. The cost is real and documented: prefix delegation interacts badly with the Gateway API L7 proxy, and WireGuard is load-bearing as a workaround rather than a performance choice.

VictoriaMetrics over Prometheus. Lower resource consumption at the same retention, and an operator with CRDs for scrape config and rules. VictoriaLogs and VictoriaTraces then follow for consistency of query surface and operational model.

OpenBao over Vault. An open-source fork after Vault’s licence change. The trade-off is a smaller ecosystem and occasional rough edges — the 2.6 line carries an open upstream deadlock that this platform works around with serialised writes rather than a version pin.

Crossplane over Terraform for application infrastructure. Not because Terraform is worse at describing cloud resources — it is better — but because a claim reconciled by a controller is continuously enforced, while a Terraform plan is only true at apply time. OpenTofu still owns the layers below Kubernetes, which is why both are here.

Tailscale over a bastion or VPN appliance. Identity-based access with ACL tags, no host to patch.

Reading on