agentsclimarketplace

Kubernetes operations

Skill Goodsmileduck/claude-registry/plugins/kubernetes-skills/skills/kubernetes-operations

Community marketplace of Claude Code plugins: DevOps skill packs (Terraform, Kubernetes, CI/CD, cloud platforms, DigitalOcean), CLAUDE.md optimization, and diagramming — gated by a best-practices lint + security-audit CI.

Install
npx -y skills add Goodsmileduck/claude-registry --skill kubernetes-operations

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Debugs Kubernetes pods and controllers — FailedCreate, ImagePullBackOff, init-container failures, probe flapping, missing service endpoints, GKE NEG readiness. Use when a pod is not Running, a Deployment/StatefulSet shows FailedCreate, image pulls fail, or services lack endpoints.

SKILL.md

11.5 KB, as published. Nobody here has run it

Kubernetes — pod debug decision tree

For ArgoCD-managed resources, also check the argocd-operations skill: direct mutations are reverted by selfHeal within ~3 minutes.

When to invoke

The pod's STATUS column tells you which branch to take. Always start with:

kubectl config current-context                  # confirm cluster/env BEFORE anything
kubectl describe pod <pod> -n <ns> | tail -40   # events at the bottom
kubectl logs <pod> -n <ns> [-c <container>] [--previous]
kubectl get events -n <ns> --sort-by=.lastTimestamp | tail -20

The Events: section at the end of describe is the single highest-signal source. Read it before anything else.

Pre-flight: is this resource Argo-managed?

Before any kubectl edit/patch/apply -f fix, check whether the resource is GitOps-owned:

kubectl get <kind> <name> -n <ns> -o jsonpath='{.metadata.labels}{"\n"}{.metadata.annotations}{"\n"}'
# managed-by indicators: argocd.argoproj.io/tracking-id, meta.helm.sh/release-name, app.kubernetes.io/managed-by

If managed: fix the source (chart/values/kustomization), not the cluster. See the argocd-operations skill.

Branch 1 — Pod never created (FailedCreate on the controller)

The pod doesn't exist yet; the ReplicaSet/StatefulSet/Job can't create it.

# Look at the controller's events, not the pod's (the pod isn't there)
kubectl describe rs <rs-name> -n <ns> | tail -30
kubectl describe statefulset <ss> -n <ns> | tail -30
Event message containsCauseFix
forbidden: violates PodSecurityPod Security Admission rejecting the spec at the namespace's PSA level (restricted, baseline)Either relax the namespace label pod-security.kubernetes.io/enforce or fix the pod spec (drop capabilities, runAsNonRoot, etc.)
exceeded quota / forbidden: exceeded quotaResourceQuota in the namespacekubectl describe resourcequota -n <ns> to see what's exhausted
admission webhook "..." denied the requestA ValidatingWebhookConfiguration rejected the podkubectl get validatingwebhookconfigurations, inspect the named webhook's policy; the webhook's controller logs explain why
serviceaccount "X" not foundSA referenced in pod spec doesn't exist in this namespaceCreate the SA, or fix the spec; common with Helm chart values mismatch
persistentvolumeclaim "X" not found (StatefulSet)The PVC template name doesn't match what was provisioned, or volumeClaimTemplate changedStatefulSet PVCs are immutable; delete and recreate, or revert the template
error looking up service account ... no tokenServiceAccount exists but no token Secret (IRSA / GKE WI setups)Check Workload Identity bindings (GCP) or service-account token projection

Branch 2 — Pod is Pending

Pod was created but never scheduled. Look at scheduler events:

kubectl describe pod <pod> -n <ns> | grep -A 10 Events
Event reasonCauseDiagnostic
FailedScheduling: 0/N nodes are available: insufficient cpu/memoryNo node has free capacitykubectl describe nodes | grep -E "Name:|Allocatable|Allocated"; consider cluster autoscaler logs
FailedScheduling: ... node(s) didn't match Pod's node affinity/selectorAffinity / nodeSelector doesn't match any nodeCompare pod's affinity/nodeSelector against kubectl get nodes --show-labels
FailedScheduling: ... node(s) had untolerated taintTainted nodes (e.g. GKE Autopilot system pools, spot-only pools)Add matching tolerations to the pod, or schedule to a different pool
FailedScheduling: ... volume node affinity conflictThe PV is in zone A, no node in zone A has capacityCommon with regional GKE + zonal PD; need a node in the PV's zone
FailedScheduling: ... topology spread constraint(s) not satisfiedtopologySpreadConstraints can't be honoredInspect the constraint's maxSkew/whenUnsatisfiable; consider ScheduleAnyway

Branch 3 — Image pull failures (ImagePullBackOff, ErrImagePull)

Container status waiting.reason reveals the specific failure:

kubectl get pod <pod> -n <ns> -o jsonpath='{.status.containerStatuses[*].state.waiting}{"\n"}'
ReasonMeaningFix
ErrImagePullFirst pull failed (registry auth, image absent, network)Read the next event for the underlying message
ImagePullBackOffRepeated ErrImagePull — kubelet is backing offSame as ErrImagePull; the backoff just means it's been failing a while
ImageInspectErrorImage manifest fetched but inspection failed (often signature/policy verification)Check sigstore / image policy controllers (Kyverno, Gatekeeper, Connaisseur)
Event: manifest unknown / not foundTag or digest doesn't exist in the registryVerify the tag with docker manifest inspect <ref>
Event: unauthorized / deniedimagePullSecret missing, expired, or wrongInspect: kubectl get sa <sa> -n <ns> -o yaml | grep imagePullSecrets; verify secret with kubectl get secret <s> -n <ns> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
Event: toomanyrequests (Docker Hub)Anonymous rate limit hit (100/6h)Use authenticated pulls or a registry mirror
Event: dial tcp: i/o timeoutNetwork egress to registry blockedCheck NetworkPolicies, NAT, firewall, private cluster master-auth

