
Dt Obs Kubernetes
- 1.5k installs
- 119 repo stars
- Updated July 29, 2026
- dynatrace/dynatrace-for-ai
dt-obs-kubernetes provides documented workflows for >-
About
The dt-obs-kubernetes skill >- # Infrastructure Kubernetes Monitor and analyze Kubernetes infrastructure using Dynatrace DQL. Query cluster resources, monitor workload health, analyze pod placement, optimize costs, and assess security posture. ## When to Use This Skill - Monitoring Kubernetes cluster health and capacity - Analyzing pod and container resource utilization - Investigating pod failures, OOMKills, evictions, or crash loops - Debugging degraded deployments, stuck rollouts, or node pressure - Optimizing Kubernetes resource costs - Assessing security posture and compliance - Troubleshooting workload scheduling and placement - Auditing ingress routing and network policies ## Knowledge Base Structure ### Core Monitoring (Start Here) 1. **Cluster Inventory** → `references/cluster-inventory.md` - Clusters, namespaces, resource distribution 2. **Node Monitoring** - Node capacity, CPU/memory usage, pod density 3. **Pod Monitoring** - Pod CPU, memory, lifecycle events 4. **Workload Monitoring** - Deployment, StatefulSet, DaemonSet resources ### Advanced Topics 1. **Configuration Analysis** → `references/labels-annotations.md` - Parse k8s.object, labels, annotations 2. **Scheduli.
- Monitoring Kubernetes cluster health and capacity
- Analyzing pod and container resource utilization
- Investigating pod failures, OOMKills, evictions, or crash loops
- Debugging degraded deployments, stuck rollouts, or node pressure
- Optimizing Kubernetes resource costs
Dt Obs Kubernetes by the numbers
- 1,465 all-time installs (skills.sh)
- +83 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #152 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
dt-obs-kubernetes capabilities & compatibility
- Capabilities
- monitoring kubernetes cluster health and capacit · analyzing pod and container resource utilization · investigating pod failures, oomkills, evictions, · debugging degraded deployments, stuck rollouts, · optimizing kubernetes resource costs
- Use cases
- documentation
What dt-obs-kubernetes says it does
# Infrastructure Kubernetes Monitor and analyze Kubernetes infrastructure using Dynatrace DQL.
Query cluster resources, monitor workload health, analyze pod placement, optimize costs, and assess security posture.
npx skills add https://github.com/dynatrace/dynatrace-for-ai --skill dt-obs-kubernetesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.5k |
|---|---|
| repo stars | ★ 119 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 29, 2026 |
| Repository | dynatrace/dynatrace-for-ai ↗ |
How do I use dt-obs-kubernetes for the task described in its SKILL.md triggers?
>-
Who is it for?
Teams invoking dt-obs-kubernetes when the user request matches documented triggers and prerequisites.
Skip if: Skip when cached docs are missing, the request is a negative trigger, or another sibling skill owns the workflow.
When should I use this skill?
>-
What you get
Step-by-step guidance grounded in dt-obs-kubernetes documentation and reference files.
- Cluster topology query patterns
- Namespace inventory results
Files
Infrastructure Kubernetes
Monitor and analyze Kubernetes infrastructure using Dynatrace DQL. Query cluster resources, monitor workload health, analyze pod placement, optimize costs, and assess security posture.
When to Use This Skill
- Monitoring Kubernetes cluster health and capacity
- Analyzing pod and container resource utilization
- Investigating pod failures, OOMKills, evictions, or crash loops
- Debugging degraded deployments, stuck rollouts, or node pressure
- Optimizing Kubernetes resource costs
- Assessing security posture and compliance
- Troubleshooting workload scheduling and placement
- Auditing ingress routing and network policies
Knowledge Base Structure
Core Monitoring (Start Here)
1. Cluster Inventory → references/cluster-inventory.md - Clusters, namespaces, resource distribution 2. Node Monitoring - Node capacity, CPU/memory usage, pod density 3. Pod Monitoring - Pod CPU, memory, lifecycle events 4. Workload Monitoring - Deployment, StatefulSet, DaemonSet resources
Advanced Topics
1. Configuration Analysis → references/labels-annotations.md - Parse k8s.object, labels, annotations 2. Scheduling & Placement → references/pod-node-placement.md - Node selectors, affinity, taints, HA 3. Cost Optimization - Right-sizing, waste detection, efficiency scoring 4. Security & Compliance - Privileged containers, security contexts
Key Concepts
Entity Types
Workloads: K8S_DEPLOYMENT, K8S_STATEFULSET, K8S_DAEMONSET, K8S_JOB, K8S_CRONJOB, K8S_HORIZONTALPODAUTOSCALER Infrastructure: K8S_CLUSTER, K8S_NAMESPACE, K8S_NODE, K8S_POD Configuration: K8S_SERVICE, K8S_CONFIGMAP, K8S_SECRET, K8S_PERSISTENTVOLUMECLAIM, K8S_PERSISTENTVOLUME, K8S_INGRESS, K8S_NETWORKPOLICY
Query Types
smartscapeNodes - Query K8s entities:
smartscapeNodes K8S_POD
| filter k8s.namespace.name == "production"
| fields k8s.cluster.name, k8s.pod.nametimeseries - Monitor metrics over time:
timeseries cpu = sum(dt.kubernetes.container.cpu_usage),
by: {k8s.pod.name, k8s.namespace.name}
| fieldsAdd avg_cpu = arrayAvg(cpu)fetch logs - Analyze log events:
fetch logs
| filter k8s.namespace.name == "production" and loglevel == "ERROR"Core Fields
k8s.cluster.name,k8s.namespace.name,k8s.pod.name,k8s.node.namek8s.workload.name,k8s.workload.kind,k8s.container.namek8s.object- Full JSON configuration for deep inspectiontags[label]- Access labels and annotations
Available Metrics
CPU: dt.kubernetes.container.cpu_usage, cpu_throttled, limits_cpu, requests_cpu Memory: dt.kubernetes.container.memory_working_set, limits_memory, requests_memory Operations: dt.kubernetes.container.restarts, oom_kills Node: dt.kubernetes.node.pods_allocatable, cpu_allocatable, memory_allocatable, dt.kubernetes.pods
Entity Disambiguation
K8S_POD vs CONTAINER: these are different entity types in Dynatrace.
- `K8S_POD` — K8s-native entities with
k8s.objectJSON, scheduling state, conditions, and K8s metrics. Use this skill. - `CONTAINER` — Host-level container inventory (image, lifetime, host assignment). Use
dt-obs-hostsskill instead.
The smartscape edge is CONTAINER --(is_part_of)--> K8S_POD. To reach containers from a pod, traverse backward:
smartscapeNodes K8S_POD
| filter k8s.namespace.name == "<namespace>"
| traverse edgeTypes: {is_part_of}, targetTypes: {CONTAINER}, direction: backward, fieldsKeep: {id}
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, container.id=idService → K8S_POD Correlation
No direct smartscape edge exists between SERVICE and K8S_POD. The correlation key is the shared dimension k8s.workload.name. See Service → Pod Drill-Down in references/pod-debugging.md for the full two-step pattern.
Common Workflows
1. Cluster Health Check
List all clusters:
smartscapeNodes K8S_CLUSTER
| fields k8s.cluster.name, k8s.cluster.version, k8s.cluster.distributionCheck node capacity:
timeseries {
current_pods = avg(dt.kubernetes.pods),
max_pods = avg(dt.kubernetes.node.pods_allocatable)
}, by: {k8s.node.name, k8s.cluster.name}
| fieldsAdd pod_capacity_pct = (arrayAvg(current_pods) / arrayAvg(max_pods)) * 100
| filter pod_capacity_pct > 80Identify pods in non-Running state:
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| fieldsAdd phase = config[status][phase]
| filter phase != "Running"
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, phase2. Resource Optimization
Find over-provisioned pods (usage < 30%):
timeseries {
cpu_usage = sum(dt.kubernetes.container.cpu_usage),
cpu_requests = avg(dt.kubernetes.container.requests_cpu)
}, by: {k8s.pod.name, k8s.namespace.name, k8s.cluster.name}
| fieldsAdd usage_pct = (arrayAvg(cpu_usage) / arrayAvg(cpu_requests)) * 100
| filter usage_pct < 30 and arrayAvg(cpu_requests) > 0Identify containers without limits:
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| expand container = config[spec][containers]
| fieldsAdd
container_name = container[name],
cpu_limit = container[resources][limits][cpu],
memory_limit = container[resources][limits][memory]
| filter isNull(cpu_limit) or isNull(memory_limit)3. Troubleshooting Pod Issues
Pod troubleshooting benefits from combining metrics (timeseries) with Kubernetes events (event stream) for a complete picture.
Metrics-Based Troubleshooting
Find pods with OOMKills:
timeseries oom_kills = sum(dt.kubernetes.container.oom_kills),
by: {k8s.pod.name, k8s.namespace.name, k8s.cluster.name}
| filter arraySum(oom_kills) > 0
| fieldsAdd total_oom_kills = arraySum(oom_kills)
| sort total_oom_kills descAnalyze pod restart patterns:
timeseries restarts = sum(dt.kubernetes.container.restarts),
by: {k8s.pod.name, k8s.namespace.name, k8s.cluster.name}
| fieldsAdd total_restarts = arraySum(restarts)
| filter total_restarts > 5Event-Based Troubleshooting
For operational events (pod restarts, OOM kills, evictions, scheduling failures), Kubernetes events provide richer context than metrics alone — including event reasons, messages, and timestamps.
When to use Kubernetes events over metrics:
- User asks about recent operational events ("show me pod restart events")
- User wants event details like reasons and messages
- User asks about events in a specific time window ("last 48 hours")
- User wants to correlate events with root causes
Kubernetes events are available through the get-events-for-kubernetes-cluster tool. Prefer this tool when the user asks about OOM events, pod restarts, evictions, or cluster-wide event history.
Important: distinguish event types when filtering results. Kubernetes events cover many categories. When the user asks about a specific event type, filter the results accordingly — do not report unrelated events:
| User Asks About | Relevant Event Reasons | NOT Related |
|---|---|---|
| Pod restarts | BackOff, CrashLoopBackOff, Killing | Readiness probe failures, CPU throttling |
| OOM events | OOMKilling, OOMKilled | Memory pressure warnings |
| Evictions | Evicted, Preempting | Node pressure |
| Scheduling failures | FailedScheduling, Unschedulable | Resource quotas |
For a complete answer, combine both approaches: 1. Use the events tool to get the event details (what happened, when, why) 2. Use timeseries metrics to show the quantitative impact (how many restarts, OOM kill counts over time)
Fetch Kubernetes Events via DQL
Pod restart and operational events can also be queried via DQL from the events table:
fetch events
| filter event.kind == "K8S_EVENT"
| filter event.type == "Warning"
| fields timestamp, k8s.cluster.name, k8s.namespace.name, k8s.pod.name,
event.reason, event.message
| sort timestamp desc
| limit 50Filter for specific event reasons:
fetch events
| filter event.kind == "K8S_EVENT"
| filter in(event.reason, {"OOMKilling", "BackOff", "Evicted", "FailedScheduling"})
| fields timestamp, k8s.cluster.name, k8s.namespace.name, k8s.pod.name,
event.reason, event.message
| sort timestamp descField names in `fetch events`: Use event.reason and event.message — not dt.kubernetes.event.reason. The dt.kubernetes.* prefix is for timeseries metrics, not the events table. Queries using the wrong prefix return zero results.
4. Security Assessment
Identify privileged containers:
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| expand container = config[spec][containers]
| fieldsAdd
container_name = container[name],
privileged = container[securityContext][privileged]
| filter privileged == trueFind containers running as root:
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| expand container = config[spec][containers]
| fieldsAdd
container_name = container[name],
run_as_user = container[securityContext][runAsUser],
run_as_non_root = container[securityContext][runAsNonRoot]
| filter (isNull(run_as_user) or run_as_user == 0) and run_as_non_root != true5. Scheduling Analysis
Verify pod distribution (HA compliance):
smartscapeNodes K8S_POD
| filter k8s.workload.kind == "deployment"
| summarize pod_count = count(),
node_count = countDistinct(k8s.node.name),
by: {k8s.cluster.name, k8s.namespace.name, k8s.workload.name}
| fieldsAdd ha_compliant = node_count > 1
| filter pod_count >= 2 and not ha_compliant6. DAVIS Problems affecting K8s Entities
Find active DAVIS problems affecting K8s entities:
fetch dt.davis.problems, from:now() - 2h
| filter not(dt.davis.is_duplicate) and event.status == "ACTIVE"
| filter matchesPhrase(smartscape.affected_entity.types, "K8S_")
| fields display_id, event.name, event.category, smartscape.affected_entity.idsUse entries smartscape.affected_entity.ids (array of Smartscape IDs) to look up the affected entity using its Smartscape ID.
Best Practices
Choosing the Right Data Source
| User Question | Best Approach | Why |
|---|---|---|
| "Show me OOM events" | Events tool + metrics | Events give reasons/messages; metrics show trends |
| "Show me pod restart events" | Events tool + timeseries metrics | Events reveal the reason (BackOff, Killing, CrashLoopBackOff); dt.kubernetes.container.restarts metric gives the actual restart counts |
| "How many pod restarts?" | Timeseries metrics | Quantitative data over time |
| "What happened to my pods in the last 48h?" | Events tool | Operational event history with context |
| "Which pods are using the most CPU?" | Timeseries metrics | Resource utilization analysis |
| "List all clusters/namespaces" | smartscapeNodes | Entity discovery and inventory |
| "Are there scheduling failures?" | Events tool | Event reasons explain why |
Query Performance
1. Filter early - Apply cluster/namespace filters immediately 2. Use specific entity types - Avoid wildcards 3. Limit result sets - Use limit for exploration 4. Cache cluster lists - Store in variables
Monitoring Recommendations
1. Set resource limits on all containers 2. Monitor OOMKills and adjust memory limits 3. Track CPU throttling and adjust CPU limits 4. Review resource efficiency regularly (target 70-80%) 5. Implement security best practices (non-root, read-only filesystem) 6. Use specific image tags (avoid :latest)
Configuration Standards
1. Use labels for organization (app, environment, team) 2. Set resource requests and limits 3. Configure health checks (liveness/readiness probes) 4. Use TLS for all ingress resources 5. Document with annotations
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| No pod data returned | Wrong entity type or missing cluster filter | Use K8S_POD (not POD); add k8s.cluster.name filter |
k8s.object parsing errors | Complex JSON structure | Use parse k8s.object, "JSON:config" then access nested fields |
| Pod network metrics unavailable | Not available in Grail | Use service mesh metrics or host-level network metrics |
| Large result sets | No time range or cluster filter | Add time range and filter by cluster/namespace early |
| Missing labels in output | Labels accessed incorrectly | Use tags[label_name] to access labels |
Limitations
Unavailable Metrics:
- Pod network metrics (rx_bytes, tx_bytes) are NOT available in Grail
- Workaround: Use service mesh metrics or host-level network metrics
Query Considerations:
- Minimize result set size: Do not include the
k8s.objectfield if not necessary - Keep result set as simple as possible: Parsing k8s.object increases query complexity
- Large clusters may require pagination or time-range limits
- Some K8s status fields update asynchronously
When to Load References
Load cluster-inventory.md when:
- Performing cluster, namespace, or resource distribution analysis
- Auditing workload counts across clusters
→ references/cluster-inventory.md
Load labels-annotations.md when:
- Filtering by labels or annotations
- Parsing
k8s.objectfor detailed configuration inspection
→ references/labels-annotations.md
Load pod-node-placement.md when:
- Analyzing scheduling constraints (affinity, taints, tolerations)
- Verifying HA compliance and pod distribution
→ references/pod-node-placement.md
Load pod-debugging.md when:
- Investigating pod exit codes, crash loops, or init container failures
- Diagnosing image pull errors or service-to-pod connectivity issues
- Drilling down from a service problem to pod-level details
→ references/pod-debugging.md
Load workload-health.md when:
- Investigating degraded deployments or stuck rollouts
- Checking node conditions, CPU throttling, or HPA scaling
- Analyzing StatefulSet ordering or DaemonSet coverage
→ references/workload-health.md
Load pv-pvc.md when:
- Working with persistent storage (PVC/PV lifecycle, orphaned volumes)
- Checking StorageClass configurations
→ references/pv-pvc.md
Load ingress.md when:
- Analyzing ingress routing rules or TLS certificates
- Auditing ingress controller configurations
→ references/ingress.md
Load network-policies.md when:
- Listing or auditing network policies
- Checking namespace isolation configurations
→ references/network-policies.md
References
- cluster-inventory.md — Cluster, namespace, and resource distribution analysis
- labels-annotations.md — Label/annotation filtering and k8s.object parsing
- pod-node-placement.md — Scheduling, affinity, taints, and HA patterns
- pod-debugging.md — Exit codes, pod conditions, init containers, image pull errors, logs, service-to-pod drill-down
- workload-health.md — Degraded deployments, stuck rollouts, node conditions, CPU throttling, HPA, StatefulSet ordering
- pv-pvc.md — PVC/PV lifecycle, phase reference, orphaned volumes, StorageClass
- ingress.md — Routing rule parsing, TLS audit
- network-policies.md — Policy listing, namespace isolation audit
Related Skills
- dt-obs-problems — For problems associated with Kubernetes clusters (use
dt.smartscape_source.idwith K8S_ prefix filters) - dt-dql-essentials — Core DQL syntax and query structure
- dt-obs-hosts — Host-level metrics for K8s nodes
Kubernetes Cluster and Namespace Inventory - Reference
Deep dive into cluster and namespace inventory queries for understanding Kubernetes topology, resource distribution, and organizational hierarchy.
Overview
Cluster and namespace entities provide the organizational foundation for Kubernetes resources. This reference covers comprehensive querying patterns for cluster topology, namespace distribution, and resource organization.
Contents
- Cluster Queries
- List All Clusters
- Cluster by Distribution
- Cluster Version Summary
- Count Nodes per Cluster
- Namespace Queries
- List All Namespaces
- Count Namespaces per Cluster
- Filter System Namespaces
- Find Empty Namespaces
- Resource Distribution
- Count All Resources per Cluster
- Pod Distribution per Cluster
- Workload Distribution per Cluster
- Namespace Resource Summary
- Multi-Cluster Queries
- Compare Clusters
- Find Clusters with Specific Workload
- Namespace Naming Patterns
- Cluster Health Overview
- Cluster Entity Count
- Clusters with Nodes
- Namespace Analysis
- Largest Namespaces by Pod Count
- Namespace Age
- Namespaces by Label
- Resource Organization
- Services per Namespace
- ConfigMaps per Namespace
- Secrets per Namespace
- Advanced Patterns
- Multi-Cluster Resource Comparison
- Namespace Resource Density
- Cluster Growth Tracking
- Best Practices
- Related Topics
Cluster Queries
List All Clusters
// List all Kubernetes clusters monitored by Dynatrace
smartscapeNodes K8S_CLUSTER
| fields k8s.cluster.name, k8s.cluster.uid, k8s.cluster.version, k8s.cluster.distribution
| sort k8s.cluster.nameCluster by Distribution
// Count clusters by Kubernetes distribution
smartscapeNodes K8S_CLUSTER
| summarize count(), by: {k8s.cluster.distribution}
| sort k8s.cluster.distributionCluster Version Summary
// List clusters with their Kubernetes versions
smartscapeNodes K8S_CLUSTER
| fields k8s.cluster.name, k8s.cluster.version, k8s.cluster.distribution
| sort k8s.cluster.version descCount Nodes per Cluster
// Count nodes in each cluster
smartscapeNodes K8S_NODE
| summarize node_count = count(), by: {k8s.cluster.name}
| sort node_count descNamespace Queries
List All Namespaces
// List all namespaces across all clusters
smartscapeNodes K8S_NAMESPACE
| fields k8s.cluster.name, k8s.namespace.name
| sort k8s.cluster.name, k8s.namespace.nameCount Namespaces per Cluster
// Count namespaces in each cluster
smartscapeNodes K8S_NAMESPACE
| summarize namespace_count = count(), by: {k8s.cluster.name}
| sort namespace_count descFilter System Namespaces
// List only application namespaces (exclude system)
smartscapeNodes K8S_NAMESPACE
| filterOut in(k8s.namespace.name, {"kube-system", "kube-public",
"kube-node-lease", "dynatrace"})
| fields k8s.cluster.name, k8s.namespace.name
| sort k8s.cluster.name, k8s.namespace.nameFind Empty Namespaces
// Find namespaces with no pods
// Note: Uses composite key workaround because array syntax is not supported
// in lookup fields
smartscapeNodes K8S_NAMESPACE
| fieldsAdd composite_key = concat(k8s.cluster.name, "|", k8s.namespace.name)
| lookup [
smartscapeNodes K8S_POD
| summarize pod_count = count(), by: {k8s.cluster.name, k8s.namespace.name}
| fieldsAdd composite_key = concat(k8s.cluster.name, "|", k8s.namespace.name)
], sourceField: composite_key, lookupField: composite_key
| filter isNull(pod_count)
| fields k8s.cluster.name, k8s.namespace.nameResource Distribution
Count All Resources per Cluster
// Count all Kubernetes resources by type per cluster
smartscapeNodes "K8S_*"
| summarize count(), by: {k8s.cluster.name, type}
| sort k8s.cluster.name, typePod Distribution per Cluster
// Count pods per cluster
smartscapeNodes K8S_POD
| summarize pod_count = count(), by: {k8s.cluster.name}
| sort pod_count descWorkload Distribution per Cluster
// Count workloads by type per cluster
smartscapeNodes K8S_DEPLOYMENT, K8S_STATEFULSET, K8S_DAEMONSET
| summarize count(), by: {k8s.cluster.name, k8s.workload.kind}
| sort k8s.cluster.name, k8s.workload.kindNamespace Resource Summary
// Count resources per namespace
smartscapeNodes K8S_POD, K8S_DEPLOYMENT, K8S_STATEFULSET, K8S_DAEMONSET, K8S_SERVICE
| summarize resource_count = count(), by: {k8s.cluster.name, k8s.namespace.name, type}
| sort k8s.cluster.name, k8s.namespace.name, typeMulti-Cluster Queries
Compare Clusters
// Compare resource counts across clusters
smartscapeNodes K8S_POD
| summarize pod_count = count(), by: {k8s.cluster.name}
| sort pod_count descFind Clusters with Specific Workload
// Find clusters running a specific workload
smartscapeNodes K8S_DEPLOYMENT
| filter k8s.workload.name == "nginx"
| dedup k8s.cluster.name
| sort k8s.cluster.nameNamespace Naming Patterns
// Analyze namespace naming patterns
smartscapeNodes K8S_NAMESPACE
| parse k8s.namespace.name, "LD:prefix '-' LD:suffix"
| filter isNotNull(prefix)
| summarize namespace_count = count(), by: {prefix}
| sort namespace_count descCluster Health Overview
Cluster Entity Count
// Get total entity count per cluster
smartscapeNodes "K8S_*"
| summarize total_entities = count(), by: {k8s.cluster.name}
| sort total_entities descClusters with Nodes
// Verify all clusters have active nodes
smartscapeNodes K8S_CLUSTER
| lookup [
smartscapeNodes K8S_NODE
| summarize node_count = count(), by: {k8s.cluster.name}
], sourceField: k8s.cluster.name, lookupField: k8s.cluster.name
| fields k8s.cluster.name, node_count
| sort k8s.cluster.nameNamespace Analysis
Largest Namespaces by Pod Count
// Find namespaces with most pods
smartscapeNodes K8S_POD
| summarize pod_count = count(), by: {k8s.cluster.name, k8s.namespace.name}
| sort pod_count desc
| limit 20Namespace Age
// Calculate namespace age
smartscapeNodes K8S_NAMESPACE
| fieldsAdd age_days = (now() - lifetime[start]) / 1d
| fields k8s.cluster.name, k8s.namespace.name, age_days
| sort age_days descNamespaces by Label
// Group namespaces by environment label
smartscapeNodes K8S_NAMESPACE
| filter isNotNull(tags[environment])
| summarize namespaces = collectDistinct(k8s.namespace.name),
by: {k8s.cluster.name, environment = tags[environment]}
| sort k8s.cluster.name, environmentResource Organization
Services per Namespace
// Count services per namespace
smartscapeNodes K8S_SERVICE
| summarize service_count = count(), by: {k8s.cluster.name, k8s.namespace.name}
| sort service_count descConfigMaps per Namespace
// Count configmaps per namespace
smartscapeNodes K8S_CONFIGMAP
| summarize configmap_count = count(), by: {k8s.cluster.name, k8s.namespace.name}
| sort configmap_count descSecrets per Namespace
// Count secrets per namespace
smartscapeNodes K8S_SECRET
| summarize secret_count = count(), by: {k8s.cluster.name, k8s.namespace.name}
| sort secret_count descAdvanced Patterns
Multi-Cluster Resource Comparison
// Compare resource distribution across clusters
smartscapeNodes K8S_POD, K8S_DEPLOYMENT, K8S_SERVICE
| summarize count(), by: {k8s.cluster.name, type}
| fields cluster = k8s.cluster.name, resource_type = type, count = `count()`Namespace Resource Density
// Calculate resource density per namespace
smartscapeNodes K8S_POD
| summarize pod_count = count(), by: {k8s.cluster.name, k8s.namespace.name}
| lookup [
smartscapeNodes K8S_SERVICE
| summarize service_count = count(),
by: {k8s.cluster.name, k8s.namespace.name}
], sourceField: k8s.cluster.name,
lookupField: k8s.cluster.name
| fieldsAdd pod_to_service_ratio = pod_count / service_count
| filter isNotNull(service_count) and service_count > 0
| sort pod_to_service_ratio descCluster Growth Tracking
// Track new namespaces created in last 7 days
smartscapeNodes K8S_NAMESPACE
| fieldsAdd age_days = (now() - lifetime[start]) / 1d
| filter age_days <= 7
| fields k8s.cluster.name, k8s.namespace.name, age_days
| sort age_days ascBest Practices
1. Cache Cluster List: Store cluster names in variables for repeated queries:
smartscapeNodes K8S_CLUSTER
| fields cluster = k8s.cluster.name
| summarize clusters = collectArray(cluster)2. Exclude System Resources: Filter out system namespaces for application-focused analysis:
| filterOut in(k8s.namespace.name, {"kube-system", "kube-public",
"kube-node-lease"})3. Use Lookups: Join cluster/namespace data with resource counts for comprehensive views
4. Monitor Distribution: Track resource distribution to identify overloaded clusters/namespaces
5. Track Changes: Compare entity counts over time to detect cluster changes
Related Topics
- Labels & Annotations →
labels-annotations.md- Filter namespaces by
labels
- Pod Placement →
pod-node-placement.md- Analyze pod distribution
within clusters
- Workload Queries (documentation) - Query specific workload types
- Entity Relationships (documentation) - Navigate cluster topology
Ingress
Query K8S_INGRESS entities, parse routing rules, and audit TLS configuration.
Relationships
K8S_INGRESS --(routes_to)--> K8S_SERVICE
K8S_INGRESS --(belongs_to)--> K8S_NAMESPACE
K8S_INGRESS --(belongs_to)--> K8S_CLUSTERList Ingresses
smartscapeNodes K8S_INGRESS
| fields k8s.cluster.name, k8s.namespace.name, k8s.ingress.name
| sort k8s.cluster.name, k8s.namespace.nameParse Routing Rules
spec.rules maps host + path patterns to backend services and ports.
smartscapeNodes K8S_INGRESS
| parse k8s.object, "JSON:config"
| fieldsAdd rules = config[`spec`][`rules`]
| expand rule = rules
| fieldsAdd
host = rule[`host`],
paths = rule[`http`][`paths`]
| expand path_entry = paths
| fieldsAdd
path = path_entry[`path`],
backend_svc = path_entry[`backend`][`service`][`name`],
backend_port = path_entry[`backend`][`service`][`port`][`number`]
| fields k8s.cluster.name, k8s.namespace.name, k8s.ingress.name,
host, path, backend_svc, backend_portOutput is a routing map: host/path → service:port.
TLS Audit
Ingresses without TLS (cleartext):
smartscapeNodes K8S_INGRESS
| parse k8s.object, "JSON:config"
| fieldsAdd tls = config[`spec`][`tls`]
| filter isNull(tls)
| fields k8s.cluster.name, k8s.namespace.name, k8s.ingress.nameIngresses with TLS — certificate secrets in use:
smartscapeNodes K8S_INGRESS
| parse k8s.object, "JSON:config"
| expand tls_entry = config[`spec`][`tls`]
| fieldsAdd
tls_hosts = tls_entry[`hosts`],
tls_secret = tls_entry[`secretName`]
| fields k8s.cluster.name, k8s.namespace.name, k8s.ingress.name,
tls_hosts, tls_secretKubernetes Labels and Annotations - Reference
Deep dive into using Kubernetes labels and annotations for filtering, organizing, and managing K8s resources in Dynatrace DQL.
Overview
Kubernetes labels and annotations are exposed in Dynatrace smartscape entities through the tags array. These metadata fields enable powerful filtering, organization, and compliance tracking of K8s resources.
Contents
- Accessing Labels and Annotations
- Basic Query Patterns
- Filter by Label
- Filter by Multiple Labels
- Find Resources with Label Present
- Find Resources Missing Label
- Grouping and Aggregation
- Group by Label Value
- List All Label Values
- Summarize by Label Presence
- Multi-Cluster Label Analysis
- Pattern Matching and Validation
- Filter with Label Pattern Matching
- Find Mismatched Labels
- Multi-Value Label Filtering
- Compliance and Standards
- Check for Required Labels
- Label Coverage Report
- Find Non-Compliant Resources
- Annotation-Specific Queries
- Filter by Annotation
- Find Annotated Services
- Extract Documentation Annotations
- Namespace Label Queries
- Access Namespace Labels
- Namespace Label Propagation Check
- Cost and Ownership Tracking
- Cost Center Allocation
- Team Ownership Mapping
- Environment Resource Distribution
- Advanced Patterns
- Conditional Label Logic
- Label-Based Resource Correlation
- Label Migration Detection
- Label Naming Conventions
- Standard Kubernetes Labels
- Common Custom Labels
- Common Annotations
- Best Practices
- Query Best Practices
- Labeling Standards
- Common Use Cases
- Troubleshooting
- Label Not Found
- Special Characters in Labels
- Related Topics
Accessing Labels and Annotations
Syntax
Labels and annotations are accessed using the tags field with the key name:
Simple keys:
tags[app]
tags[environment]
tags[version]Keys with special characters (dots, slashes):
tags[`app.kubernetes.io/name`]
tags[`prometheus.io/scrape`]
tags[`example.com/annotation`]Key Types:
- Labels: Standard Kubernetes labels →
tags[label_key] - Annotations: Kubernetes annotations →
tags[annotation_key]
Both are accessed the same way in DQL.
Basic Query Patterns
Filter by Label
// Find pods with specific label
smartscapeNodes K8S_POD
| filter tags[app] == "checkout-service"
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.nameFilter by Multiple Labels
// Find pods matching multiple labels
smartscapeNodes K8S_POD
| filter tags[app] == "frontend" and tags[environment] == "production"
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.nameFind Resources with Label Present
// Find deployments that have a specific label set
smartscapeNodes K8S_DEPLOYMENT
| filter isNotNull(tags[version])
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name, tags[version]Find Resources Missing Label
// Find deployments without owner label
smartscapeNodes K8S_DEPLOYMENT
| filter isNull(tags[owner])
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.nameUse Case: Identify resources that don't comply with labeling standards
Grouping and Aggregation
Group by Label Value
// Count pods by application label
smartscapeNodes K8S_POD
| filter isNotNull(tags[app])
| summarize pod_count = count(), by: {k8s.cluster.name, app_label = tags[app]}
| sort pod_count descList All Label Values
// Find all unique values for environment label
smartscapeNodes K8S_DEPLOYMENT, K8S_STATEFULSET
| filter isNotNull(tags[environment])
| summarize by: {environment = tags[environment]}, count()
| sort environmentUse Case: Discover what values are being used for a label across your infrastructure
Summarize by Label Presence
// Count workloads by presence of monitoring label
smartscapeNodes K8S_DEPLOYMENT, K8S_STATEFULSET
| fieldsAdd has_monitoring = if(isNotNull(tags[monitoring]), "yes", else: "no")
| summarize count(), by: {k8s.cluster.name, has_monitoring}Multi-Cluster Label Analysis
// Compare label usage across clusters
smartscapeNodes K8S_POD
| filter isNotNull(tags[tier])
| summarize pod_count = count(), by: {k8s.cluster.name, tier = tags[tier]}
| sort k8s.cluster.name, pod_count descPattern Matching and Validation
Filter with Label Pattern Matching
// Find pods with labels starting with specific prefix
smartscapeNodes K8S_POD
| filter matchesPhrase(tags[app], "payment-*")
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, tags[app]Find Mismatched Labels
// Find pods where app and service labels don't match
smartscapeNodes K8S_POD
| filter isNotNull(tags[app]) and isNotNull(tags[service])
| filter tags[app] != tags[service]
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name,
tags[app], tags[service]Use Case: Detect labeling inconsistencies
Multi-Value Label Filtering
// Find pods with label in set of values
smartscapeNodes K8S_POD
| filter in(tags[tier], {"frontend", "backend", "database"})
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, tier = tags[tier]
| sort tierCompliance and Standards
Check for Required Labels
// Find deployments missing required labels
smartscapeNodes K8S_DEPLOYMENT
| filter isNull(tags[owner]) or isNull(tags[team]) or isNull(tags[`cost-center`])
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name,
owner = tags[owner], team = tags[team], cost_center = tags[`cost-center`]Use Case: Enforce organizational labeling policies
Label Coverage Report
// Report on label coverage across deployments
smartscapeNodes K8S_DEPLOYMENT
| fieldsAdd
has_owner = isNotNull(tags[owner]),
has_team = isNotNull(tags[team]),
has_environment = isNotNull(tags[environment]),
has_version = isNotNull(tags[version])
| summarize
total = count(),
with_owner = countIf(has_owner),
with_team = countIf(has_team),
with_environment = countIf(has_environment),
with_version = countIf(has_version),
by: {k8s.cluster.name}
| fieldsAdd
owner_pct = 100.0 * with_owner / total,
team_pct = 100.0 * with_team / total,
environment_pct = 100.0 * with_environment / total,
version_pct = 100.0 * with_version / totalFind Non-Compliant Resources
// Find resources not following naming conventions
smartscapeNodes K8S_POD
| filter isNotNull(tags[app])
| filter not matchesPhrase(tags[app], "*-service")
and not matchesPhrase(tags[app], "*-worker")
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, tags[app]Annotation-Specific Queries
Filter by Annotation
// Find pods with Prometheus scraping enabled
smartscapeNodes K8S_POD
| filter tags[`prometheus.io/scrape`] == "true"
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name,
tags[`prometheus.io/port`], tags[`prometheus.io/path`]Find Annotated Services
// Find services with specific cloud provider annotation
smartscapeNodes K8S_SERVICE
| filter tags[`service.beta.kubernetes.io/aws-load-balancer-type`] == "nlb"
| fields k8s.cluster.name, k8s.namespace.name, k8s.service.nameExtract Documentation Annotations
// Find resources with documentation annotations
smartscapeNodes K8S_DEPLOYMENT, K8S_STATEFULSET
| filter isNotNull(tags[`description`])
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name,
description = tags[`description`]Namespace Label Queries
Access Namespace Labels
// Query namespaces by labels
smartscapeNodes K8S_NAMESPACE
| filter tags[environment] == "production"
| fields k8s.cluster.name, k8s.namespace.name, tags[environment], tags[team]Namespace Label Propagation Check
// Check if pods inherit namespace labels
smartscapeNodes K8S_POD
| filter k8s.namespace.name == "production-app"
| lookup [
smartscapeNodes K8S_NAMESPACE
| fields k8s.namespace.name, ns_env = tags[environment]
], sourceField: k8s.namespace.name, lookupField: k8s.namespace.name
| fieldsAdd pod_env = tags[environment]
| filter ns_env != pod_env
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, ns_env, pod_envCost and Ownership Tracking
Cost Center Allocation
// Aggregate pod count by cost center
smartscapeNodes K8S_POD
| filter isNotNull(tags[`cost-center`])
| summarize pod_count = count(), by: {cost_center = tags[`cost-center`]}
| sort pod_count descTeam Ownership Mapping
// Map resources to owning teams
smartscapeNodes K8S_DEPLOYMENT, K8S_STATEFULSET
| filter isNotNull(tags[team])
| summarize workload_count = count(), by: {k8s.cluster.name, team = tags[team]}
| sort k8s.cluster.name, workload_count descEnvironment Resource Distribution
// Count resources per environment
smartscapeNodes K8S_POD
| filter isNotNull(tags[environment])
| summarize pod_count = count(), by: {environment = tags[environment], k8s.cluster.name}
| sort environment, pod_count descAdvanced Patterns
Conditional Label Logic
// Classify workloads by label patterns
smartscapeNodes K8S_DEPLOYMENT
| fieldsAdd workload_class = if(
matchesPhrase(tags[app], "*-api"), "API",
else: if(matchesPhrase(tags[app], "*-worker"), "Worker",
else: if(matchesPhrase(tags[app], "*-frontend"), "Frontend",
else: "Unknown"))
)
| summarize count(), by: {k8s.cluster.name, workload_class}Label-Based Resource Correlation
// Correlate pods with their parent workload labels
smartscapeNodes K8S_POD
| filter isNotNull(k8s.workload.name)
| lookup [
smartscapeNodes K8S_DEPLOYMENT, K8S_STATEFULSET
| fields k8s.workload.name, workload_env = tags[environment]
], sourceField: k8s.workload.name, lookupField: k8s.workload.name
| fieldsAdd pod_env = tags[environment]
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, pod_env, workload_envLabel Migration Detection
// Find resources using deprecated labels
smartscapeNodes K8S_POD
| filter isNotNull(tags[app]) and isNull(tags[`app.kubernetes.io/name`])
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name,
old_label = tags[app]Use Case: Track migration from legacy label keys to recommended keys
Label Naming Conventions
Standard Kubernetes Labels
Recommended label keys (kubernetes.io namespace):
app.kubernetes.io/name- Application nameapp.kubernetes.io/instance- Unique instance nameapp.kubernetes.io/version- Application versionapp.kubernetes.io/component- Component in the architectureapp.kubernetes.io/part-of- Higher-level application nameapp.kubernetes.io/managed-by- Tool managing the operation
Common Custom Labels
Application labels:
app- Application name (legacy, prefer app.kubernetes.io/name)version- Application versioncomponent- Application component
Organizational labels:
environment- Deployment environment (dev, staging, prod)owner- Owning team or individualteam- Team responsible for the resourcecost-center- Cost allocation identifier
Infrastructure labels:
tier- Application tier (frontend, backend, database)criticality- Business criticality (high, medium, low)region- Geographic region
Common Annotations
Kubernetes annotations:
kubernetes.io/created-by- Creator informationkubernetes.io/description- Resource description
Tool-specific annotations:
prometheus.io/scrape- Enable Prometheus scrapingprometheus.io/port- Metrics portprometheus.io/path- Metrics endpoint path
Cloud provider annotations:
service.beta.kubernetes.io/aws-load-balancer-type- AWS LB typeservice.beta.kubernetes.io/azure-load-balancer-internal- Azure internal LB
Best Practices
Query Best Practices
1. Use Backticks for Special Characters: Always wrap keys with dots or slashes in backticks
tags[``app.kubernetes.io/name``]
tags[``prometheus.io/scrape``]2. Check for Null: Use isNotNull() before accessing label values to avoid errors
| filter isNotNull(tags[app])
| fields tags[app]3. Filter Early: Apply label filters immediately after entity selection for better performance
smartscapeNodes K8S_POD
| filter tags[environment] == "production" // Early filter
| parse k8s.object, "JSON:config" // Then parse4. Use Summarize for Aggregations: Group by labels efficiently
| summarize count(), by: {app = tags[app], env = tags[environment]}Labeling Standards
1. Consistent Naming: Use standardized label keys across your organization
- Document required vs. optional labels
- Use domain prefixes for custom labels:
mycompany.io/label
2. Label Hierarchy: Establish clear label hierarchy
- Namespace-level: environment, team, cost-center
- Workload-level: app, version, component
- Pod-level: instance, replica
3. Validation: Implement label validation at deployment time
- Use admission webhooks
- Regular audits with compliance queries
4. Documentation: Use annotations for human-readable documentation
description- What the resource doescontact- Who to contact for issuesrunbook- Link to operational runbook
5. Avoid Overuse: Don't put dynamic data in labels
- Labels are for grouping and selection
- Use annotations for non-queryable metadata
- Limit: 63 characters per label value
Common Use Cases
| Use Case | Query Type | Example Label |
|---|---|---|
| Cost allocation | Group by cost-center | tags[cost-center] |
| Team ownership | Group by team | tags[team] |
| Environment isolation | Filter by environment | tags[environment] |
| Version tracking | Filter/group by version | tags[version] |
| Feature flags | Filter by feature label | tags[feature] |
| Compliance auditing | Check required labels | Multiple required labels |
| Resource organization | Group by tier/component | tier, component |
Troubleshooting
Label Not Found
Issue: Query returns no results when filtering by label
Solutions:
// Check if label exists
smartscapeNodes K8S_POD
| filter isNotNull(tags[your_label])// List all labels on a resource
smartscapeNodes K8S_POD
| limit 1
| parse k8s.object, "JSON:config"
| fieldsAdd labels = config[metadata][labels]Special Characters in Labels
Issue: Label key has dots, slashes, or other special characters
Solution: Use backticks
tags[`app.kubernetes.io/name`]
tags[`example.com/custom-label`]Related Topics
- Cluster Inventory →
cluster-inventory.md- Use labels to organize namespaces - Pod Placement →
pod-node-placement.md- Use labels for node selection - Security Posture (documentation) - Label-based compliance checks
- Cost Optimization (documentation) - Label-based cost tracking
Network Policies
Audit K8S_NETWORKPOLICY entities for namespace isolation coverage and inspect policy rules.
List All Network Policies
smartscapeNodes K8S_NETWORKPOLICY
| fields k8s.cluster.name, k8s.namespace.name, k8s.networkpolicy.name
| sort k8s.cluster.name, k8s.namespace.nameNamespaces Without Any Network Policy
Namespaces with no NetworkPolicy allow all ingress and egress by default — a default-allow posture.
smartscapeNodes K8S_NAMESPACE
| filterOut k8s.namespace.name in [
smartscapeNodes K8S_NETWORKPOLICY
| dedup k8s.namespace.name
| fields k8s.namespace.name
]
| fields k8s.cluster.name, k8s.namespace.namePolicy Count per Namespace
smartscapeNodes K8S_NETWORKPOLICY
| summarize policy_count = count(), by: {k8s.cluster.name, k8s.namespace.name}
| sort policy_count descPolicy Rule Inspection
Parse spec.podSelector, spec.policyTypes, spec.ingress, and spec.egress from k8s.object:
smartscapeNodes K8S_NETWORKPOLICY
| filter k8s.namespace.name == "<namespace>"
| parse k8s.object, "JSON:config"
| fieldsAdd
pod_selector = config[`spec`][`podSelector`],
policy_types = config[`spec`][`policyTypes`],
ingress_rules = config[`spec`][`ingress`],
egress_rules = config[`spec`][`egress`]
| fields k8s.cluster.name, k8s.namespace.name, k8s.networkpolicy.name,
pod_selector, policy_types, ingress_rules, egress_rulesPod Debugging
Exit codes, pod conditions, init container failures, image pull errors, and K8s-scoped log queries.
Note: OOMKill and restart metrics are available via dt.kubernetes.container.* metric series. This reference covers the complementary approach of parsing k8s.object for per-container state details not available in metrics.
Contents
- Exit Codes and Termination Reasons
- Pod Conditions
- Init Container Failures
- Image Pull Failures
- K8s-Scoped Log Queries
- Service → Pod Drill-Down
Exit Codes and Termination Reasons
Container exit codes from lastState.terminated explain why a container stopped:
| Exit code | Cause | Action |
|---|---|---|
137 | OOMKilled | Raise memory limit |
1 or 2 | Application crash | Check container logs |
143 | SIGTERM (graceful shutdown) | Normal or probe misconfiguration causing premature restart |
0 | Clean exit | Likely a failing readiness probe restarting a healthy container |
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| expand container = config[`status`][`containerStatuses`]
| fieldsAdd
container_name = container[`name`],
restart_count = container[`restartCount`],
exit_code = container[`lastState`][`terminated`][`exitCode`],
reason = container[`lastState`][`terminated`][`reason`]
| filter isNotNull(exit_code) and restart_count > 0
| sort restart_count desc
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, container_name,
restart_count, exit_code, reasonPod Conditions
status.conditions explains why a pod is not Ready or not Scheduled. status.condition is an array of objects, where the last element of the array represents the latest status.
| Condition | If False or Unknown means |
|---|---|
PodScheduled | No node accepted the pod (resource pressure, taint mismatch, affinity conflict) |
ContainersReady | At least one container not yet passing readiness probes |
Ready | Pod not ready to serve traffic |
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| expand condition = config[`status`][`conditions`][-1]
| fieldsAdd
cond_type = condition[`type`],
cond_status = condition[`status`],
cond_reason = condition[`reason`],
message = condition[`message`]
| filter (cond_status == "False" or cond_status == "Unknown") and cond_reason != "PodCompleted"
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name,
cond_type, cond_status, message, cond_reasonInit Container Failures
Init containers run sequentially before main containers start. A failed init container blocks the entire pod indefinitely.
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| expand init = config[`status`][`initContainerStatuses`]
| fieldsAdd
init_name = init[`name`],
init_ready = init[`ready`],
init_exit = coalesce(init[`state`][`terminated`][`exitCode`], init[`state`][`waiting`][`exitCode`], init[`state`][`terminated`][`running`])
| filter init_ready == false
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, init_name, init_exitImage Pull Failures
ImagePullBackOff and ErrImagePull appear in state.waiting.reason.
Note: Container image names are not available in smartscape — they are only accessible via k8s.object JSON parsing.
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| expand container = config[`status`][`containerStatuses`]
| fieldsAdd
container_name = container[`name`],
image = container[`image`],
reason = container[`state`][`waiting`][`reason`]
| filter in(reason, array("ImagePullBackOff", "ErrImagePull", "InvalidImageName"))
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, container_name, image, reasonK8s-Scoped Log Queries
Namespace-level log filtering for pod-specific and crash-window scenarios.
Errors from a specific pod:
fetch logs
| filter k8s.pod.name == "<pod-name>" and k8s.namespace.name == "<namespace>"
| filter loglevel == "ERROR"
| fields timestamp, k8s.container.name, content
| sort timestamp descLogs within a time window before a known restart:
fetch logs, from: <restart_timestamp> - 5m, to: <restart_timestamp>
| filter k8s.pod.name == "<pod-name>" and k8s.namespace.name == "<namespace>"
| sort timestamp descService → Pod Drill-Down
No direct smartscape edge exists between SERVICE and K8S_POD. Use the shared dimension k8s.workload.name as the correlation key.
Step 1 — find workloads with elevated error rate:
timeseries errors = sum(dt.service.request.failure_count),
by: {k8s.workload.name, k8s.namespace.name}
| fieldsAdd total_errors = arraySum(errors)
| filter total_errors > 0
| sort total_errors descStep 2 — filter pods by the identified workload and expand container statuses:
smartscapeNodes K8S_POD
| filter k8s.workload.name == "<workload-name>" and k8s.namespace.name == "<namespace>"
| parse k8s.object, "JSON:config"
| expand container = config[`status`][`containerStatuses`]
| fieldsAdd
phase = config[`status`][`phase`],
container_name = container[`name`],
container_ready = container[`ready`],
restart_count = container[`restartCount`],
exit_code = container[`lastState`][`terminated`][`exitCode`]
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name,
phase, container_name, container_ready, restart_count, exit_codeCross-reference exit codes with the table at the top of this file to determine the failure cause.
Node and Pod Placement - Reference
Deep dive into pod distribution, node characteristics, scheduling constraints, and high availability patterns in Kubernetes.
Overview
Understanding pod distribution across nodes is critical for resource utilization, high availability, and capacity planning. This reference covers comprehensive analysis of node characteristics and pod placement patterns.
Contents
- Node Queries
- List All Nodes
- Node Count per Cluster
- Find Unschedulable Nodes
- Extract Node Labels
- Node Taints Summary
- Pod Distribution
- Pods per Node
- Pod Distribution Balance
- Namespace Distribution per Node
- Workload Distribution per Node
- Pod Placement Constraints
- Pods with Node Selectors
- Pods with Node Affinity
- Pods with Tolerations
- Workloads with Anti-Affinity
- Node Capacity Analysis
- Nodes by Availability Zone
- Nodes by Instance Type
- Pod Distribution by Zone
- Scheduling Analysis
- DaemonSet Coverage
- Pods Pending Scheduling
- Single-Node Workloads (HA Risk)
- High Availability Patterns
- Multi-Node Deployment Verification
- Zone Distribution for Critical Apps
- StatefulSet Pod Distribution
- Advanced Patterns
- Node Pressure and Pod Placement
- Pod Spread by Topology
- Best Practices
- Common Issues and Solutions
- Related Topics
Node Queries
List All Nodes
// List all Kubernetes nodes
smartscapeNodes K8S_NODE
| fields k8s.cluster.name, k8s.node.name
| sort k8s.cluster.name, k8s.node.nameNode Count per Cluster
// Count nodes per cluster
smartscapeNodes K8S_NODE
| summarize node_count = count(), by: {k8s.cluster.name}
| sort node_count descFind Unschedulable Nodes
// Find nodes that are unschedulable (cordoned)
smartscapeNodes K8S_NODE
| parse k8s.object, "JSON:config"
| fieldsAdd taints = config[spec][taints]
| expand taint = taints
| filter taint[key] == "node.kubernetes.io/unschedulable"
| fields k8s.cluster.name, k8s.node.name, taint[effect]Extract Node Labels
// List nodes with their labels
smartscapeNodes K8S_NODE
| parse k8s.object, "JSON:config"
| fieldsAdd labels = config[metadata][labels]
| fieldsFlatten labels, prefix: "label."
| fields k8s.cluster.name, k8s.node.name, labels
| limit 10Node Taints Summary
// Summarize all node taints across clusters
smartscapeNodes K8S_NODE
| parse k8s.object, "JSON:config"
| expand taint = config[spec][taints]
| filter isNotNull(taint)
| fieldsAdd taint_key = taint[key], taint_effect = taint[effect]
| summarize node_count = count(), by: {k8s.cluster.name, taint_key, taint_effect}
| sort k8s.cluster.name, node_count descPod Distribution
Pods per Node
// Count pods running on each node
smartscapeNodes K8S_POD
| filter isNotNull(k8s.node.name)
| summarize pod_count = count(), by: {k8s.cluster.name, k8s.node.name}
| sort pod_count descPod Distribution Balance
// Check pod distribution balance across nodes
smartscapeNodes K8S_POD
| filter isNotNull(k8s.node.name)
| summarize pod_count = count(), by: {k8s.cluster.name, k8s.node.name}
| summarize avg_pods = avg(pod_count),
min_pods = min(pod_count),
max_pods = max(pod_count),
by: {k8s.cluster.name}
| fieldsAdd imbalance_ratio = max_pods / avg_pods
| sort imbalance_ratio descInterpretation:
imbalance_rationear 1.0 = well-balancedimbalance_ratio> 2.0 = significant imbalance
Namespace Distribution per Node
// Show namespace distribution across nodes
smartscapeNodes K8S_POD
| filter isNotNull(k8s.node.name)
| summarize pod_count = count(), by: {k8s.cluster.name, k8s.node.name, k8s.namespace.name}
| sort k8s.node.name, pod_count descWorkload Distribution per Node
// Show workload distribution across nodes
smartscapeNodes K8S_POD
| filter isNotNull(k8s.node.name) and isNotNull(k8s.workload.name)
| summarize pod_count = count(), by: {k8s.cluster.name, k8s.node.name, k8s.workload.name}
| sort k8s.node.name, pod_count descPod Placement Constraints
Pods with Node Selectors
// Find pods using node selectors
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| fieldsAdd node_selector = config[spec][nodeSelector]
| filter isNotNull(node_selector)
| fieldsFlatten node_selector, prefix: "selector."
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, node_selectorUse Case: Identify pods with specific node placement requirements (GPU nodes, high-memory nodes, etc.)
Pods with Node Affinity
// Find pods with node affinity rules
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| fieldsAdd node_affinity = config[spec][affinity][nodeAffinity]
| filter isNotNull(node_affinity)
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.namePods with Tolerations
// List pods with tolerations
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| fieldsAdd tolerations = config[spec][tolerations]
| filter isNotNull(tolerations) and arraySize(tolerations) > 0
| expand toleration = tolerations
| fieldsAdd taint_key = toleration[key], taint_effect = toleration[effect]
| fields k8s.pod.name, k8s.node.name, taint_key, taint_effectUse Case: Understand which pods can tolerate node taints (e.g., dedicated nodes, maintenance windows)
Workloads with Anti-Affinity
// Find workloads with pod anti-affinity rules
smartscapeNodes K8S_DEPLOYMENT, K8S_STATEFULSET
| parse k8s.object, "JSON:config"
| fieldsAdd anti_affinity =
config[spec][template][spec][affinity][podAntiAffinity]
| filter isNotNull(anti_affinity)
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.nameUse Case: Identify workloads configured for high availability (spread across nodes/zones)
Node Capacity Analysis
Nodes by Availability Zone
// Group nodes by availability zone
smartscapeNodes K8S_NODE
| parse k8s.object, "JSON:config"
| fieldsAdd zone = config[metadata][labels][`topology.kubernetes.io/zone`]
| filter isNotNull(zone)
| summarize node_count = count(), by: {k8s.cluster.name, zone}
| sort k8s.cluster.name, zoneNodes by Instance Type
// Group nodes by instance type
smartscapeNodes K8S_NODE
| parse k8s.object, "JSON:config"
| fieldsAdd instance_type = config[metadata][labels][`node.kubernetes.io/instance-type`]
| filter isNotNull(instance_type)
| summarize node_count = count(), by: {k8s.cluster.name, instance_type}
| sort k8s.cluster.name, node_count descPod Distribution by Zone
// Analyze pod distribution across availability zones
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| fieldsAdd node_name = config[spec][nodeName]
| lookup [
smartscapeNodes K8S_NODE
| parse k8s.object, "JSON:config"
| fieldsAdd zone = config[metadata][labels][`topology.kubernetes.io/zone`]
| fields k8s.node.name, zone
], sourceField: node_name, lookupField: k8s.node.name
| filter isNotNull(zone)
| summarize pod_count = count(), by: {k8s.cluster.name, zone}
| sort k8s.cluster.name, zoneScheduling Analysis
DaemonSet Coverage
// Verify DaemonSet pods are on all nodes
// Note: Using join instead of lookup because DQL lookup doesn't merge
// aggregated fields from subqueries, causing total_nodes field to be
// inaccessible
smartscapeNodes K8S_POD
| filter k8s.workload.kind == "daemonset"
| summarize nodes_with_daemonset = countDistinct(k8s.node.name),
by: {k8s.cluster.name, k8s.workload.name}
| join [
smartscapeNodes K8S_NODE
| summarize total_nodes = count(), by: {k8s.cluster.name}
], on: {k8s.cluster.name}, fields: {total_nodes}
| fieldsAdd coverage_pct =
100.0 * nodes_with_daemonset / total_nodes
| filter coverage_pct < 100
| fields k8s.cluster.name, k8s.workload.name, nodes_with_daemonset,
total_nodes, coverage_pctUse Case: Detect DaemonSets that aren't running on all nodes (may indicate taint/toleration issues)
Pods Pending Scheduling
// Find pods that are pending (not scheduled to nodes)
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| fieldsAdd phase = config[status][phase]
| filter phase == "Pending" or isNull(k8s.node.name)
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, phaseCommon Causes:
- Insufficient resources
- No nodes match nodeSelector/affinity
- Node taints without matching tolerations
- PVC binding issues
Single-Node Workloads (HA Risk)
// Find workloads with all pods on one node
smartscapeNodes K8S_POD
| filter isNotNull(k8s.workload.name) and isNotNull(k8s.node.name)
| summarize pod_count = count(),
node_count = countDistinct(k8s.node.name),
nodes = collectDistinct(k8s.node.name),
by: {k8s.cluster.name, k8s.namespace.name, k8s.workload.name}
| filter pod_count > 1 and node_count == 1
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name, pod_count, nodesAction: Review these workloads for high availability requirements
High Availability Patterns
Multi-Node Deployment Verification
// Verify deployments are spread across multiple nodes
smartscapeNodes K8S_POD
| filter k8s.workload.kind == "deployment"
| summarize pod_count = count(),
node_count = countDistinct(k8s.node.name),
by: {k8s.cluster.name, k8s.namespace.name, k8s.workload.name}
| fieldsAdd ha_compliant = node_count > 1
| filter pod_count >= 2 and not ha_compliant
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name, pod_count, node_countBest Practice: Deployments with 2+ replicas should span multiple nodes
Zone Distribution for Critical Apps
// Check if critical workloads span multiple zones
smartscapeNodes K8S_POD
| filter tags[criticality] == "high"
| parse k8s.object, "JSON:config"
| fieldsAdd node_name = config[spec][nodeName]
| lookup [
smartscapeNodes K8S_NODE
| parse k8s.object, "JSON:config"
| fieldsAdd zone = config[metadata][labels][`topology.kubernetes.io/zone`]
| fields k8s.node.name, zone
], sourceField: node_name, lookupField: k8s.node.name
| summarize zone_count = countDistinct(zone),
zones = collectDistinct(zone),
by: {k8s.cluster.name, k8s.workload.name}
| fields k8s.cluster.name, k8s.workload.name, zone_count, zonesBest Practice: Critical apps should span 2+ availability zones
StatefulSet Pod Distribution
// Analyze StatefulSet pod placement
smartscapeNodes K8S_POD
| filter k8s.workload.kind == "statefulset"
| summarize pod_count = count(),
node_count = countDistinct(k8s.node.name),
nodes = collectDistinct(k8s.node.name),
by: {k8s.cluster.name, k8s.namespace.name, k8s.workload.name}
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name, pod_count,
node_count, nodesAdvanced Patterns
Node Pressure and Pod Placement
// Correlate node resource pressure with pod count
timeseries {
cpu_usage = sum(dt.kubernetes.container.cpu_usage),
pod_count = avg(dt.kubernetes.pods)
}, by: {k8s.node.name, k8s.cluster.name}
| fieldsAdd avg_cpu = arrayAvg(cpu_usage),
avg_pods = arrayAvg(pod_count)
| filter avg_cpu > 70000000000
| sort avg_cpu descPod Spread by Topology
// Analyze pod spread using topology spread constraints
smartscapeNodes K8S_POD
| parse k8s.object, "JSON:config"
| fieldsAdd spread_constraints = config[spec][topologySpreadConstraints]
| filter isNotNull(spread_constraints) and arraySize(spread_constraints) > 0
| expand constraint = spread_constraints
| fieldsAdd topology_key = constraint[topologyKey],
max_skew = constraint[maxSkew]
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, topology_key, max_skewBest Practices
1. Monitor Balance: Regularly check pod distribution to avoid node hotspots
- Target:
imbalance_ratio< 1.5
2. Verify HA: Ensure critical workloads span multiple nodes and zones
- Production deployments: 2+ nodes, 2+ zones
- StatefulSets: Consider node anti-affinity
3. Track Taints: Monitor node taints to understand scheduling constraints
- Document custom taints and their purpose
- Ensure DaemonSets have appropriate tolerations
4. Check Pending Pods: Regularly query for pending pods to detect scheduling issues
- Set up alerts for pods pending > 5 minutes
- Review nodeSelector/affinity rules
5. Validate DaemonSets: Verify DaemonSet coverage across all applicable nodes
- Expect 100% coverage unless using node selectors
- Check for taint/toleration mismatches
6. Zone Awareness: Use topology spread constraints for critical applications
- Prefer
topologySpreadConstraintsover deprecated
podAntiAffinity
- Target even distribution across zones
Common Issues and Solutions
| Issue | Query to Detect | Solution |
|---|---|---|
| Pod hotspots | Pod Distribution Balance query | Add anti-affinity rules |
| Pending pods | Pods Pending Scheduling query | Check resources/taints |
| Single-zone deployment | Zone Distribution query | Add spread constraints |
| DaemonSet gaps | DaemonSet Coverage query | Add tolerations |
| HA violations | Multi-Node Deployment Verification | Add anti-affinity |
Related Topics
- Cluster Inventory →
cluster-inventory.md- Understand cluster topology - Labels & Annotations →
labels-annotations.md- Use labels for node selection - Node Resources (documentation) - Monitor node capacity and utilization
- Pod Lifecycle (documentation) - Investigate pod failures and restarts
Persistent Volumes and Claims
Contents
- PVC and PV Lifecycle — Phase Reference
- Relationships
- Find Problem PVCs
- K8S_PERSISTENTVOLUME Entity
- StorageClass Distribution
PVC and PV Lifecycle — Phase Reference
PersistentVolumeClaims (PVCs) and PersistentVolumes (PVs) have separate lifecycle phases. Confusing them produces incorrect filters.
PVC phases (K8S_PERSISTENTVOLUMECLAIM):
| Phase | Meaning |
|---|---|
Pending | No matching PV bound yet — storage class or capacity mismatch, or provisioner not ready |
Bound | PVC is linked to a PV and in use |
Lost | The backing PV was deleted while this PVC still exists; pods mounting it will stay in Pending |
PV phases (K8S_PERSISTENTVOLUME):
| Phase | Meaning |
|---|---|
Available | PV exists but no PVC has claimed it |
Bound | PV is linked to a PVC |
Released | The PVC was deleted but the PV was not reclaimed (data still present) |
Failed | Automatic reclaim failed |
ReleasedandFailedare PV phases only. A filter
phase == "Released"onK8S_PERSISTENTVOLUMECLAIMwill never match.
Relationships
K8S_POD --(uses)--> K8S_PERSISTENTVOLUMECLAIM --(uses)--> K8S_PERSISTENTVOLUME
K8S_PERSISTENTVOLUME --(belongs_to)--> K8S_CLUSTERFind Problem PVCs
List PVCs that are Pending or Lost.
smartscapeNodes K8S_PERSISTENTVOLUMECLAIM
| parse k8s.object, "JSON:config"
| fieldsAdd
phase = config[`status`][`phase`],
storage_class = config[`spec`][`storageClassName`],
capacity = config[`status`][`capacity`][`storage`]
| filter in(phase, array("Pending", "Lost"))
| fields k8s.cluster.name, k8s.namespace.name, k8s.pvc.name, phase,
storage_class, capacityLost PVCs block any pod that tries to mount them. Pending PVCs prevent StatefulSet pods from starting (pod-order dependency — see references/workload-health.md).
K8S_PERSISTENTVOLUME Entity
K8S_PERSISTENTVOLUME is cluster-scoped (no namespace). Query it directly when you need cross-cluster storage inventory or to detect leaked volumes — neither is visible from the PVC side alone.
All PVs with phase and capacity (inventory / cost audit):
smartscapeNodes K8S_PERSISTENTVOLUME
| parse k8s.object, "JSON:config"
| fieldsAdd
phase = config[`status`][`phase`],
storage_class = config[`spec`][`storageClassName`],
capacity = config[`spec`][`capacity`][`storage`],
reclaim_policy = config[`spec`][`persistentVolumeReclaimPolicy`]
| fields k8s.cluster.name, entity.name, phase, storage_class, capacity, reclaim_policyReleased PVs — the PVC was deleted but the PV (and its data) still exists. With a Retain reclaim policy this is expected; with Delete it signals a reclaim failure that needs manual cleanup:
smartscapeNodes K8S_PERSISTENTVOLUME
| parse k8s.object, "JSON:config"
| fieldsAdd
phase = config[`status`][`phase`],
reclaim_policy = config[`spec`][`persistentVolumeReclaimPolicy`]
| filter phase == "Released"
| fields k8s.cluster.name, entity.name, phase, reclaim_policyFilter by provisioner — because K8S_STORAGECLASS is not a smartscape entity type, the annotation pv.kubernetes.io/provisioned-by (values like ebs.csi.aws.com, pd.csi.storage.gke.io) is the only way to scope PV queries to a specific CSI driver:
smartscapeNodes K8S_PERSISTENTVOLUME
| parse k8s.object, "JSON:config"
| fieldsAdd
provisioner = config[`metadata`][`annotations`][`pv.kubernetes.io/provisioned-by`],
phase = config[`status`][`phase`],
storage_class = config[`spec`][`storageClassName`],
capacity = config[`spec`][`capacity`][`storage`]
| filter provisioner == "<provisioner>"
| fields k8s.cluster.name, entity.name, provisioner, phase, storage_class, capacityStorageClass Distribution
smartscapeNodes K8S_PERSISTENTVOLUMECLAIM
| parse k8s.object, "JSON:config"
| fieldsAdd storage_class = config[`spec`][`storageClassName`]
| summarize pvc_count = count(), by: {k8s.cluster.name, storage_class}
| sort pvc_count descWorkload Health and Rollout Debugging
Detection patterns for degraded deployments, stuck rollouts, node pressure, CPU throttling, HPA scaling, and StatefulSet ordering.
Contents
- Deployment Replica Health
- Stuck Rollout Detection
- Node Conditions
- CPU Throttling
- HPA Inspection
- StatefulSet
- StatefulSet Pod Order
Deployment Replica Health
A deployment is healthy when status.readyReplicas == spec.replicas. Filter with isNotNull(desired) to guard against false positives when k8s.object is unpopulated.
smartscapeNodes K8S_DEPLOYMENT
| parse k8s.object, "JSON:config"
| fieldsAdd
desired = config[`spec`][`replicas`],
ready = config[`status`][`readyReplicas`],
available = config[`status`][`availableReplicas`],
updated = config[`status`][`updatedReplicas`]
| filter isNotNull(desired) and (isNull(ready) or ready < desired)
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name, desired, ready, availableStuck Rollout Detection
A stuck rollout differs from a simple replica shortage:
- Replica shortage — replicas are missing but the rollout is still
progressing (slow image pull, resource pressure). Will resolve.
- Stuck rollout — Kubernetes gave up after
progressDeadlineSeconds
(default: 10 min). No further progress until intervention. Common causes: bad image tag, quota exhausted, PVC not bound, failing readiness probe.
status.conditions will contain type=Progressing with reason=ProgressDeadlineExceeded:
smartscapeNodes K8S_DEPLOYMENT
| parse k8s.object, "JSON:config"
| expand condition = config[`status`][`conditions`]
| fieldsAdd
cond_type = condition[`type`],
cond_reason = condition[`reason`],
cond_message = condition[`message`]
| filter cond_type == "Progressing" and cond_reason == "ProgressDeadlineExceeded"
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name, cond_messageNode Conditions
Node status.conditions exposes health states that block scheduling or trigger evictions.
| Condition | Unhealthy state | Impact |
|---|---|---|
Ready | False or Unknown | Node not accepting pods; existing pods may be evicted |
MemoryPressure | True | Memory low; evictions likely |
DiskPressure | True | Disk low; image pulls may fail |
PIDPressure | True | Near process limit |
smartscapeNodes K8S_NODE
| parse k8s.object, "JSON:config"
| expand condition = config[`status`][`conditions`]
| fieldsAdd
cond_type = condition[`type`],
cond_status = condition[`status`],
message = condition[`message`]
| filter (cond_type == "Ready" and cond_status != "True")
or (in(cond_type, array("MemoryPressure","DiskPressure","PIDPressure")) and cond_status == "True")
| fields k8s.cluster.name, k8s.node.name, cond_type, cond_status, messageBlast radius — all pods on a failing node:
smartscapeNodes K8S_POD
| filter k8s.node.name == "<failing-node>"
| fields k8s.cluster.name, k8s.namespace.name, k8s.pod.name, k8s.workload.nameCPU Throttling
CPU throttling caps container execution when usage hits the CPU limit. Unlike OOMKills, the container stays running but responds slowly — a common source of latency that appears as application slowness rather than crashes.
timeseries {
throttled = avg(dt.kubernetes.container.cpu_throttled),
limit = avg(dt.kubernetes.container.limits_cpu),
usage = avg(dt.kubernetes.container.cpu_usage)
}, by: {k8s.pod.name, k8s.namespace.name, k8s.cluster.name}
| fieldsAdd throttle_pct = (arrayAvg(throttled) / arrayAvg(limit)) * 100
| filter throttle_pct > 25
| sort throttle_pct descthrottle_pct > 25 means the container is throttled more than 25% of the time it wants to run. Resolution: raise the CPU limit or reduce usage.
HPA Inspection
K8S_HORIZONTALPODAUTOSCALER exposes current, desired, min, and max replicas.
smartscapeNodes K8S_HORIZONTALPODAUTOSCALER
| parse k8s.object, "JSON:config"
| fieldsAdd
min_replicas = config[`spec`][`minReplicas`],
max_replicas = config[`spec`][`maxReplicas`],
current_replicas = config[`status`][`currentReplicas`],
desired_replicas = config[`status`][`desiredReplicas`]
| fields k8s.cluster.name, k8s.namespace.name, k8s.horizontalpodautoscaler.name,
min_replicas, max_replicas, current_replicas, desired_replicasHPAs stuck at max (cannot scale further):
smartscapeNodes K8S_HORIZONTALPODAUTOSCALER
| parse k8s.object, "JSON:config"
| fieldsAdd
max_replicas = config[`spec`][`maxReplicas`],
current_replicas = config[`status`][`currentReplicas`]
| filter current_replicas >= max_replicas
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name,
current_replicas, max_replicasStatefulSet
Retrieve StatefulSet instances
smartscapeNodes K8S_STATEFULSET
| parse k8s.object, "JSON:config"
| sort k8s.statefulset.name asc
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name, k8s.pod.name, configStatefulSet Pod Order
StatefulSets start and stop pods in strict ordinal order (pod-0, pod-1...). Pod N will not start until pod N-1 is Ready. The first pod in non-Running state is the blocker.
smartscapeNodes K8S_POD
| filter k8s.workload.kind == "statefulset"
| parse k8s.object, "JSON:config"
| fieldsAdd phase = config[`status`][`phase`]
| sort k8s.pod.name asc
| fields k8s.cluster.name, k8s.namespace.name, k8s.workload.name, k8s.pod.name, phaseInvestigate the blocking pod using references/pod-debugging.md.
Related skills
How it compares
Use dt-obs-kubernetes for K8s inventory and topology queries in Dynatrace rather than generic application-level tracing skills.
FAQ
What does dt-obs-kubernetes do?
>-
When should I use dt-obs-kubernetes?
>-
What are common prerequisites?
--- name: dt-obs-kubernetes description: >- Kubernetes cluster, pod, node, and workload monitoring.
Is Dt Obs Kubernetes safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.