Repository navigation
MW K8S Agent Debugging Cheat Sheet
# Are all mw-agent pods running?
kubectl get pods -n mw-agent-ns
kubectl describe pod <MW_AGENT_POD> -n <NAMESPACE>
# Quick overview of everything in the namespace
kubectl get all -n mw-agent-ns
# Check events for errors
kubectl get events -n mw-agent-ns --sort-by='.lastTimestamp'These should always be running after installation.
DaemonSet — one pod per node for OS/kubelet metrics:
kubectl get daemonset mw-kube-agent -n mw-agent-nsDeployment — cluster-wide telemetry:
kubectl get deployment mw-kube-agent -n mw-agent-nsConfig Updater:
kubectl get deployment mw-kube-agent-config-updater -n mw-agent-nsCheck if DaemonSet is running on all nodes:
# Compare DESIRED vs READY columns
kubectl get ds mw-kube-agent -n mw-agent-ns -o wideOnly present if mw-autoinstrumentation.enabled=true.
kubectl get deployment mw-agent-opentelemetry-operator -n mw-agent-ns
kubectl get deployment mw-auto-injector -n mw-agent-ns
kubectl get deployment mw-lang-aggregator -n mw-agent-ns
kubectl get daemonset mw-lang-detector -n mw-agent-nsCheck Instrumentation CR exists:
kubectl get otelinst mw-autoinstrumentation -n mw-agent-ns
kubectl get instrumentations.opentelemetry.io mw-autoinstrumentation -n mw-agent-nsInspect full Instrumentation CR:
kubectl get otelinst mw-autoinstrumentation -n mw-agent-ns -o yaml
kubectl get instrumentations.opentelemetry.io mw-autoinstrumentation -n mw-agent-ns -o yamlOnly present if opsai.enabled=true.
kubectl get deployment opsai -n mw-agent-ns# DaemonSet logs
kubectl logs -f daemonset/mw-kube-agent -n mw-agent-ns
# Deployment logs
kubectl logs -f deployment/mw-kube-agent -n mw-agent-ns
# Config updater logs
kubectl logs -f deployment/mw-kube-agent-config-updater -n mw-agent-ns
# Previous container logs (if crash-looping)
kubectl logs <POD_NAME> -n mw-agent-ns --previous# Language detector
kubectl logs daemonset/mw-lang-detector -n mw-agent-ns
# Admission webhook / auto-injector
kubectl logs deploy/mw-auto-injector -n mw-agent-ns
# OpenTelemetry Operator
kubectl logs deploy/mw-agent-opentelemetry-operator -n mw-agent-ns
# Language aggregator
kubectl logs deploy/mw-lang-aggregator -n mw-agent-nskubectl logs -n mw-agent-ns -l app.kubernetes.io/instance=mw-agent \
--all-containers | grep -i "error\|fatal\|panic"The MW agent service exposes two OTEL endpoints:
-
gRPC —
mw-service.mw-agent-ns:9319 -
HTTP —
mw-service.mw-agent-ns:9320
Verify the service exists:
kubectl get svc mw-service -n mw-agent-nsTest connectivity from an app pod to the agent:
# HTTP endpoint
kubectl exec -it <APP_POD> -n <APP_NAMESPACE> -- \
curl http://mw-service.mw-agent-ns:9320
# gRPC endpoint
kubectl exec -it <APP_POD> -n <APP_NAMESPACE> -- \
curl http://mw-service.mw-agent-ns:9319DNS resolution test:
kubectl exec -it <APP_POD> -n <APP_NAMESPACE> -- \
nslookup mw-service.mw-agent-nsOutbound connectivity (Agent to Middleware Backend):
kubectl exec -it <MW_AGENT_POD> -n mw-agent-ns -- \
curl -v https://<MW_TARGET_URL># Check current release status
helm status mw-agent -n mw-agent-ns
# View deployed values
helm get values mw-agent -n mw-agent-ns
# View ALL values including defaults
helm get values mw-agent -n mw-agent-ns --all
# View release history
helm history mw-agent -n mw-agent-ns
# Dry-run an upgrade to preview changes
helm upgrade mw-agent middleware-labs/mw-kube-agent-v3 \
--dry-run --debug \
-f values.yaml \
-n mw-agent-ns
# Force restart config updater to pick up new config
kubectl rollout restart deployment \
mw-kube-agent-config-updater -n mw-agent-ns# Check lang-detector logs
kubectl logs daemonset/mw-lang-detector -n mw-agent-ns
# Restart lang-detector if detection is stuck
kubectl rollout restart daemonset/mw-lang-detector -n mw-agent-ns
# Verify app pods are Running
kubectl get pods -n <APP_NAMESPACE> -l app=<APP_LABEL>Checklist:
- App uses a supported language? (Java, Node.js, Python, .NET, Go, Apache HTTPD, Nginx)
- Main app container is listed first in
spec.containers? - App pod is in
Runningstate?
# Check auto-injector webhook logs
kubectl logs deploy/mw-auto-injector -n mw-agent-ns
# Check OTel operator logs
kubectl logs deploy/mw-agent-opentelemetry-operator -n mw-agent-ns
# Verify annotations on your pod template
kubectl get deployment <APP_DEPLOYMENT> -n <APP_NAMESPACE> \
-o jsonpath='{.spec.template.metadata.annotations}' | jq .
# Restart pods after enabling instrumentation
kubectl rollout restart deployment/<APP_DEPLOYMENT> -n <APP_NAMESPACE>Checklist:
- Namespace is in auto-instrumentation scope?
- Pods restarted after enabling?
- Annotations under
spec.template.metadata.annotations? (NOT top-levelmetadata.annotations) - Network connectivity from app pod to
mw-service.mw-agent-ns:9319/9320?
Java:
instrumentation.opentelemetry.io/inject-java: "mw-agent-ns/mw-autoinstrumentation"Node.js:
instrumentation.opentelemetry.io/inject-nodejs: "mw-agent-ns/mw-autoinstrumentation"Python:
instrumentation.opentelemetry.io/inject-python: "mw-agent-ns/mw-autoinstrumentation"Python on Alpine (musl):
instrumentation.opentelemetry.io/inject-python: "mw-agent-ns/mw-autoinstrumentation"
instrumentation.opentelemetry.io/otel-python-platform: "musl".NET (glibc):
instrumentation.opentelemetry.io/inject-dotnet: "mw-agent-ns/mw-autoinstrumentation"
instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: "linux-x64".NET (musl):
instrumentation.opentelemetry.io/inject-dotnet: "mw-agent-ns/mw-autoinstrumentation"
instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: "linux-musl-x64"Go (requires privileged security context):
instrumentation.opentelemetry.io/inject-go: "mw-agent-ns/mw-autoinstrumentation"
instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/path/to/executable"Apache HTTPD:
instrumentation.opentelemetry.io/inject-apache-httpd: "mw-agent-ns/mw-autoinstrumentation"Nginx:
instrumentation.opentelemetry.io/inject-nginx: "mw-agent-ns/mw-autoinstrumentation"Single language — specify which containers:
instrumentation.opentelemetry.io/inject-java: "mw-agent-ns/mw-autoinstrumentation"
instrumentation.opentelemetry.io/java-container-names: "myapp,myapp2"Multiple languages — use language-specific container-names:
instrumentation.opentelemetry.io/inject-java: "mw-agent-ns/mw-autoinstrumentation"
instrumentation.opentelemetry.io/java-container-names: "myapp"
instrumentation.opentelemetry.io/inject-python: "mw-agent-ns/mw-autoinstrumentation"
instrumentation.opentelemetry.io/python-container-names: "myapp2"Important notes:
- Go does NOT support multi-container pods
- A single container cannot be instrumented with multiple languages
- If
container-namesis not set, the first container gets instrumented (could be a sidecar!)
# Include only specific namespaces
--set mw-autoinstrumentation.webhook.includedNamespaces="{app,backend}"
# Exclude specific namespaces
--set mw-autoinstrumentation.webhook.userExcludedNamespaces="{monitoring,infra}"
# Skip app detection for specific namespaces
--set mw-autoinstrumentation.langDetector.userExcludedNamespaces="{app,backend}"- Cause: Agent not running or no outbound internet access
- Fix: Check pod status, verify outbound connectivity to MW target URL
- Cause: Default resource limits too low for large clusters
-
Fix: Increase
resources.limits.memoryandresources.limits.cpuin values.yaml
- Cause: Node taints that pods cannot tolerate (common with Karpenter or custom pools)
- Fix: Add appropriate tolerations in values.yaml
- Cause: More than one MW agent DaemonSet deployed in the cluster
- Fix: Run only ONE mw-agent DaemonSet per cluster
- Cause: Unsupported language, or sidecar container is listed first
- Fix: Verify supported language, reorder containers so app is first
- Cause: Pods not restarted after enabling, or annotation typo/wrong path
-
Fix: Restart pods, verify annotations are under
spec.template.metadata.annotations
- Cause: cert-manager not installed, or TLS certs expired
- Fix: Install cert-manager, or use self-signed certs (see Section 12)
- Cause: Existing OpenTelemetry Operator CRDs in cluster
- Fix: Delete old CRDs or skip CRD creation (see Section 11)
- Cause: Config updater has not picked up the new values
- Fix:
kubectl rollout restart deployment mw-kube-agent-config-updater -n mw-agent-nsFind the control-plane CIDR:
gcloud container clusters describe <CLUSTER_NAME> \
--region <REGION> \
--format="value(privateClusterConfig.masterIpv4CidrBlock)"Add a firewall rule:
gcloud compute firewall-rules create cert-manager-9443 \
--source-ranges <GKE_CONTROL_PLANE_CIDR> \
--target-tags <GKE_CONTROL_PLANE_TAG> \
--allow TCP:9443- Auto language detection: NOT supported
- UI-driven instrumentation toggle: NOT supported
- Must use
mw-autoinstrumentation.mode=manualwith manual annotations -
features.enableHostMonitoringmust be set tofalse
- DaemonSets: NOT supported
- UI-driven auto-instrumentation: NOT supported (use manual annotations)
-
mw-agent-nsmust be included in a Fargate profile or pods stay inPending - Logs collected via AWS Fluent Bit log router (not
/var/log/containers)
If install fails with the error:
Error: INSTALLATION FAILED: unable to continue with install:
CustomResourceDefinition "targetallocators.opentelemetry.io" exists
and cannot be imported into the current release
Option 1 — Remove old CRDs (Recommended):
kubectl delete crd \
opentelemetrycollectors.opentelemetry.io \
instrumentations.opentelemetry.io \
targetallocators.opentelemetry.io \
opampbridges.opentelemetry.ioOption 2 — Keep existing CRDs, skip creation:
--set mw-autoinstrumentation.opentelemetry-operator.crds.create=falseWithout cert-manager — use self-signed certs:
--set mw-autoinstrumentation.webhook.certManager.enabled=false
--set mw-autoinstrumentation.opentelemetry-operator.admissionWebhooks.certManager.enabled=falseAfter upgrades or cert expiry, restart these components:
kubectl rollout restart deploy/mw-agent-opentelemetry-operator -n mw-agent-ns
kubectl rollout restart deploy/mw-auto-injector -n mw-agent-nsSave as mw-debug.sh and run with bash mw-debug.sh:
#!/bin/bash
NS="mw-agent-ns"
echo "========================================="
echo " MW-Agent Diagnostic Report"
echo " $(date)"
echo "========================================="
echo ""
echo "--- Kubernetes Context ---"
kubectl config current-context
echo ""
echo "--- All Resources in $NS ---"
kubectl get all -n $NS
echo ""
echo "--- Pod Status ---"
kubectl get pods -n $NS -o wide
echo ""
echo "--- DaemonSet Status ---"
kubectl get ds -n $NS
echo ""
echo "--- Deployments ---"
kubectl get deploy -n $NS
echo ""
echo "--- Services ---"
kubectl get svc -n $NS
echo ""
echo "--- Instrumentation CR ---"
kubectl get otelinst -n $NS 2>/dev/null || echo "No Instrumentation CR found"
echo ""
echo "--- Recent Events (last 20) ---"
kubectl get events -n $NS --sort-by='.lastTimestamp' | tail -20
echo ""
echo "--- Pods NOT Ready ---"
kubectl get pods -n $NS --field-selector=status.phase!=Running 2>/dev/null
echo ""
echo "--- Helm Release ---"
helm status mw-agent -n $NS 2>/dev/null || echo "Helm release not found"
echo ""
echo "--- Helm Values ---"
helm get values mw-agent -n $NS 2>/dev/null || echo "No values found"
echo ""
echo "========================================="
echo " Done. Share this output with the team."
echo "========================================="kubectl patch instrumentation mw-autoinstrumentation \
-n mw-agent-ns \
--type='merge' \
-p '{
"spec": {
"go": {
"image": "ghcr.io/middleware-labs/opentelemetry-go-instrumentation/autoinstrumentation-go:v0.24.0"
}
}
}'
kubectl patch instrumentation mw-autoinstrumentation -n mw-agent-ns --type='json' -p='[
{
"op": "add",
"path": "/spec/java/env/-",
"value": {
"name": "YOUR_ENV_NAME",
"value": "your-env-value"
}
}
]'
kubectl patch deployment mw-kube-agent -n mw-agent-ns --type json -p '[
{"op": "remove", "path": "/spec/template/spec/containers/0/resources/limits"}
]'kubectl logs shippingservice-846bddc898-8nb4z -c opentelemetry-auto-instrumentation -n defaultK8s Troubleshooting
ps aux
ls -l /proc/<PID>/exe
# Remove Helm release
helm uninstall mw-agent -n mw-agent-ns
# Delete namespace
kubectl delete namespace mw-agent-nsapiVersion: apps/v1
kind: Deployment
metadata:
name: flask-app
namespace: default
labels:
app: flask-app
spec:
replicas: 1
selector:
matchLabels:
app: flask-app
template:
metadata:
creationTimestamp: null
labels:
app: flask-app
spec:
containers:
- name: flask-app
image: ghcr.io/middleware-labs/node-redis-example:test54
ports:
- name: http
containerPort: 8000
protocol: TCP
env:
- name: ENVIRONMENT
value: production
- name: TZ
value: America/Chicago
- name: obi
image: >-
ghcr.io/open-telemetry/opentelemetry-ebpf-instrumentation/ebpf-instrument:main
env:
- name: OTEL_SERVICE_NAME
value: flask-app
# your main app container port
- name: OTEL_EBPF_OPEN_PORT
value: '8080'
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://mw-service.mw-agent-ns:9320
- name: OTEL_EBPF_KUBE_METADATA_ENABLE
value: 'false'
- name: OTEL_EBPF_BPF_CONTEXT_PROPAGATION
value: 'all'
securityContext:
privileged: true
shareProcessNamespace: true
securityContext: {}
--set mw-autoinstrumentation.opentelemetry-operator.enabled=false
K8s Network Debug Pod Spin up a temporary debug pod with curl, dig, nslookup, netcat and other network tools pre-installed:
kubectl run debug --rm -it --image=nicolaka/netshoot -n <NAMESPACE> -- /bin/bash
Once inside the debug pod:
curl -v http://mw-service.mw-agent-ns:9320
nslookup mw-service.mw-agent-ns
dig mw-service.mw-agent-ns
nc -zv mw-service.mw-agent-ns 9320
ping mw-service.mw-agent-ns
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: mw-autoinstrumentation
namespace: mw-agent-ns
spec:
exporter:
endpoint: http://mw-service.mw-agent-ns:9319
propagators:
- tracecontext
- baggage
- b3
sampler:
type: parentbased_traceidratio
argument: "1.0"
python:
env:
- name: MW_AGENT_SERVICE
value: mw-service.mw-agent-ns.svc.cluster.local
- name: GIT_PYTHON_REFRESH
value: quiet
- name: MW_K8S_PYTHON_INSTRUMENTATION
value: 'true'
- name: MW_TRACKER
value: 'false'
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://mw-service.mw-agent-ns:9320
- name: MW_API_KEY
value: your-api-key
- name: OTEL_PROPAGATORS
value: tracecontext,baggage,b3
nodejs:
env:
- name: OTEL_NODE_DISABLED_INSTRUMENTATIONS
value: fs,dns,net
- name: OTEL_PROPAGATORS
value: b3,tracecontext,baggage
go:
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://mw-service.mw-agent-ns:9319
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: grpc
- name: OTEL_PROPAGATORS
value: b3,tracecontext,baggage
dotnet:
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://mw-service.mw-agent-ns:9320
- name: OTEL_PROPAGATORS
value: b3,tracecontext,baggage
java:
env:
- name: MW_AGENT_SERVICE
value: mw-service.mw-agent-ns.svc.cluster.local
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://mw-service.mw-agent-ns:9319
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: grpc
- name: MW_API_KEY
value: your-api-key
- name: OTEL_PROPAGATORS
value: tracecontext,baggage,b3
helm install mw-agent middleware-labs/mw-kube-agent-v3 \
--version 1.6.7 \
--set global.mw.apiKey=api-key \
--set global.mw.target=https://msehd-fdr.middleware.io:443 \
--set opsai.enabled=true \
--set mw-autoinstrumentation.enabled=true \
--set global.clusterMetadata.name=old \
-n mw-agent-ns --create-namespace
kubectl get all -A | wc -l
helm upgrade mw-agent middleware-labs/mw-kube-agent-v3 \
--reuse-values \
--set daemonset.resources.limits.memory=1024Mi \
-n mw-agent-ns \
--server-side=false
kubectl patch deployment mw-agent-opentelemetry-operator \
-n mw-agent-ns \
--type='json' \
-p='[{"op": "replace", "path": "/spec/template/spec/containers/0/resources/limits/memory", "value": "1Gi"}]'
kubectl patch deployment mw-agent-opentelemetry-operator \
-n mw-agent-ns \
--type='json' \
-p='[
{
"op": "add",
"path": "/spec/template/spec/containers/0/args/-",
"value": "--zap-log-level=debug"
}
]'