← Back to DevBytes

Monitoring AKS: Metrics, Alarms, and Dashboards

Monitoring AKS: Metrics, Alarms, and Dashboards

Monitoring Azure Kubernetes Service (AKS) is the continuous process of collecting, analyzing, and acting on performance data, logs, and events from your cluster, its nodes, and the workloads running inside it. Effective monitoring gives you visibility into everything from cluster health and resource saturation down to individual container metrics and application-level signals. Without it, you are flying blind — unable to detect regressions, predict capacity needs, or troubleshoot failures efficiently.

What Makes AKS Monitoring Different

AKS sits at the intersection of infrastructure and platform. You are responsible for the nodes (if not using virtual nodes), the Kubernetes control plane is managed by Azure, and your workloads bring their own observability requirements. A robust monitoring strategy must therefore cover three distinct layers:

Why Monitoring Matters for AKS

Beyond the obvious "know when something breaks," monitoring on AKS drives several critical operational functions:

Core Monitoring Components in Azure

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Azure Monitor and Container Insights

The primary managed offering for AKS observability is Container Insights, built on top of Azure Monitor and Log Analytics. It deploys a DaemonSet called the OMS agent (or the newer Azure Monitor Agent for Linux) on every node, plus a replica pod that collects Kubernetes-specific data via the Kubelet API and Kubernetes API server. Together they ship the following into a Log Analytics workspace:

Enabling Container Insights on an Existing AKS Cluster

You can enable monitoring at cluster creation via the Azure portal, Azure CLI, or ARM/Bicep. For an existing cluster, the CLI approach is the most repeatable:

# Enable Container Insights on an existing AKS cluster
az aks enable-addons \
  --resource-group MyResourceGroup \
  --name MyAKSCluster \
  --addons monitoring \
  --workspace-resource-id "/subscriptions/.../resourceGroups/LogAnalyticsRG/providers/Microsoft.OperationalInsights/workspaces/MyWorkspace"

If you don't already have a Log Analytics workspace, create one first:

az monitor log-analytics workspace create \
  --resource-group LogAnalyticsRG \
  --workspace-name MyWorkspace \
  --location eastus

After a few minutes, the DaemonSet pods appear in the kube-system namespace. Verify they are running:

kubectl get pods -n kube-system -l component=oms-agent
kubectl get pods -n kube-system -l app=omsagent-rs

Querying Metrics and Logs

Kusto Query Language (KQL) Fundamentals

All data collected by Container Insights lands in Log Analytics tables and is queried with KQL. The query language is powerful and worth learning deeply. Here are essential patterns:

Get current CPU usage across nodes, aggregated per node:

Perf
| where ObjectName == "K8s Node"
| where CounterName == "cpuUsageNanoCores"
| summarize AvgCpuNanoCores = avg(CounterValue) by Computer, bin(TimeGenerated, 5m)
| render timechart

Find pods with high memory usage, ranked:

Perf
| where ObjectName == "K8s Container"
| where CounterName == "memoryWorkingSetBytes"
| summarize MaxMemoryBytes = max(CounterValue) by InstanceName, ContainerName, bin(TimeGenerated, 1h)
| order by MaxMemoryBytes desc
| project TimeGenerated, InstanceName, ContainerName, MaxMemoryMB = MaxMemoryBytes / 1048576

Tail container logs for a specific deployment:

ContainerLog
| where ContainerName contains "my-app"
| where TimeGenerated > ago(30m)
| project TimeGenerated, LogEntry, ContainerName
| order by TimeGenerated desc

Check Kubernetes events for warning-level issues:

KubeEvents
| where TimeGenerated > ago(1h)
| where Type == "Warning"
| project TimeGenerated, Namespace, Name, Reason, Message
| order by TimeGenerated desc

InsightsMetrics: Prometheus-Style Metrics Without Scraping

The bundled agent exposes a set of pre-aggregated metrics in the InsightsMetrics table. These come from kube-state-metrics and node-exporter-like collectors and are ideal for dashboards:

InsightsMetrics
| where Namespace == "container"
| where Name == "cpuUsagePercentage"
| summarize AvgCpuPct = avg(Val) by bin(TimeGenerated, 5m), Computer
| render timechart

Commonly used InsightsMetrics names include:

Alarms: Creating and Managing Alerts

Azure Monitor Alert Rules

Alerts in Azure Monitor are created as alert rules that combine a signal (metric or log query), a condition, and an action group. For AKS, you will use two types of signals:

Creating a Metric Alert for Node CPU

