Engineering Note

Running production k3s on ARM with GitOps

The orchestration layer behind Badger Cloud is small on purpose: lightweight Kubernetes, ARM compute, and Git as the single source of truth.

Engineering note · 29 June 2026

Why k3s, and why ARM

We didn't need a sprawling managed Kubernetes service to run a focused e-commerce platform. We needed something dependable, cheap to operate, and efficient. That led us to k3s — a fully CNCF-certified Kubernetes distribution packaged as a single lightweight binary — running on ARM64 (Ampere-class) nodes.

ARM gives us strong performance-per-watt, which keeps both the bill and the energy draw down (the case for that is on our sustainability page). k3s keeps the control-plane overhead small enough that a modest node can run it comfortably, leaving the worker nodes free for actual workloads.

Git is the source of truth

Every piece of the platform — workloads, monitoring, ingress, even this landing page — is declared as YAML in a single Git repository. Flux runs inside the cluster and continuously reconciles the live state to match the repository. There is no manual kubectl apply in normal operation: you open a merge request, it gets validated, it merges, and the cluster converges.

We use Kustomize overlays to keep a clean separation between base manifests and per-environment configuration (development vs production), so the difference between environments is explicit and reviewable rather than hidden in scripts.

The interesting gotcha: an IPv6-only worker fleet

To keep costs and address usage lean, our worker nodes are IPv6-only, with the control-plane node acting as a NAT gateway for outbound IPv4. It's efficient, but it creates a genuine dependency worth designing around: when the control plane restarts, the workers briefly lose outbound IPv4 connectivity.

The lesson is to treat that node's maintenance as a deliberate, planned operation — drain, reboot in the quiet window, uncordon — and to keep application workloads on the workers so they keep serving traffic throughout. It's a reminder that "efficient" and "naive" aren't the same thing: the savings are real, but only if the failure mode is understood and handled.

Keeping it current, automatically

The cluster largely maintains itself. Worker nodes are upgraded by an in-cluster upgrade controller following a pinned plan; OS patching is automated; and node reboots are coordinated through a dedicated reboot daemon that operates only within a defined overnight window and announces itself to our team chat. The control-plane upgrade stays a deliberate, manual step — precisely because of the NAT-gateway dependency above.

Next: how we ship without downtime →