Skip to content

QUAYZ v0.1.0

Latest

Choose a tag to compare

@PNX89 PNX89 released this 28 Aug 21:22
· 8 commits to main since this release

A crash loop and an OOMKill told apart by the one field that separates them, with the failure no single field finds named beside them.

What it is. Five ways a deploy ends with a pod that is not serving, each produced against a kind cluster the test run creates and destroys, each read with six instruments. A Helm chart that produces the failures by name, three measurement harnesses, a Go controller that classifies a container status into a verdict with its evidence, and a Terraform module for the cluster. 135 tests run with nothing installed; three more create a cluster and are in the job that says so.

The measurements.

state phase restarted waiting reason terminated reason exit endpoints ready
healthy, the control Running no none none none 2
image cannot be pulled Pending no ImagePullBackOff none none 0
crash loop Running yes CrashLoopBackOff Error 1 0
killed for memory Running yes CrashLoopBackOff OOMKilled 137 0
alive but never ready Running no none none none 0
  • A crash loop and an OOMKill agree on four of six columns. The OOMKilled container printed zero log lines mentioning a problem; the crash-looping one printed the single line the process chose on its way out.
  • No single field finds the pod that is alive and never ready. Its row differs from a healthy pod in one column, and that column reads the same for all four failures.
  • terraform plan -detailed-exitcode over a helm_release exits 0 for a Deployment hand-scaled from two replicas to five. helm get values | helm template | kubectl diff exits 1 on the same edit.
  • With -refresh=false, terraform reports no changes and exits 0 against a cluster that has been deleted.
  • kubectl get endpointslice -o wide printed both pod addresses with zero endpoints ready.
  • helm upgrade --atomic exits 1 leaving 2 of 2 ready; a bare helm upgrade exits 1 leaving 2 ready of 3 total, which is why counting only ready pods makes a stuck rolling update look healthy.

Three things in client-go that changed the code. A nil field selector segfaults cache.NewListWatchFromClient in v0.37. The fake clientset returns nil from CoreV1().RESTClient(). WatchListClient has defaulted to true since Kubernetes v1.35, so counting List calls proves nothing about resumption and the resourceVersion of the re-watch is the honest instrument.

What it does not establish. One node, one namespace, one release, and a cluster that lives for the length of a test run. Nothing here is evidence about node failure, zone failure, capacity, autoscaling, a service mesh or behaviour under load. There is no production cluster behind this repository.

Supply chain. The controller image is built twice from nothing and the manifest digests compared, then built a third time with an SBOM and provenance; the image manifest inside that attested index must equal the digest the comparison proved before anything is signed, and on main the digest that landed in the registry is compared to it again. Signed keyless with cosign and verified against this workflow on this branch, not merely against this repository.

Card: https://pnx89.github.io/QUAYZ/