This alert fires when the average CPU percentage across all nodes exceeds 85% for 10 minutes:

az monitor metrics alert create \
  --resource-group MyResourceGroup \
  --name "NodeCPUHigh" \
  --scopes "/subscriptions/.../resourceGroups/MC_MyRG_MyAKSCluster_eastus/providers/Microsoft.ContainerService/managedClusters/MyAKSCluster" \
  --condition "avg Percentage CPU > 85" \
  --window-size 10m \
  --evaluation-frequency 1m \
  --description "Alert when average node CPU exceeds 85 percent for 10 minutes" \
  --action-group "/subscriptions/.../resourceGroups/MyResourceGroup/providers/Microsoft.Insights/actionGroups/MyActionGroup"

The scope must point to the actual managed cluster resource (the one in the MC_ resource group), not the AKS resource itself. You can find it with:

az aks show --resource-group MyResourceGroup --name MyAKSCluster --query "id" -o tsv

Creating a Log Search Alert for Pod Restart Spikes

Log alerts let you detect anomalies like a sudden increase in container restarts over a short window:

# First, create the action group if you don't have one
az monitor action-group create \
  --resource-group MyResourceGroup \
  --name MyActionGroup \
  --short-name MyAG \
  --action email myemail@example.com

# Then create the log search alert
az monitor scheduled-query create \
  --resource-group MyResourceGroup \
  --name "PodRestartSpike" \
  --scopes "/subscriptions/.../resourceGroups/LogAnalyticsRG/providers/Microsoft.OperationalInsights/workspaces/MyWorkspace" \
  --query 'InsightsMetrics
| where Namespace == "container"
| where Name == "restartCount"
| summarize TotalRestarts = sum(Val) by bin(TimeGenerated, 5m)
| where TotalRestarts > 10' \
  --window-size 15m \
  --evaluation-frequency 5m \
  --severity 2 \
  --auto-mitigate false \
  --action-groups "/subscriptions/.../resourceGroups/MyResourceGroup/providers/Microsoft.Insights/actionGroups/MyActionGroup"

Action Groups: Where Alerts Go

An action group defines the notification channels and automated responses. You can include:

Alert Processing Rules (Suppression and Filtering)

Once alerts fire, you can apply alert processing rules (formerly action rules) to suppress noise during maintenance windows or route alerts differently based on severity or resource group:

# Suppress all alerts on weekends for a specific cluster
az monitor alert-processing-rule create \
  --resource-group MyResourceGroup \
  --name "WeekendSuppression" \
  --rule-type RemoveActionGroups \
  --scopes "/subscriptions/.../resourceGroups/MC_MyRG_MyAKSCluster_eastus/providers/Microsoft.ContainerService/managedClusters/MyAKSCluster" \
  --schedule-recurrence-type Weekly \
  --schedule-recurrence-days Saturday Sunday \
  --schedule-recurrence-start-time "00:00:00" \
  --schedule-recurrence-end-time "23:59:59" \
  --description "Suppress alerts during weekend maintenance windows"

Dashboards: Visualizing Cluster Health

Azure Workbooks and the Built-In Container Insights Views

Container Insights ships with a set of curated workbooks accessible from the Azure portal under your AKS cluster's Insights blade. These include:

You can customize these or build entirely new workbooks from scratch. Workbooks support KQL queries, rich visualizations (time charts, bar charts, scatter plots, grids), and parameter-driven interactivity.

Building a Custom Workbook for Application SLO Tracking

Below is a KQL snippet you might embed in a workbook to track HTTP 5xx rate for a service, using Application Insights data from instrumented pods:

let threshold = 0.01; // 1% error rate threshold
AppRequests
| where Name startswith "POST /api/"
| summarize TotalRequests = count(), FailedRequests = countif(ResponseCode >= 500) by bin(TimeGenerated, 5m)
| extend ErrorRate = (FailedRequests * 1.0) / TotalRequests
| extend Breached = ErrorRate > threshold
| project TimeGenerated, ErrorRate, TotalRequests, FailedRequests, Breached
| render timechart with (kind=stacked)

Workbooks let you parameterize the time range, namespace, and threshold so operators can interact without editing queries.

Azure Managed Grafana for AKS Dashboards

For teams that prefer Grafana's dashboarding model, Azure offers Azure Managed Grafana (an Azure-native Grafana 10 instance with managed authentication). You connect it to your Azure Monitor data sources — including Log Analytics and Azure Monitor Metrics — and build dashboards with the full Grafana panel library.

To connect Managed Grafana to your Log Analytics workspace:

