GKE Workload Troubleshooting Skill
Use this skill to systematically diagnose and resolve failures in application
workloads deployed in GKE clusters. This skill operates non-interactively and
enforces a read-only diagnostics boundary: it only proposes fixes — whether
Kubernetes manifest/config patches or Google Cloud changes (for example gcloud
IAM bindings or node-pool recreation) — and never executes live mutations
itself.
🔍 Diagnostic Workflow
Step 0: Non-Interactive Context Discovery & Time Window Definition
Parameter Extraction: Extract required context (project_id,
cluster_name, cluster_location, workload_name, workload_namespace)
non-interactively from the user prompt, active SETTINGS.md, or active
environment defaults:
- Default
workload_namespace to default if omitted.
- Infer missing cluster parameters from active environment (
kubectl config current-context or gcloud config get-value project).
- Prioritize non-interactive context discovery from prompts and
environment defaults to ensure autonomous execution flow.
Cluster Credentials & Fallback Mode:
- Attempt credential fetch:
gcloud container clusters get-credentials {cluster_name} --region/--zone {cluster_location}
- Fallback / Dry-Run Mode: If the cluster is unreachable,
non-existent, or live command execution fails (such as in sandboxed
evaluations, dry-run mode, or offline analysis):
- Limit retry attempts to avoid resource exhaustion and context
overflow in unreachable cluster scenarios.
- Immediately present the exact sequence of
kubectl diagnostic
commands for the human operator to run.
- Synthesize the root cause analysis and output the proposed GitOps
manifest fix based on the reported symptoms.
Time Handling & Fallbacks:
- Determine Issue Timestamp ({issue_time}):
- Specific Time Provided: If the user provides a specific
timestamp, use it as
{issue_time}.
- Relative Time Provided (e.g., "5 minutes ago"): Dynamically
calculate the corresponding UTC timestamp based on current system
time, and use it as
{issue_time}.
- No Time Provided (Default): Use current system time as
{issue_time}.
- Window Calculation: Center a 1-hour query window around
{issue_time} (start_time = {issue_time} - 30m, end_time =
{issue_time} + 30m).
Step 1: Analyze Pod Status and Conditions
Inspect the workload's active pod states and controller status.
Diagnostic Commands:
# 1. Inspect the deployment's actual selector labels:
kubectl get deployment {workload_name} -n {workload_namespace} -o jsonpath='{.spec.selector.matchLabels}'
# 2. Query the pods using the returned labels, for example:
kubectl get pods -l {selector_labels} -n {workload_namespace}
kubectl get deploy/{workload_name} -n {workload_namespace} -o yaml
Diagnostic Decision Tree:
Phase: Pending:
- The Pod cannot schedule on any node. Proceed directly to Step 2 (Query
Namespace Events).
State: CrashLoopBackOff / Error:
- The container boots but exits repeatedly; the
kubelet restarts it with
an increasing back-off delay of up to five minutes. First read the
terminated reason and exit code:
kubectl describe pod {pod_name} -n {workload_namespace}
kubectl get pod {pod_name} -n {workload_namespace} -o jsonpath='{.status.containerStatuses[*].lastState.terminated}'
- Reason: OOMKilled (Exit Code 137): The container's memory limit was
reached. Proceed to Step 3 (Inspect Logs) → OOM Analysis to classify
container-level vs node-level, then Step 5 to propose fixes.
- Exit Code 0 (successful exit): Unexpected for a long-running
Deployment/StatefulSet —
restartPolicy: Always restarts the finished
process, creating the loop. Common causes: the command/entrypoint
does not start a persistent process, a worker exits on an empty queue,
or a missing/invalid config (e.g., an unattached or mis-keyed
ConfigMap volume) makes the app exit cleanly. Proceed to Step 3
(Inspect Logs).
- Exit Code 128: Invalid
command/entrypoint — the executable path
is wrong or absent in the image. Verify the container command in the
manifest.
- Exit Code 1 or other non-zero: The application crashed —
configuration errors, missing/invalid env vars or config files,
unreachable dependencies, or auth failures (
401/403) on Google Cloud
calls (check the Pod's IAM / Workload Identity Federation). Proceed
directly to Step 3 (Inspect Logs).
- If the exit code looks healthy but the container keeps restarting,
suspect a liveness probe failure (see Step 3).
State: ImagePullBackOff / ErrImagePull:
- The kubelet cannot pull the container image.
ImagePullBackOff means it
keeps retrying with back-off; ErrImagePull is a general,
non-recoverable pull error. Related statuses: InvalidImageName,
RegistryUnavailable, SignatureValidationFailed, ImageInspectError.
Proceed to Step 2 (Query Namespace Events) to read the exact pull
error message.
State: ContainerCreating:
- The container is blocked during volume mount, networking setup, or image
pulling. Proceed directly to Step 2 (Query Namespace Events).
Step 2: Query Namespace Events
Look for infrastructure, volume, image, or scheduling alerts in GKE.
Diagnostic Command:
kubectl get events -n {workload_namespace} --sort-by='.metadata.creationTimestamp'
# Or query Cloud Logging for historical GKE events within the time window:
gcloud logging read "resource.type=\"k8s_cluster\" AND logName=\"projects/{project_id}/logs/events\" AND jsonPayload.involvedObject.namespace=\"{workload_namespace}\"" --start-time="{start_time}" --end-time="{end_time}" --project="{project_id}"
# Or query specifically for image pull failures within the time window:
gcloud logging read 'log_id("events") AND resource.type="k8s_pod" AND resource.labels.cluster_name="{cluster_name}" AND jsonPayload.message=~"Failed to pull image"' --project="{project_id}"
Note: Retrieve the sorted events list and manually inspect the event timestamps
(CreationTimestamp/LastSeen) to identify failures occurring within the
{start_time} and {end_time} window.
Signature Identifiers:
FailedScheduling: Node resource exhaustion. Look for messages like
0/3 nodes are available: 3 Insufficient memory. or missing node affinity
tolerations (e.g. Spot VM taints).
FailedMount:
- Missing PersistentVolumeClaim (
PVC).
- Missing Secret (
Secret "{secret_name}" not found).
- Missing ConfigMap (
ConfigMap "{configmap_name}" not found).
Failed / BackOff (Image Pull): First read the exact event message
(Failed to pull image "IMAGE": ...) and triage by what it actually says.
Do not jump to IAM / node service-account investigation unless the
message is genuinely a permission or authentication error.
Wrong image name/tag — start here (not found, manifest unknown,
InvalidImageName): the most common cause — the tag or path is wrong,
or the image was deleted, frequently introduced by a recent deployment
change.
- Identify the failing container image name and the invalid tag.
- Check the Git history for the last known working image tag:
git log -p -S "{image_name}" -- {manifest_file_path} (or run git log on
the folder containing manifests).
- Propose reverting the image tag to the last working version (or
correcting the tag) in the manifest patch.
Permission / authentication errors only (the message contains 403 Forbidden / denied, or 401 Unauthorized / unauthorized): the node
cannot authorize or authenticate to the registry. Pursue the checks
below only when the message matches.
403 Forbidden (authorization) — the node pool service account
(or the imagePullSecret's service account) is missing registry read
access. Suggest granting it by presenting the following command
for the user to review and run; do not execute it. For Artifact
Registry:
gcloud artifacts repositories add-iam-policy-binding {repository} \
--location={repo_location} \
--member="serviceAccount:{node_service_account_email}" \
--role="roles/artifactregistry.reader"
For Container Registry (gcr.io), grant
roles/storage.objectViewer on the backing bucket (or the Artifact
Registry role if gcr.io was migrated). Also check that any VPC
Service Controls perimeter allows Artifact Registry.
401 Unauthorized (authentication) — the node service account
is disabled or the node lacks the required OAuth scope:
gcloud container clusters describe {cluster_name} --location={cluster_location} \
--format="table(nodePools.name,nodePools.config.serviceAccount)"
gcloud iam service-accounts list \
--filter="email:{node_service_account_email} AND disabled:true" --project={project_id}
gcloud compute instances describe {node_name} --zone={node_zone} \
--format="flattened(serviceAccounts[].scopes)"
Scopes must include devstorage.read_only or cloud-platform
(provided by gke-default). Nodes are immutable, so suggest
recreating the node pool with --scopes="gke-default" if the scope
is missing — present it as a proposed command for the user to run,
do not execute it.
Private / self-hosted registry: ensure a valid imagePullSecret
exists and is referenced by the Deployment.
Other statuses: RegistryUnavailable / i/o timeout / DNS server misbehaving → registry network path (DNS, firewall egress, Google API
connectivity); exec format error or a deprecated schema-1 image →
architecture/schema mismatch.
Step 3: Inspect Application Logs
Extract exceptions and stack traces from the application runtime.
Diagnostic Commands:
# Check current active log stream (handles multi-container pods)
kubectl logs {pod_name} -n {workload_namespace} --all-containers --tail=100
# Check logs from previously terminated container instances (handles multi-container pods)
kubectl logs {pod_name} -n {workload_namespace} --all-containers -p --tail=100
Signature Identifiers:
Out-of-Memory (OOM) Analysis: First confirm and classify the kill.
Container-level OOM (most common): kubectl describe pod shows
Last State: Terminated, Reason: OOMKilled, Exit Code: 137. The
container exceeded its cgroup memory limit. Differentiate an
application memory leak/loop (unbounded growth in logs and startup
command) from an infrastructure capacity mismatch (legitimate demand
exceeding resources.limits.memory).
Node-level (system) OOM: the entire node ran out of memory; look for
evicted Pods and node-pressure eviction. The combined memory of all Pods
exceeded node capacity.
"Invisible" OOM (cgroup v1): a child process is killed but the
main process (PID 1) keeps running, so Kubernetes never marks
OOMKilled. Search node logs in Cloud Logging:
gcloud logging read 'resource.type="k8s_node" AND resource.labels.cluster_name="{cluster_name}" AND jsonPayload.MESSAGE:("TaskOOM event" OR "ContainerDied")' --project="{project_id}"
A TaskOOM entry confirms an OOM kill; match its container ID to the
ContainerDied entry to find the affected Pod. On the node, journalctl -k distinguishes container-level kills (memory cgroup, memcg) from
system-level kills (Out of memory: Killed process).
Do not rely solely on sampled memory metrics — they often miss the spike
that triggers the kill. Then proceed to Step 5 to propose fixes
(raise limits, fix the leak, or right-size the node pool).
Liveness Probe Failure (CrashLoop with no application error): if the
container restarts but its logs show no crash, the kubelet may be killing
it on failed liveness probes (default failureThreshold: 3). Confirm in
Cloud Logging:
gcloud logging read 'resource.type="k8s_node" AND log_id("kubelet") AND jsonPayload.MESSAGE:"failed liveness probe, will be restarted" AND resource.labels.cluster_name="{cluster_name}"' --project="{project_id}"
Common fixes: correct the probe type/path/port, raise initialDelaySeconds
or timeoutSeconds/failureThreshold for slow starts, or relieve CPU/disk
I/O contention causing probe timeouts. Keep probe commands lightweight.
Stack Trace / Unhandled Exception: Look for language-specific stack
traces (e.g., panic:, NullPointerException, Traceback (most recent call)). This indicates an application bug.
Egress Network Timeout: Look for connection timeouts (e.g., Connection timed out, dial tcp: i/o timeout). Proceed to Step 4 (Verify
Connectivity).
Permission Errors (ReadOnlyRootFilesystem): Look for write errors (e.g.,
Read-only file system, Permission denied when writing to /tmp or
/var/log). Propose adding an emptyDir volume mount to that directory in
the manifest.
Step 4: Verify Service Connectivity and Network Policies
Troubleshoot connection drops to other services.
Diagnostic Commands:
# Verify target endpoint is active
kubectl get endpoints {target_service_name} -n {target_namespace}
# Query network policies inside namespace
kubectl get networkpolicies -n {workload_namespace} -o yaml
Logic & Dry-Run Fallback:
Live Cluster Mode:
- If
kubectl get endpoints returns an empty list, the target
microservice itself is failing to schedule or boot (troubleshoot target
service).
- If endpoints exist but logs show timeouts, analyze
NetworkPolicy
egress blocks to verify if egress traffic to the target service's
IP/port is allowed.
Sandboxed / Dry-Run Mode:
- If live
kubectl queries fail or cluster connection is unavailable, do
NOT retry live cluster access or enter repetitive connection attempts.
- Immediately inspect the application source code (e.g.
worker.py,
app.go, DB connection strings) or Deployment manifests to identify the
target service hostname (e.g. account-db) and destination port (e.g.
5432).
- Present the exact
kubectl get endpoints and kubectl get networkpolicies commands for the user, and synthesize the required
NetworkPolicy egress patch allowing traffic to the target service and
port.
Step 5: Propose GitOps Correction
Following the GitOps boundary, do not apply changes directly — this includes
both cluster manifest/config patches and any Google Cloud mutations (for example
gcloud IAM bindings or node-pool recreation). Present every change as a
reviewable suggestion: a manifest patch / PR, or a command for the user to run.
- Synthesize the root cause analysis for the human operator (e.g.
"payment-api is failing with exit code 137 because its memory limit is set
to 256Mi while actual usage spiked to 270Mi").
- Generate the corrected YAML manifest patch (e.g. increase memory limits, add
missing Secret mounts, or add tolerations for Spot nodes).
- Check if a branch or Pull Request (PR) already exists for this
workload/failure. If so, update the existing branch/PR or notify the user
instead of creating a duplicate. Otherwise, create a branch, commit the
change, open a Pull Request (PR) on GitHub, and conclude the workflow (do
not wait for human merge).
References
1---2name: gke-workload-troubleshooting3description: Diagnoses GKE workload failures (CrashLoopBackOff, OOMKilled, ImagePullBackOff, Pending, etc.) via logs and events. Use when pods fail to start or crash repeatedly. Don't use for GKE cluster infrastructure provisioning, node pool creation, or non-Kubernetes Google Cloud services.4---56# GKE Workload Troubleshooting Skill78Use this skill to systematically diagnose and resolve failures in application9workloads deployed in GKE clusters. This skill operates non-interactively and10enforces a read-only diagnostics boundary: it only **proposes** fixes — whether11Kubernetes manifest/config patches or Google Cloud changes (for example `gcloud`12IAM bindings or node-pool recreation) — and never executes live mutations13itself.1415## 🔍 Diagnostic Workflow1617### Step 0: Non-Interactive Context Discovery & Time Window Definition18191. **Parameter Extraction**: Extract required context (`project_id`,20 `cluster_name`, `cluster_location`, `workload_name`, `workload_namespace`)21 non-interactively from the user prompt, active `SETTINGS.md`, or active22 environment defaults:2324 - Default `workload_namespace` to `default` if omitted.25 - Infer missing cluster parameters from active environment (`kubectl26 config current-context` or `gcloud config get-value project`).27 - Prioritize non-interactive context discovery from prompts and28 environment defaults to ensure autonomous execution flow.29302. **Cluster Credentials & Fallback Mode**:3132 - Attempt credential fetch: `gcloud container clusters get-credentials33 {cluster_name} --region/--zone {cluster_location}`34 - **Fallback / Dry-Run Mode**: If the cluster is unreachable,35 non-existent, or live command execution fails (such as in sandboxed36 evaluations, dry-run mode, or offline analysis):37 - Limit retry attempts to avoid resource exhaustion and context38 overflow in unreachable cluster scenarios.39 - Immediately present the exact sequence of `kubectl` diagnostic40 commands for the human operator to run.41 - Synthesize the root cause analysis and output the proposed GitOps42 manifest fix based on the reported symptoms.43443. **Time Handling & Fallbacks**:4546 - **Determine Issue Timestamp ({issue_time})**:47 - **Specific Time Provided**: If the user provides a specific48 timestamp, use it as `{issue_time}`.49 - **Relative Time Provided (e.g., "5 minutes ago")**: Dynamically50 calculate the corresponding UTC timestamp based on current system51 time, and use it as `{issue_time}`.52 - **No Time Provided (Default)**: Use current system time as53 `{issue_time}`.54 - **Window Calculation**: Center a 1-hour query window around55 `{issue_time}` (`start_time` = `{issue_time} - 30m`, `end_time` =56 `{issue_time} + 30m`).5758--------------------------------------------------------------------------------5960### Step 1: Analyze Pod Status and Conditions6162Inspect the workload's active pod states and controller status.6364**Diagnostic Commands:**6566```bash67# 1. Inspect the deployment's actual selector labels:68kubectl get deployment {workload_name} -n {workload_namespace} -o jsonpath='{.spec.selector.matchLabels}'69# 2. Query the pods using the returned labels, for example:70kubectl get pods -l {selector_labels} -n {workload_namespace}71kubectl get deploy/{workload_name} -n {workload_namespace} -o yaml72```7374#### Diagnostic Decision Tree:7576- **Phase: Pending**:77 - The Pod cannot schedule on any node. Proceed directly to **Step 2 (Query78 Namespace Events)**.79- **State: CrashLoopBackOff / Error**:8081 - The container boots but exits repeatedly; the `kubelet` restarts it with82 an increasing back-off delay of up to five minutes. First read the83 terminated **reason** and **exit code**:8485 ```bash86 kubectl describe pod {pod_name} -n {workload_namespace}87 kubectl get pod {pod_name} -n {workload_namespace} -o jsonpath='{.status.containerStatuses[*].lastState.terminated}'88 ```8990 - **Reason: OOMKilled (Exit Code 137)**: The container's memory limit was91 reached. Proceed to **Step 3 (Inspect Logs) → OOM Analysis** to classify92 container-level vs node-level, then **Step 5** to propose fixes.93 - **Exit Code 0 (successful exit)**: Unexpected for a long-running94 Deployment/StatefulSet — `restartPolicy: Always` restarts the finished95 process, creating the loop. Common causes: the `command`/`entrypoint`96 does not start a persistent process, a worker exits on an empty queue,97 or a missing/invalid config (e.g., an unattached or mis-keyed98 `ConfigMap` volume) makes the app exit cleanly. Proceed to **Step 399 (Inspect Logs)**.100 - **Exit Code 128**: Invalid `command`/`entrypoint` — the executable path101 is wrong or absent in the image. Verify the container command in the102 manifest.103 - **Exit Code 1 or other non-zero**: The application crashed —104 configuration errors, missing/invalid env vars or config files,105 unreachable dependencies, or auth failures (`401`/`403`) on Google Cloud106 calls (check the Pod's IAM / Workload Identity Federation). Proceed107 directly to **Step 3 (Inspect Logs)**.108 - If the exit code looks healthy but the container keeps restarting,109 suspect a **liveness probe failure** (see Step 3).110111- **State: ImagePullBackOff / ErrImagePull**:112113 - The kubelet cannot pull the container image. `ImagePullBackOff` means it114 keeps retrying with back-off; `ErrImagePull` is a general,115 non-recoverable pull error. Related statuses: `InvalidImageName`,116 `RegistryUnavailable`, `SignatureValidationFailed`, `ImageInspectError`.117 Proceed to **Step 2 (Query Namespace Events)** to read the exact pull118 error message.119120- **State: ContainerCreating**:121122 - The container is blocked during volume mount, networking setup, or image123 pulling. Proceed directly to **Step 2 (Query Namespace Events)**.124125--------------------------------------------------------------------------------126127### Step 2: Query Namespace Events128129Look for infrastructure, volume, image, or scheduling alerts in GKE.130131**Diagnostic Command:**132133```bash134kubectl get events -n {workload_namespace} --sort-by='.metadata.creationTimestamp'135# Or query Cloud Logging for historical GKE events within the time window:136gcloud logging read "resource.type=\"k8s_cluster\" AND logName=\"projects/{project_id}/logs/events\" AND jsonPayload.involvedObject.namespace=\"{workload_namespace}\"" --start-time="{start_time}" --end-time="{end_time}" --project="{project_id}"137# Or query specifically for image pull failures within the time window:138gcloud logging read 'log_id("events") AND resource.type="k8s_pod" AND resource.labels.cluster_name="{cluster_name}" AND jsonPayload.message=~"Failed to pull image"' --project="{project_id}"139```140141*Note: Retrieve the sorted events list and manually inspect the event timestamps142(CreationTimestamp/LastSeen) to identify failures occurring within the143`{start_time}` and `{end_time}` window.*144145#### Signature Identifiers:146147- **`FailedScheduling`**: Node resource exhaustion. Look for messages like148 `0/3 nodes are available: 3 Insufficient memory.` or missing node affinity149 tolerations (e.g. Spot VM taints).150- **`FailedMount`**:151 - Missing PersistentVolumeClaim (`PVC`).152 - Missing Secret (`Secret "{secret_name}" not found`).153 - Missing ConfigMap (`ConfigMap "{configmap_name}" not found`).154- **`Failed` / `BackOff` (Image Pull)**: First read the exact event message155 (`Failed to pull image "IMAGE": ...`) and triage by what it actually says.156 Do **not** jump to IAM / node service-account investigation unless the157 message is genuinely a permission or authentication error.158159 - **Wrong image name/tag — start here** (`not found`, `manifest unknown`,160 `InvalidImageName`): the most common cause — the tag or path is wrong,161 or the image was deleted, frequently introduced by a recent deployment162 change.163 * Identify the failing container image name and the invalid tag.164 * Check the Git history for the last known working image tag: `git log165 -p -S "{image_name}" -- {manifest_file_path}` (or run `git log` on166 the folder containing manifests).167 * Propose reverting the image tag to the last working version (or168 correcting the tag) in the manifest patch.169 - **Permission / authentication errors only** (the message contains `403170 Forbidden` / `denied`, or `401 Unauthorized` / `unauthorized`): the node171 cannot authorize or authenticate to the registry. Pursue the checks172 below **only** when the message matches.173174 * **`403 Forbidden` (authorization)** — the node pool service account175 (or the imagePullSecret's service account) is missing registry read176 access. **Suggest** granting it by presenting the following command177 for the user to review and run; do not execute it. For **Artifact178 Registry**:179180 ```bash181 gcloud artifacts repositories add-iam-policy-binding {repository} \182 --location={repo_location} \183 --member="serviceAccount:{node_service_account_email}" \184 --role="roles/artifactregistry.reader"185 ```186187 For **Container Registry (`gcr.io`)**, grant188 `roles/storage.objectViewer` on the backing bucket (or the Artifact189 Registry role if `gcr.io` was migrated). Also check that any **VPC190 Service Controls** perimeter allows Artifact Registry.191 * **`401 Unauthorized` (authentication)** — the node service account192 is disabled or the node lacks the required OAuth scope:193194 ```bash195 gcloud container clusters describe {cluster_name} --location={cluster_location} \196 --format="table(nodePools.name,nodePools.config.serviceAccount)"197 gcloud iam service-accounts list \198 --filter="email:{node_service_account_email} AND disabled:true" --project={project_id}199 gcloud compute instances describe {node_name} --zone={node_zone} \200 --format="flattened(serviceAccounts[].scopes)"201 ```202203 Scopes must include `devstorage.read_only` or `cloud-platform`204 (provided by `gke-default`). Nodes are immutable, so **suggest**205 recreating the node pool with `--scopes="gke-default"` if the scope206 is missing — present it as a proposed command for the user to run,207 do not execute it.208 * **Private / self-hosted registry**: ensure a valid `imagePullSecret`209 exists and is referenced by the Deployment.210 - **Other statuses**: `RegistryUnavailable` / `i/o timeout` / DNS `server211 misbehaving` → registry network path (DNS, firewall egress, Google API212 connectivity); `exec format error` or a deprecated schema-1 image →213 architecture/schema mismatch.214215--------------------------------------------------------------------------------216217### Step 3: Inspect Application Logs218219Extract exceptions and stack traces from the application runtime.220221**Diagnostic Commands:**222223```bash224# Check current active log stream (handles multi-container pods)225kubectl logs {pod_name} -n {workload_namespace} --all-containers --tail=100226227# Check logs from previously terminated container instances (handles multi-container pods)228kubectl logs {pod_name} -n {workload_namespace} --all-containers -p --tail=100229```230231#### Signature Identifiers:232233- **Out-of-Memory (OOM) Analysis**: First confirm and classify the kill.234235 - **Container-level OOM** (most common): `kubectl describe pod` shows236 `Last State: Terminated`, `Reason: OOMKilled`, `Exit Code: 137`. The237 container exceeded its cgroup memory limit. Differentiate an238 **application memory leak/loop** (unbounded growth in logs and startup239 command) from an **infrastructure capacity mismatch** (legitimate demand240 exceeding `resources.limits.memory`).241 - **Node-level (system) OOM**: the entire node ran out of memory; look for242 evicted Pods and node-pressure eviction. The combined memory of all Pods243 exceeded node capacity.244 - **"Invisible" OOM** (`cgroup v1`): a child process is killed but the245 main process (PID 1) keeps running, so Kubernetes never marks246 `OOMKilled`. Search node logs in Cloud Logging:247248 ```bash249 gcloud logging read 'resource.type="k8s_node" AND resource.labels.cluster_name="{cluster_name}" AND jsonPayload.MESSAGE:("TaskOOM event" OR "ContainerDied")' --project="{project_id}"250 ```251252 A `TaskOOM` entry confirms an OOM kill; match its container ID to the253 `ContainerDied` entry to find the affected Pod. On the node, `journalctl254 -k` distinguishes container-level kills (`memory cgroup`, `memcg`) from255 system-level kills (`Out of memory: Killed process`).256 - Do not rely solely on sampled memory metrics — they often miss the spike257 that triggers the kill. Then proceed to **Step 5** to propose fixes258 (raise limits, fix the leak, or right-size the node pool).259- **Liveness Probe Failure (CrashLoop with no application error)**: if the260 container restarts but its logs show no crash, the `kubelet` may be killing261 it on failed liveness probes (default `failureThreshold: 3`). Confirm in262 Cloud Logging:263264 ```bash265 gcloud logging read 'resource.type="k8s_node" AND log_id("kubelet") AND jsonPayload.MESSAGE:"failed liveness probe, will be restarted" AND resource.labels.cluster_name="{cluster_name}"' --project="{project_id}"266 ```267268 Common fixes: correct the probe type/path/port, raise `initialDelaySeconds`269 or `timeoutSeconds`/`failureThreshold` for slow starts, or relieve CPU/disk270 I/O contention causing probe timeouts. Keep probe commands lightweight.271- **Stack Trace / Unhandled Exception**: Look for language-specific stack272 traces (e.g., `panic:`, `NullPointerException`, `Traceback (most recent273 call)`). This indicates an application bug.274- **Egress Network Timeout**: Look for connection timeouts (e.g., `Connection275 timed out`, `dial tcp: i/o timeout`). Proceed to **Step 4 (Verify276 Connectivity)**.277- **Permission Errors (ReadOnlyRootFilesystem)**: Look for write errors (e.g.,278 `Read-only file system`, `Permission denied` when writing to `/tmp` or279 `/var/log`). Propose adding an `emptyDir` volume mount to that directory in280 the manifest.281282--------------------------------------------------------------------------------283284### Step 4: Verify Service Connectivity and Network Policies285286Troubleshoot connection drops to other services.287288**Diagnostic Commands:**289290```bash291# Verify target endpoint is active292kubectl get endpoints {target_service_name} -n {target_namespace}293294# Query network policies inside namespace295kubectl get networkpolicies -n {workload_namespace} -o yaml296```297298#### Logic & Dry-Run Fallback:2993001. **Live Cluster Mode**:301302 - If `kubectl get endpoints` returns an empty list, the target303 microservice itself is failing to schedule or boot (troubleshoot target304 service).305 - If endpoints exist but logs show timeouts, analyze `NetworkPolicy`306 egress blocks to verify if egress traffic to the target service's307 IP/port is allowed.3083092. **Sandboxed / Dry-Run Mode**:310311 - If live `kubectl` queries fail or cluster connection is unavailable, do312 NOT retry live cluster access or enter repetitive connection attempts.313 - Immediately inspect the application source code (e.g. `worker.py`,314 `app.go`, DB connection strings) or Deployment manifests to identify the315 target service hostname (e.g. `account-db`) and destination port (e.g.316 `5432`).317 - Present the exact `kubectl get endpoints` and `kubectl get318 networkpolicies` commands for the user, and synthesize the required319 `NetworkPolicy` egress patch allowing traffic to the target service and320 port.321322--------------------------------------------------------------------------------323324### Step 5: Propose GitOps Correction325326Following the GitOps boundary, **do not apply changes directly** — this includes327both cluster manifest/config patches and any Google Cloud mutations (for example328`gcloud` IAM bindings or node-pool recreation). Present every change as a329reviewable suggestion: a manifest patch / PR, or a command for the user to run.3303311. Synthesize the root cause analysis for the human operator (e.g.332 *"payment-api is failing with exit code 137 because its memory limit is set333 to 256Mi while actual usage spiked to 270Mi"*).3342. Generate the corrected YAML manifest patch (e.g. increase memory limits, add335 missing Secret mounts, or add tolerations for Spot nodes).3363. Check if a branch or Pull Request (PR) already exists for this337 workload/failure. If so, update the existing branch/PR or notify the user338 instead of creating a duplicate. Otherwise, create a branch, commit the339 change, open a Pull Request (PR) on GitHub, and conclude the workflow (do340 not wait for human merge).341342--------------------------------------------------------------------------------343344## References345346- [Troubleshoot OOM events](https://docs.cloud.google.com/kubernetes-engine/docs/troubleshooting/oom-events.md.txt)347- [Troubleshoot image pulls](https://docs.cloud.google.com/kubernetes-engine/docs/troubleshooting/image-pulls.md.txt)348- [Troubleshoot CrashLoopBackOff events](https://docs.cloud.google.com/kubernetes-engine/docs/troubleshooting/crashloopbackoff-events.md.txt)349- [Troubleshoot deployed workloads](https://docs.cloud.google.com/kubernetes-engine/docs/troubleshooting/deployed-workloads.md.txt)350- [Artifact Registry access control with GKE](https://docs.cloud.google.com/artifact-registry/docs/access-control.md.txt#gke)