For private GCR/Artifact Registry on GKE: the node's SA needs roles/artifactregistry.reader on the AR repo, or use Workload Identity bound to a GSA that has it. Anonymous pulls from gcr.io/google-containers/* style public mirrors don't need auth.

Branch 4 — Init container failing

The pod status shows Init:CrashLoopBackOff, Init:Error, or Init:0/N. Containers run sequentially; one failure blocks the rest.

# Identify which init container by index
kubectl get pod <pod> -n <ns> -o jsonpath='{.status.initContainerStatuses[*].name}{"\n"}'
# Then read its logs
kubectl logs <pod> -n <ns> -c <init-container-name>
kubectl logs <pod> -n <ns> -c <init-container-name> --previous   # if it crashed
StateMeaning
Init:0/3 Pending for long timeInit container hasn't started — image pull failure (see branch 3) or volume mount failure
Init:CrashLoopBackOffInit container ran and exited non-zero, repeatedly — read its logs
Init:ErrorMost recent run exited non-zero, no backoff yet — read logs with --previous after the next attempt

Common init-container roles and their failure modes:

  • Wait-for-DB / wait-for-service scripts → DNS or network failure; check kubectl get svc -n <ns>, run nslookup <svc> from a debug pod
  • Volume permission fixers (chown) → SecurityContext.fsGroup mismatch or readOnly volume
  • Secret materializers (Vault Agent, External Secrets job-style) → the upstream secret source isn't ready or unauthorized

Branch 5 — Main container CrashLoopBackOff

The pod started but the container exits repeatedly.

kubectl logs <pod> -n <ns> --previous       # logs from the crashed instance
kubectl get pod <pod> -n <ns> -o jsonpath='{.status.containerStatuses[*].lastState.terminated}{"\n"}' | jq .

The terminated block shows exitCode, reason, and message:

exitCode / reasonLikely cause
137 + reason OOMKilledHit container memory limit — raise resources.limits.memory or fix leak
139 (SIGSEGV)Segfault — application bug
143 (SIGTERM)Graceful termination, but exiting fast enough to look like a crash — check probe behavior (branch 6)
1 + app-level logRead the logs; application config or startup error
reason Error exit 255Often crashloop right at PID 1 — entrypoint script bug

Branch 6 — Probe-induced flapping (Running but restarting)

Pod restarts but logs look fine. Suspect liveness probe killing a healthy container.

kubectl describe pod <pod> -n <ns> | grep -A 5 "Liveness\|Readiness\|Startup"
kubectl get events -n <ns> --field-selector involvedObject.name=<pod> | grep -i probe

Probe rules of thumb (the trap that keeps showing up):

  • Startup probe exists to protect slow-starting containers from liveness — set this for anything that takes >10s to be ready. Without it, slow startups get killed before they can answer the liveness probe.
  • Liveness probe kills the container on failure. Use it only for "deadlocked process" cases. Default to no liveness probe if you're not sure — readiness alone is safer.
  • Readiness probe controls service traffic only (the container stays alive, just leaves the endpoint set). Use it freely.
  • A single HTTP endpoint serving as both liveness and readiness is fine, but make sure it doesn't depend on downstream services — otherwise a temporary DB blip kills your pods.

Common misconfigurations:

  • initialDelaySeconds too small + no startup probe → liveness kills during startup → crashloop that looks application-side
  • periodSeconds smaller than the endpoint's typical latency → false negatives
  • Probe scheme HTTPS against a container serving plain HTTP (or vice versa)

Branch 7 — Pod Running and Ready, but service has no endpoints (GKE NEG case)

The pod is healthy in every way, but kubectl get endpoints <svc> is empty, OR the GKE container-native LB shows the backend as unhealthy.

kubectl get pod <pod> -n <ns> -o yaml | grep -A 3 "readinessGates\|conditions:"
kubectl get svc <svc> -n <ns> -o yaml | grep -A 5 "annotations:\|selector:"
kubectl get pod <pod> -n <ns> -o jsonpath='{.metadata.annotations.cloud\.google\.com/neg-status}{"\n"}'
CheckWhat it should show
Service selector matches pod labelskubectl get pod <pod> -n <ns> --show-labels; compare to svc selector
Pod has cloud.google.com/neg-status annotationIndicates GKE picked it up for a Network Endpoint Group; absence means standalone NEG isn't configured
Pod has readinessGates: cloud.google.com/load-balancer-neg-readyThe pod won't be Ready until the LB health check passes — required for proper rolling updates with container-native LB
BackendConfig referenced by service annotation cloud.google.com/backend-configkubectl get backendconfig -n <ns> — the health-check path/port must reach the pod

The most common GKE NEG failure mode: BackendConfig health check path is / but the app serves on /healthz, so the LB marks the backend unhealthy even though Kubernetes thinks the pod is Ready. Add a readinessGate so the pod's Ready status reflects the LB's view, not just Kubernetes'.

When you've exhausted the tree

If describe pod, logs, --previous, events, and the controller's events all look clean and the pod still misbehaves:

  • Check NetworkPolicies in the namespace (kubectl get netpol -n <ns>) — egress to DNS, kube-api, or other services may be silently blocked.
  • Check resource pressure on the node (kubectl describe node <node> | grep -E "Conditions:\|MemoryPressure\|DiskPressure\|PIDPressure").
  • Check container runtime logs on the node (last resort; requires node access).
  • Pull a debug copy of the pod: kubectl debug <pod> -n <ns> --image=busybox --target=<container> to inspect the namespace from inside the same network/PID context.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.