Transmission 015 · 2026-06-18

The cluster ran out of room. Two pods broke. Scaling down fixed both.

A Helm upgrade to revision 5 triggered new monitoring pods on a node already out of CPU and memory. Grafana froze during a Docker Hub handshake. kube-state-metrics crashed 11 times. Scaling the API down to 2 replicas gave the node enough room. Both pods recovered.

014 verified the pipeline and left one thing open: confirm the Grafana utilisation panels after the cAdvisor TLS fix. I came in today to do that. The node had other plans.


The constraint

The cluster started with kube-state-metrics already at 100 restarts over 8 days:

$ kubectl get pods
prometheus-kube-state-metrics-678b9d8db-9sxlp   1/1   Running   100 (86s ago)   8d

The logs showed the liveness probe at /livez returning 503 repeatedly:

W0618 06:38:38.482931  1 server.go:556] Failed to contact API server for /livez: got 0
W0618 06:38:46.481706  1 server.go:556] Failed to contact API server for /livez: got 0

100 restarts on a metrics agent is not normal. The node was already under pressure before I ran anything.


The proof

The Helm upgrade landed. The node did not have room for what came next.

$ helm upgrade prometheus prometheus-community/kube-prometheus-stack \
  -f kubernetes/values.yaml --namespace default --cleanup-on-fail
Release "prometheus" has been upgraded. Happy Helming!
REVISION: 5
STATUS: deployed

The upgrade succeeded. New pods started spinning up — a new Grafana, a new kube-state-metrics, a new operator. The HPA was still enforcing a minimum of 3 model API replicas. The node was already carrying the full monitoring stack plus five API pods. The scheduler could not fit one more:

$ kubectl describe pod simple-model-api-deployment-6ff5fb88cb-p5gcx
Events:
  Warning  FailedScheduling  default-scheduler  0/1 nodes are available:
  1 Insufficient cpu. preemption: 0/1 nodes available:
  1 No preemption victims found for incoming pod.

Grafana stuck in ContainerCreating for 40 minutes

The new Grafana pod 7dc9bbf8cf-dzvsg sat at 0/3 ContainerCreating for 40 minutes. The only event was a pull that never finished:

Events:
  Normal  Pulling  39m  kubelet  Pulling image "docker.io/grafana/grafana:13.0.2"

I checked whether the image was reachable inside the node:

$ minikube ssh -- sudo crictl pull docker.io/grafana/grafana:13.0.2
FATA[0016] pulling image: Error response from daemon: Head
"https://registry-1.docker.io/v2/grafana/grafana/manifests/13.0.2":
unable to decode token response: context deadline exceeded

crictl failed. The Docker Hub token handshake timed out — the node’s network link to the registry froze during the TLS exchange. I tried the raw Docker daemon:

$ minikube ssh -- docker pull docker.io/grafana/grafana:13.0.2
Digest: sha256:5dad0df181cb644a14e13617b913b261a54f7d4fd4510721dba420929f35bea2
Status: Image is up to date for grafana/grafana:13.0.2

The image was already on the node. crictl was hitting the registry for a manifest check even though nothing needed downloading. Force-deleting the stuck pod alone would not fix it — the new pod would hit the same frozen path. Pulling through the raw Docker daemon first bypassed the token check. Then I deleted the pod:

$ kubectl delete pod prometheus-grafana-7dc9bbf8cf-dzvsg --grace-period=0 --force
pod "prometheus-grafana-7dc9bbf8cf-dzvsg" force deleted

A new pod lsw9t spawned and grabbed the local image immediately.


kube-state-metrics in CrashLoopBackOff

While Grafana was stuck, kube-state-metrics hit CrashLoopBackOff at restart 10:

prometheus-kube-state-metrics-6cc7c56db5-6vdrv   0/1   CrashLoopBackOff   10 (22s ago)   63m

I did not touch it. The node had no CPU left to keep it stable. The fix came from reducing the API replicas.


Scaling down freed the node

I deleted the HPA and scaled manually:

$ kubectl delete hpa simple-model-api-hpa
horizontalpodautoscaler.autoscaling "simple-model-api-hpa" deleted

$ kubectl scale deployment simple-model-api-deployment --replicas=2
deployment.apps/simple-model-api-deployment scaled

Two replicas instead of five gave the monitoring stack room to breathe. kube-state-metrics stopped crashing and stabilised at restart 11 on its own. Grafana lsw9t climbed from 2/3 to 3/3. The Grafana container crashed twice before it held — exit code 2 both times:

    State:      Running
      Started:  Thu, 18 Jun 2026 10:59:09 +0300
    Last State: Terminated
      Reason:   Error
      Exit Code: 2
      Started:  Thu, 18 Jun 2026 10:56:25 +0300
      Finished: Thu, 18 Jun 2026 10:59:08 +0300
    Ready:      True
    Restart Count: 2

Final state:

$ kubectl get pods
alertmanager-prometheus-kube-prometheus-alertmanager-0   2/2   Running   0    73m
prometheus-grafana-7dc9bbf8cf-lsw9t                      3/3   Running   2    17m
prometheus-kube-prometheus-operator-7ff545b6fb-pdrdt     1/1   Running   0    74m
prometheus-kube-state-metrics-6cc7c56db5-6vdrv           1/1   Running   11   74m
prometheus-prometheus-kube-prometheus-prometheus-0       2/2   Running   2    2d1h
simple-model-api-deployment-6ff5fb88cb-sb2f6             1/1   Running   0    95m

HPA back with corrected minimums

$ kubectl apply -f kubernetes/hpa.yaml
horizontalpodautoscaler.autoscaling/simple-model-api-hpa created

$ kubectl get hpa simple-model-api-hpa
NAME                   REFERENCE                                TARGETS                        MINPODS   MAXPODS   REPLICAS
simple-model-api-hpa   Deployment/simple-model-api-deployment   cpu: 0%/70%, memory: 73%/80%   2         10        2

Minimum replicas is now 2, down from 3. The node can hold the monitoring stack and the API together without hitting the ceiling.


Where this sits

ItemStatus
Helm upgrade — revision 5Done
Grafana stuck in ContainerCreating — 40 minutesFixed — local image pull then force delete
kube-state-metrics CrashLoopBackOffRecovered — node had room once API scaled down
API replicas reduced to 2Done
HPA minimum corrected to 2Done
Grafana utilisation panels — cAdvisor data flowingNot verified — next session

Both problems came from the same place. The node ran out of room and the monitoring stack started falling apart. Scaling down one deployment fixed two broken pods.

← Back to Transmissions