Skip to content

0020. Kubernetes, GitOps, secrets and benchmark tools

Status

Accepted

Context

Projects that use this image increasingly deploy to Kubernetes with Flux, keep secrets in git as encrypted files, move images between registries, and need to measure how fast a VM or disk is. The image had none of the CLIs for that: kubectl, flux, crane, sops, age, sysbench and fio were all missing. Installing them at runtime does not work, because apk add needs root (sudo is scoped to four maintenance scripts) and the egress allowlist ships locked down.

Constraints specific to this image:

  • Alpine/musl (ADR 0001) on amd64 and arm64 (ADR 0012).
  • Binaries are Renovate-pinned and checksum-verified in the builder stage (ADR 0008); packages that Alpine builds natively come from apk, unpinned, like the rest of Layer A.

Decision

Two routes, chosen per tool:

Pinned upstream binaries (builder stage, one ARG + # renovate: comment each, sha256sum -c before install, both arches):

Tool Source Checksum source
kubectl dl.k8s.io/release/v<ver>/bin/linux/<arch>/kubectl kubectl.sha256 sidecar. It holds only the digest, so the check line is built by hand.
flux fluxcd/flux2 release tarball flux_<ver>_checksums.txt
crane google/go-containerregistry release tarball (only crane is extracted, not gcrane or krane) checksums.txt
sops getsops/sops release, a bare binary sops-v<ver>.checksums.txt

These four go into the existing cli-tools Renovate group, with the kubernetes/kubernetes release tag tracked for kubectl.

Alpine packages (Layer A, unpinned):

  • sysbench and fio are C programs, so the apk build is the natural route.
  • age is available as an upstream binary, but upstream publishes no checksum file for it, only sigsum .proof sidecars. Alpine's signed package index is a stronger integrity check than HTTPS alone, so it comes from apk. The trade-off is that the version tracks the alpine:3.24 snapshot instead of Renovate; sops does not need the age CLI, since age support is built in.

Rejected:

  • All seven from apk. Alpine 3.24 carries every one of them, but the versions lag upstream (read from the aarch64 index: kubectl 1.36.1, flux 2.8.1, sops 3.12.2, crane 0.21.6, against upstream 1.37.2, 2.10.0, 3.13.3 and 0.22.1 at the time of writing). The repo pins CLI tools like gh and glab from upstream for the same reason, and kubectl and flux should be close to the cluster they talk to.
  • Helm, kustomize, k9s, kubeconform. Not requested at the time. kubectl has built-in kustomize. Helm, k9s and kubeconform were added later by the same route in ADR 0021.
  • gcrane and krane. They ship in the same crane tarball but target Google Cloud and Kubernetes auth helpers, which this image has no need for.

Consequences

Accepted:

  • The image gets larger (the arm64 flux and sops binaries measure 76 MB and 48 MB uncompressed, crane 11 MB; kubectl was not measured), and the Layer A change invalidates the layers below it for one build.
  • age, sysbench and fio update with the Alpine base, not with a Renovate PR.
  • No egress allowlist entries were added. The tools talk only to the clusters, registries and key servers a project configures; the examples/ allowlist already lists the common registries (commented out).

Not verified when this was written:

  • dl.k8s.io could not be reached from the authoring container (the firewall's resolved IPs had gone stale), so the kubectl URL layout follows the documented pattern and is confirmed only by the CI build.
  • The apk versions above were read from the aarch64 index; the x86_64 index was not inspected.