Gemini 4 Argon 如何在 GKE 建立事故診斷 Agent,關聯叢集事件與 VPA 日誌
Automated incident triage on GKE with Gemini 4 Argon and Model Context Protocol: Correlating cluster events and VPA logs
文中示範以 Gemini 4 Argon 和 GKE MCP 伺服器構建事故診斷 Agent,讓它關聯 Kubernetes 事件、Pod 日誌與 KCP_VPA 決策記錄。
When an on-call engineer gets paged at 2 AM for a degraded payment service, the hardest part of incident triage is rarely fixing the YAML manifest. Instead, the bottleneck is correlating telemetry across three different control loops: transient Kubernetes Pod events that expire after an hour, application stack traces in Cloud Logging, and vertical autoscaling actions emitted by the control plane.
Consider a common failure mode on Google Kubernetes Engine (GKE): a latency spike triggers an out-of-memory (OOMKilled) termination while the Vertical Pod Autoscaler (VPA) attempts an in-place resize (InPlaceOrRecreate) that gets capped by node capacity or GKE Autopilot compute ratio constraints. Diagnosing that sequence manually requires stitching together kubectl describe pod, container exit codes, and container.googleapis.com/vpa-controller decision logs.
With the release of Gemini 4 Argon and the open-source Google Kubernetes Engine MCP server, platform teams can deploy an in-cluster incident triage agent that autonomously queries Kubernetes state, inspects KCP_VPA control plane logs, identifies the root cause, and generates a verified remediation patch.
In this article, I will walk through the architecture of a read-only Gemini 4 Argon incident triage agent on GKE, show how to configure least-privilege RBAC and Workload Identity Federation for GKE, and demonstrate how the agent correlates live cluster telemetry through the Model Context Protocol (MCP).
Why incident triage requires multi-hop tool reasoning
Single-turn log summarization falls short during real Kubernetes incidents because the first symptom is almost never the root cause. A CrashLoopBackOff status on a Pod tells you only that the kubelet is delaying restarts; it does not tell you whether the failure stems from an expired secret, a failed readiness probe during JVM initialization, or a memory limit that VPA could not resize in place.
Gemini 4 Argon's long-horizon tool calling allows an agent to execute a structured diagnostic workflow across multiple MCP tools before forming a hypothesis:
- Trigger ingest: An incoming alert webhook from Cloud Monitoring delivers the initial incident context, affected namespace, and alert threshold to the in-cluster triage agent.
-
Kubernetes API inspection: The agent calls
list_k8s_eventsandget_k8s_resourcethrough the GKE MCP server to pull active events, Pod termination reasons, and deployment spec history. -
Workload telemetry: The agent queries container stdout/stderr logs via
get_k8s_logsto capture application stack traces and unhandled exceptions. -
Control plane log correlation: The agent queries
query_vpa_decision_logsagainst Cloud Logging to evaluateKCP_VPAdecisions, checking whether autoscaling recommendations were capped or throttled. - Remediation synthesis: The agent compiles a root-cause report and generates a suggested YAML diff delivered to an on-call Slack channel or GitOps pull request for human review.
To keep the cluster safe from unintended mutations during an active outage, the triage agent operates under a strict separation of duties:
| Operational phase | Access level | Mechanism | Security boundary |
|---|---|---|---|
| Telemetry discovery | Read-only (get, list, watch) |
GKE MCP server + Kubernetes ClusterRole
|
Denies create, patch, delete, and access to Secret payloads |
| Control plane log correlation | Read-only (roles/logging.viewer) |
Cloud Logging API via Workload Identity | Scoped to k8s_container, k8s_pod, and vpa-controller logs |
| Remediation proposal | Zero direct cluster write access | Structured Markdown report and YAML diff | Requires human approval or GitOps pipeline validation before apply |
Preparing the cluster and control plane logging
For the triage agent to inspect vertical autoscaling decisions alongside standard workload logs, enable VPA decision logging (KCP_VPA, available in Public Preview on GKE 1.36.0-gke.1601000 and later) on your GKE Autopilot or GKE Standard cluster. On GKE Autopilot clusters, Vertical Pod Autoscaling is enabled by default; on GKE Standard clusters, ensure --enable-vertical-pod-autoscaling is also enabled.
When updating --logging on an existing cluster, always include your existing logging components (such as SYSTEM and WORKLOAD) so you do not overwrite active settings:
export PROJECT_ID="production-ai-platform"
export PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")
export LOCATION="us-central1"
export CLUSTER_NAME="commerce-production-cluster"
# Check currently enabled logging components first
gcloud container clusters describe "${CLUSTER_NAME}" \
--location="${LOCATION}" \
--project="${PROJECT_ID}" \
--format="value(loggingConfig.componentConfig.enableComponents)"
# Enable SYSTEM, WORKLOAD, and KCP_VPA logs
gcloud container clusters update "${CLUSTER_NAME}" \
--location="${LOCATION}" \
--project="${PROJECT_ID}" \
--logging=SYSTEM,WORKLOAD,KCP_VPA
Hardening RBAC and Workload Identity for the triage agent
Never grant an AI agent cluster-admin permissions or read access to Kubernetes Secret objects. Create a dedicated sre-triage namespace and a ClusterRole that grants read-only visibility into workloads, events, HPA/VPA policies, and custom compute classes while explicitly excluding secrets.
Save the following manifest as triage-agent-rbac.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: sre-triage
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: gemini-triage-sa
namespace: sre-triage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gemini-readonly-triage-role
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "events", "services", "nodes", "namespaces", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["events.k8s.io"]
resources: ["events"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets", "replicasets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["get", "list", "watch"]
- apiGroups: ["autoscaling.k8s.io"]
resources: ["verticalpodautoscalers"]
verbs: ["get", "list", "watch"]
- apiGroups: ["cloud.google.com"]
resources: ["computeclasses"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gemini-readonly-triage-binding
subjects:
- kind: ServiceAccount
name: gemini-triage-sa
namespace: sre-triage
roleRef:
kind: ClusterRole
name: gemini-readonly-triage-role
apiGroup: rbac.authorization.k8s.io
Apply the RBAC manifest and bind the gemini-triage-sa ServiceAccount to the Gemini platform, GKE Viewer, and Cloud Logging Viewer IAM roles via Workload Identity Federation:
kubectl apply -f triage-agent-rbac.yaml
for ROLE in roles/aiplatform.user roles/container.viewer roles/logging.viewer; do
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/sre-triage/sa/gemini-triage-sa" \
--role="${ROLE}" \
--condition=None
done
Implementing the Gemini 4 Argon + MCP incident triage loop
The triage agent connects Gemini 4 Argon (gemini-4-argon) to an in-process gke-mcp session alongside a dedicated tool for querying container.googleapis.com/vpa-controller decision logs in Cloud Logging.
Here is the core implementation (triage_agent.py):
import asyncio
import os
from google import genai
from google.genai import types
from google.cloud import logging as cloud_logging
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"]
LOCATION = os.environ.get("VERTEX_LOCATION", "us-central1")
MODEL_ID = os.environ.get("GEMINI_MODEL_ID", "gemini-4-argon")
genai_client = genai.Client(vertexai=True, project=PROJECT_ID, location=LOCATION)
logging_client = cloud_logging.Client(project=PROJECT_ID)
def query_vpa_decision_logs(
cluster_name: str, namespace: str, workload_name: str, limit: int = 10
) -> list[dict]:
"""Queries GKE KCP_VPA control plane logs for a specific workload to inspect resize or eviction decisions.
Args:
cluster_name: Name of the GKE cluster.
namespace: Kubernetes namespace of the target workload.
workload_name: Name of the target Deployment or workload.
limit: Maximum number of log entries to return.
"""
log_filter = (
'resource.type="k8s_control_plane_component" '
f'AND resource.labels.cluster_name="{cluster_name}" '
f'AND logName="projects/{PROJECT_ID}/logs/container.googleapis.com%2Fvpa-controller" '
f'AND jsonPayload.target.namespace="{namespace}" '
f'AND jsonPayload.target.name="{workload_name}"'
)
entries = logging_client.list_entries(
filter_=log_filter,
order_by=cloud_logging.DESCENDING,
max_results=limit,
)
results = []
for entry in entries:
payload = entry.payload if isinstance(entry.payload, dict) else {}
results.append({
"timestamp": str(entry.timestamp),
"operation": payload.get("operation"),
"state": payload.get("state"),
"reason": payload.get("reason"),
"confidence": payload.get("confidence"),
})
return results
async def investigate_workload_incident(cluster_name: str, namespace: str, workload_name: str) -> str:
"""Connects Gemini to the GKE MCP server and Cloud Logging to diagnose a failing workload."""
server_params = StdioServerParameters(
command="gke-mcp",
args=[],
env=os.environ.copy(),
)
async with stdio_client(server_params) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as mcp_session:
await mcp_session.initialize()
prompt = (
f"Investigate the degraded Deployment '{workload_name}' in namespace '{namespace}' "
f"on GKE cluster '{cluster_name}'. "
"1. List recent Kubernetes events and inspect the Deployment and Pod statuses. "
"2. Check the container termination exit codes and recent Pod logs. "
"3. Query VPA decision logs using query_vpa_decision_logs to see if an in-place resize "
"or eviction occurred or was skipped. "
"4. Provide a concise root-cause timeline and a git-ready YAML patch."
)
config = types.GenerateContentConfig(
system_instruction=(
"You are a senior GKE Site Reliability Engineer. Always verify Pod status, exit codes, "
"Kubernetes events, and VPA decision logs before proposing a fix. Never guess when "
"telemetry can be queried via your tools."
),
tools=[mcp_session, query_vpa_decision_logs],
automatic_function_calling=types.AutomaticFunctionCallingConfig(
maximum_remote_calls=8
),
temperature=0.1,
)
response = await genai_client.aio.models.generate_content(
model=MODEL_ID,
contents=prompt,
config=config,
)
return response.text
By passing both mcp_session and query_vpa_decision_logs into tools, the google-genai SDK automatically discovers the GKE MCP server tools (list_k8s_events, get_k8s_resource, get_k8s_logs) and orchestrates the multi-step investigation up to the configured maximum_remote_calls limit. Passing env=os.environ.copy() to StdioServerParameters ensures the gke-mcp subprocess inherits in-cluster Kubernetes service environment variables (KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT) and GOOGLE_CLOUD_PROJECT.
Verifying the diagnosis on an OOMKilled workload
To see what the triage agent captures in practice, suppose the checkout-service Deployment in the payments namespace starts restarting with exit code 137 (OOMKilled) while managed by a VerticalPodAutoscaler in InPlaceOrRecreate mode.
When triggered, Gemini 4 Argon executes four tool calls in sequence and produces a structured diagnostic report:
Root-cause summary for Deployment payments/checkout-service:
1. Pod status & exit code: Pod checkout-service-7c9d8b6f4-x82lp terminated with reason OOMKilled (exit code 137) at 06:14:22 UTC after memory usage reached its 1Gi limit.
2. Kubernetes events: BackOff restarting failed container; InPlaceResizeFailed event reported on node gke-commerce-pool-4a91f.
3. VPA control plane logs (KCP_VPA):
- Operation: APPLY_RECOMMENDATION_IN_PLACE | State: FAILED | Confidence: HIGH
- Reason: Recommended memory target (2Gi) exceeded maxAllowed policy bound (1Gi) defined in VerticalPodAutoscaler checkout-service-vpa.
4. Recommended remediation: Raise resourcePolicy.containerPolicies[0].maxAllowed.memory in checkout-service-vpa from 1Gi to 3Gi so VPA can apply high-confidence in-place memory resizes without triggering OOM terminations.
You can independently verify the agent's finding using kubectl and gcloud:
# Verify the VPA resource policy cap on the cluster
kubectl get vpa checkout-service-vpa -n payments -o yaml
# Inspect the corresponding KCP_VPA log entry in Cloud Logging
gcloud logging read "resource.type=\"k8s_control_plane_component\" AND resource.labels.cluster_name=\"${CLUSTER_NAME}\" AND logName=\"projects/${PROJECT_ID}/logs/container.googleapis.com%2Fvpa-controller\" AND jsonPayload.target.name=\"checkout-service\"" \
--project="${PROJECT_ID}" \
--limit=3 \
--format=json
Operational guardrails and trade-offs
When running an AI-assisted triage agent inside your production GKE environment, apply these operational safeguards:
-
Keep remediation out-of-band: Even with Gemini 4 Argon's strong reasoning accuracy, an autonomous agent should not directly run
kubectl applyor mutate resource limits during an active incident. Have the agent open a pull request against your GitOps repository (managed by Config Sync or Argo CD) so human operators can review the diff. -
Scrub sensitive payloads from Pod logs: Application containers occasionally log PII or bearer tokens in stack traces during crashes. Configure a log-scrubbing filter before forwarding raw
pods/logoutput to the model API, and ensure your Gemini platform data governance policies disable prompt logging where required. -
Bound tool-call iterations during alert storms: If a node outage triggers 50 Pod alerts simultaneously, firing 50 parallel multi-turn Gemini 4 Argon investigations will exhaust both your Kubernetes API server client QPS limits and Gemini platform token quotas. Deduplicate alerts by owner reference (
DeploymentorStatefulSet) and cap each investigation to a maximum of 8 tool-calling turns.
Next steps
Combining Gemini 4 Argon with the GKE Model Context Protocol server and structured control plane logs (KCP_VPA) turns multi-system incident correlation from a 30-minute manual scavenger hunt into an automated, auditable workflow.
To deploy this pattern on your clusters, explore the open-source Google Kubernetes Engine MCP server repository, read the GKE VPA decision logs documentation, and review Workload Identity Federation for GKE for zero-key IAM authentication.
來源:DEV Community · dev.to