# Create a Managed Grafana instance
az grafana create \
  --resource-group MyResourceGroup \
  --name MyGrafanaInstance \
  --location eastus

# Grant the Grafana managed identity access to the Log Analytics workspace
az role assignment create \
  --assignee "$(az grafana show --resource-group MyResourceGroup --name MyGrafanaInstance --query "identity.principalId" -o tsv)" \
  --role "Log Analytics Reader" \
  --scope "/subscriptions/.../resourceGroups/LogAnalyticsRG/providers/Microsoft.OperationalInsights/workspaces/MyWorkspace"

Inside Grafana, add an Azure Monitor data source, authenticate with the managed identity, and start creating dashboards that query the same KQL tables you use in the portal. This unifies infrastructure monitoring with application dashboards your team already maintains in Grafana.

Native Kubernetes Dashboards with Metrics Server and kube-prometheus-stack

Many teams also run Prometheus and Grafana directly inside the cluster for sub-minute granularity and custom service monitors. The kube-prometheus-stack Helm chart bundles Prometheus, Alertmanager, and Grafana with a rich set of Kubernetes-focused dashboards:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false

This gives you the classic Grafana dashboards for node-exporter, kube-state-metrics, and the Kubernetes control plane — all running on your cluster. Combine this with Azure Monitor for long-term retention and cross-cluster aggregation.

Best Practices for AKS Monitoring

Example End-to-End Monitoring Deployment

The following Bicep snippet bundles a baseline: Log Analytics workspace, Container Insights enabled on the AKS cluster, a CPU alert, and an action group. Use it as a starting template for production deployments:

// monitoring.bicep - deploy alongside your AKS cluster
param location string = resourceGroup().location
param aksClusterName string
param logAnalyticsWorkspaceName string = 'aks-monitoring-${aksClusterName}'
param alertEmail string

// Log Analytics workspace
resource law 'Microsoft.OperationalInsights/workspaces@2023-09-01' = {
  name: logAnalyticsWorkspaceName
  location: location
  properties: {
    sku: { name: 'PerGB2018' }
    retentionInDays: 31
  }
}

// Enable Container Insights on AKS
resource aksCluster 'Microsoft.ContainerService/managedClusters@2023-08-01' existing = {
  name: aksClusterName
}

resource aksMonitoring 'Microsoft.ContainerService/managedClusters/addonProfiles@2023-08-01' = {
  parent: aksCluster
  name: 'omsagent'
  properties: {
    config: {
      logAnalyticsWorkspaceResourceID: law.id
    }
    enabled: true
  }
}

// Action group for email notifications
resource actionGroup 'Microsoft.Insights/actionGroups@2023-01-01' = {
  name: 'aks-critical-ag'
  location: 'global'
  properties: {
    enabled: true
    groupShortName: 'AKSCrit'
    emailReceivers: [
      {
        name: 'oncall'
        emailAddress: alertEmail
        useCommonAlertSchema: true
      }
    ]
  }
}

// Metric alert on average node CPU > 85% for 10 minutes
resource cpuAlert 'Microsoft.Insights/metricAlerts@2023-01-01' = {
  name: 'node-cpu-high'
  location: 'global'
  properties: {
    description: 'Alert when average node CPU exceeds 85 percent for 10 minutes'
    severity: 2
    enabled: true
    scopes: [aksCluster.id]
    evaluationFrequency: 'PT1M'
    windowSize: 'PT10M'
    criteria: {
      'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria'
      allOf: [
        {
          name: 'Metric1'
          criterionType: 'StaticThresholdCriterion'
          metricName: 'cpuUsagePercentage'
          metricNamespace: 'Microsoft.ContainerService/managedClusters'
          operator: 'GreaterThan'
          threshold: 85
          timeAggregation: 'Average'
          dimensions: []
        }
      ]
    }
    actions: [
      {
        actionGroupId: actionGroup.id
      }
    ]
  }
}

Conclusion

Monitoring AKS effectively means weaving together Azure's native observability stack — Container Insights, Log Analytics, metric alerts, and workbooks — with Kubernetes-native tools like Prometheus and Grafana where sub-minute granularity or custom service monitors are required. Start with the built-in views and a small set of high-signal alerts (node capacity, pod restarts, deployment readiness), then iterate as you learn what normal looks like for your workloads. Treat alert rules as code, test them regularly, and route them to the right people with action groups and processing rules. A well-monitored cluster doesn't just help you sleep better — it directly reduces mean time to detect and recover, keeps your autoscaling honest, and gives you the data you need to make confident capacity and architecture decisions.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles