We have discussed "Deploying Azure Managed Grafana with Terraform" ealier. Now that we have managed grafana available in Azure for the AKS clsuters we can enable managed prometheus. You can setup prometheus on your own in AKS however it is beter to use Azure managed prometheus with AKS as it would leverage the capabilities of Azure monitor and Azure managed grafana to better monitoring and alerting abilities and avoid additional work required to setup full monitoring and observability on your own in an AKS cluster. The offcial documentation is here for leaning more information on the setup.
The expectaion is to have monotring setup with managed prometheus as shown below.
To setup we need below terraform variables setup in local.
locals { kubernetes_version = "1.33.2" subscription_id = "subscription_id" tenant_id = "tenant_id" spn_app_id = "spn_app_id" spn_pwd = "spn_pwd" # replace with your actual service principal password log_dataflow_streams = [ "Microsoft-ContainerLogV2", "Microsoft-KubeEvents", "Microsoft-KubePodInventory", "Microsoft-KubeNodeInventory", "Microsoft-KubePVInventory", "Microsoft-KubeServices", "Microsoft-KubeMonAgentEvents", "Microsoft-InsightsMetrics", "Microsoft-ContainerInventory", "Microsoft-ContainerNodeInventory", "Microsoft-Perf" ] enable_high_log_scale_mode = contains(local.log_dataflow_streams, "Microsoft-ContainerLogV2-HighScale") }
Then we can set aks clsuter with managed prometheus using below terraform code. This is using the managed grafana setup as described in "Deploying Azure Managed Grafana with Terraform". Full code example is available in GitHub here as well. If you have windows nodes as well enable the windows rule groups as well.
terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "=4.38.1" } azuread = { source = "hashicorp/azuread" version = "=3.4.0" } } } provider "azurerm" { features {} subscription_id = local.subscription_id } #region Basic AKS setup # resource group for aks resource "azurerm_resource_group" "aks_rg" { name = "rg-chdemo-dev01" location = "eastus" } # vnet for aks resource "azurerm_virtual_network" "aks_vnet" { name = "vnet_chdemo_dev01" resource_group_name = azurerm_resource_group.aks_rg.name location = azurerm_resource_group.aks_rg.location address_space = ["10.235.0.0/16"] } # subnet for aks resource "azurerm_subnet" "aks_snet" { name = "snet-aks-chdemo-dev01" resource_group_name = azurerm_resource_group.aks_rg.name virtual_network_name = azurerm_virtual_network.aks_vnet.name address_prefixes = ["10.235.128.0/22"] } # refer to my team ad group to assign as aks admins data "azuread_group" "myteam" { display_name = "sub_owners" security_enabled = true } # AKS user assigned identity resource "azurerm_user_assigned_identity" "aks" { location = azurerm_resource_group.aks_rg.location name = "uai-aks-chdemo-dev01" resource_group_name = azurerm_resource_group.aks_rg.name } # Log analytics workspace for AKS and Application Insights resource "azurerm_log_analytics_workspace" "instance_log" { name = "log-chdemo-dev01" location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name retention_in_days = 30 } # acr resource "azurerm_container_registry" "acr" { name = "acrchdemodev01" resource_group_name = azurerm_resource_group.aks_rg.name location = azurerm_resource_group.aks_rg.location sku = "Standard" admin_enabled = false } # aks cluster resource "azurerm_kubernetes_cluster" "aks" { # any autoscaling should not be reset by TF after intial setup lifecycle { ignore_changes = [default_node_pool[0].node_count] } name = "aks-chdemo-dev01" kubernetes_version = local.kubernetes_version location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name dns_prefix = "aks-chdemo-dev01-dns" node_resource_group = "rg-chdemo-aks-dev01" image_cleaner_enabled = false image_cleaner_interval_hours = 48 network_profile { network_plugin = "azure" load_balancer_sku = "standard" network_plugin_mode = "overlay" pod_cidr = "100.112.0.0/12" } storage_profile { file_driver_enabled = true } default_node_pool { name = "chlinux" orchestrator_version = local.kubernetes_version node_count = 1 auto_scaling_enabled = true min_count = 1 max_count = 4 vm_size = "Standard_B4ms" os_sku = "Ubuntu" vnet_subnet_id = azurerm_subnet.aks_snet.id max_pods = 30 type = "VirtualMachineScaleSets" scale_down_mode = "Delete" zones = ["1", "2", "3"] upgrade_settings { drain_timeout_in_minutes = 0 max_surge = "10%" node_soak_duration_in_minutes = 0 } } #region promethus monitor_metrics { annotations_allowed = null labels_allowed = null } #endregion promethus timeouts { update = "180m" delete = "180m" } identity { type = "UserAssigned" identity_ids = [azurerm_user_assigned_identity.aks.id] } key_vault_secrets_provider { secret_rotation_enabled = false } azure_active_directory_role_based_access_control { azure_rbac_enabled = false tenant_id = local.tenant_id # add my team as cluster admin admin_group_object_ids = [ data.azuread_group.myteam.object_id] # azure AD group object ID } oms_agent { log_analytics_workspace_id = azurerm_log_analytics_workspace.instance_log.id msi_auth_for_monitoring_enabled = true } } resource "azurerm_role_assignment" "acr_attach" { principal_id = azurerm_kubernetes_cluster.aks.kubelet_identity[0].object_id role_definition_name = "AcrPull" scope = azurerm_container_registry.acr.id skip_service_principal_aad_check = true depends_on = [ azurerm_kubernetes_cluster.aks, azurerm_container_registry.acr ] } #endregion Basic AKS setup #region Managed Prometheus setup # Refer https://learn.microsoft.com/en-us/azure/azure-monitor/containers/kubernetes-monitoring-enable?tabs=terraform # Azure monitor workspace resource "azurerm_monitor_workspace" "instance_amw" { name = "amw-chdemo-dev01" location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name } # Common data collection endpoint for prometheus and container insights resource "azurerm_monitor_data_collection_endpoint" "dce" { name = substr("MSProm-${azurerm_resource_group.aks_rg.location}-${azurerm_kubernetes_cluster.aks.name}", 0, min(44, length("MSProm-${azurerm_resource_group.aks_rg.location}-${azurerm_kubernetes_cluster.aks.name}"))) resource_group_name = azurerm_resource_group.aks_rg.name location = azurerm_resource_group.aks_rg.location kind = "Linux" depends_on = [ azurerm_kubernetes_cluster.aks ] } # Prometheus data collection rule resource "azurerm_monitor_data_collection_rule" "prometheus_dcr" { name = substr("MSProm-${azurerm_resource_group.aks_rg.location}-${azurerm_kubernetes_cluster.aks.name}", 0, min(64, length("MSProm-${azurerm_resource_group.aks_rg.location}-${azurerm_kubernetes_cluster.aks.name}"))) resource_group_name = azurerm_resource_group.aks_rg.name location = azurerm_resource_group.aks_rg.location data_collection_endpoint_id = azurerm_monitor_data_collection_endpoint.dce.id kind = "Linux" destinations { monitor_account { monitor_account_id = azurerm_monitor_workspace.instance_amw.id name = "MonitoringAccount1" } } data_flow { streams = ["Microsoft-PrometheusMetrics"] destinations = ["MonitoringAccount1"] } data_sources { prometheus_forwarder { streams = ["Microsoft-PrometheusMetrics"] name = "PrometheusDataSource" } } description = "DCR for Azure Monitor Metrics Profile (Managed Prometheus)" depends_on = [ azurerm_monitor_data_collection_endpoint.dce ] } # Prometheus data collection rule association resource "azurerm_monitor_data_collection_rule_association" "prometheus_dcra" { name = "MSProm-${azurerm_resource_group.aks_rg.location}-${azurerm_kubernetes_cluster.aks.name}" target_resource_id = azurerm_kubernetes_cluster.aks.id data_collection_rule_id = azurerm_monitor_data_collection_rule.prometheus_dcr.id description = "Association of data collection rule. Deleting this association will break the data collection for this AKS Cluster." depends_on = [ azurerm_monitor_data_collection_rule.prometheus_dcr ] } # Container Insights data collection rule resource "azurerm_monitor_data_collection_rule" "ci_dcr" { name = "MSCI-${azurerm_resource_group.aks_rg.location}-${azurerm_kubernetes_cluster.aks.name}" resource_group_name = azurerm_resource_group.aks_rg.name location = azurerm_resource_group.aks_rg.location destinations { log_analytics { workspace_resource_id = azurerm_log_analytics_workspace.instance_log.id name = "ciworkspace" } } data_flow { streams = local.log_dataflow_streams destinations = ["ciworkspace"] } data_sources { extension { streams = local.log_dataflow_streams extension_name = "ContainerInsights" extension_json = jsonencode({ "dataCollectionSettings" : { "interval" : "1m", "namespaceFilteringMode" : "Off", "namespaces" : ["kube-system", "gatekeeper-system"] "enableContainerLogV2" : true } }) name = "ContainerInsightsExtension" } } data_collection_endpoint_id = local.enable_high_log_scale_mode ? azurerm_monitor_data_collection_endpoint.dce.id : null description = "DCR for Azure Monitor Container Insights" depends_on = [ azurerm_monitor_data_collection_endpoint.dce ] } # Container Insights data collection rule association resource "azurerm_monitor_data_collection_rule_association" "ci_dcra" { name = "ContainerInsightsExtension" target_resource_id = azurerm_kubernetes_cluster.aks.id data_collection_rule_id = azurerm_monitor_data_collection_rule.ci_dcr.id description = "Association of container insights data collection rule. Deleting this association will break the data collection for this AKS Cluster." depends_on = [ azurerm_monitor_data_collection_rule.ci_dcr ] } # Managed Grafana setup data "azurerm_resource_group" "grafana_rg" { name = "ch-demo-grafana-shared-rg" } data "azurerm_dashboard_grafana" "grafana" { name = "ch-demo-shared-dg-001" resource_group_name = data.azurerm_resource_group.grafana_rg.name } # Managed Grafana integration with Azure Monitor Workspace resource "null_resource" "amw_grafana" { triggers = { amw_id = azurerm_monitor_workspace.instance_amw.id } depends_on = [ azurerm_monitor_workspace.instance_amw, data.azurerm_dashboard_grafana.grafana ] provisioner "local-exec" { command = <<-SHELL az login --service-principal -u ${local.spn_app_id} -p ${local.spn_pwd} --tenant ${local.tenant_id} az extension add --name amg --upgrade --yes az grafana integrations monitor add --monitor-name ${azurerm_monitor_workspace.instance_amw.name} --monitor-resource-group-name ${azurerm_resource_group.aks_rg.name} --monitor-subscription-id ${local.subscription_id} --name ${data.azurerm_dashboard_grafana.grafana.name} --resource-group ${data.azurerm_resource_group.grafana_rg.name} --subscription ${local.subscription_id} SHELL interpreter = ["PowerShell"] } } # Assign "Monitoring Data Reader" role to the Azure monitor workspace for Grafana # https://www.azadvertizer.net/azrolesadvertizer/b0d8363b-8ddd-447d-831f-62ca05bff136.html resource "azurerm_role_assignment" "datareaderrole" { scope = azurerm_monitor_workspace.instance_amw.id role_definition_id = "/subscriptions/${split("/", azurerm_monitor_workspace.instance_amw.id)[2]}/providers/Microsoft.Authorization/roleDefinitions/b0d8363b-8ddd-447d-831f-62ca05bff136" principal_id = data.azurerm_dashboard_grafana.grafana.identity.0.principal_id } # Managed Prometheus recording rules for AKS resource "azurerm_monitor_alert_prometheus_rule_group" "node_recording_rules_rule_group" { name = "NodeRecordingRulesRuleGroup-${azurerm_kubernetes_cluster.aks.name}" location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name cluster_name = azurerm_kubernetes_cluster.aks.name description = "Node Recording Rules Rule Group" rule_group_enabled = true interval = "PT1M" scopes = [azurerm_monitor_workspace.instance_amw.id, azurerm_kubernetes_cluster.aks.id] rule { enabled = true record = "instance:node_num_cpu:sum" expression = <<EOF count without (cpu, mode) ( node_cpu_seconds_total{job="node",mode="idle"}) EOF } rule { enabled = true record = "instance:node_cpu_utilisation:rate5m" expression = <<EOF 1 - avg without (cpu) ( sum without (mode) (rate(node_cpu_seconds_total{job="node", mode=~"idle|iowait|steal"}[5m]))) EOF } rule { enabled = true record = "instance:node_load1_per_cpu:ratio" expression = <<EOF ( node_load1{job="node"}/ instance:node_num_cpu:sum{job="node"}) EOF } rule { enabled = true record = "instance:node_memory_utilisation:ratio" expression = <<EOF 1 - ( ( node_memory_MemAvailable_bytes{job="node"} or ( node_memory_Buffers_bytes{job="node"} + node_memory_Cached_bytes{job="node"} + node_memory_MemFree_bytes{job="node"} + node_memory_Slab_bytes{job="node"} ) )/ node_memory_MemTotal_bytes{job="node"}) EOF } rule { enabled = true record = "instance:node_vmstat_pgmajfault:rate5m" expression = <<EOF rate(node_vmstat_pgmajfault{job="node"}[5m]) EOF } rule { enabled = true record = "instance_device:node_disk_io_time_seconds:rate5m" expression = <<EOF rate(node_disk_io_time_seconds_total{job="node", device!=""}[5m]) EOF } rule { enabled = true record = "instance_device:node_disk_io_time_weighted_seconds:rate5m" expression = <<EOF rate(node_disk_io_time_weighted_seconds_total{job="node", device!=""}[5m]) EOF } rule { enabled = true record = "instance:node_network_receive_bytes_excluding_lo:rate5m" expression = <<EOF sum without (device) ( rate(node_network_receive_bytes_total{job="node", device!="lo"}[5m])) EOF } rule { enabled = true record = "instance:node_network_transmit_bytes_excluding_lo:rate5m" expression = <<EOF sum without (device) ( rate(node_network_transmit_bytes_total{job="node", device!="lo"}[5m])) EOF } rule { enabled = true record = "instance:node_network_receive_drop_excluding_lo:rate5m" expression = <<EOF sum without (device) ( rate(node_network_receive_drop_total{job="node", device!="lo"}[5m])) EOF } rule { enabled = true record = "instance:node_network_transmit_drop_excluding_lo:rate5m" expression = <<EOF sum without (device) ( rate(node_network_transmit_drop_total{job="node", device!="lo"}[5m])) EOF } depends_on = [ azurerm_monitor_workspace.instance_amw, azurerm_kubernetes_cluster.aks, azurerm_monitor_data_collection_endpoint.dce, azurerm_monitor_data_collection_rule.prometheus_dcr, azurerm_monitor_data_collection_rule_association.prometheus_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "kubernetes_recording_rules_rule_group" { name = "KubernetesRecordingRulesRuleGroup-${azurerm_kubernetes_cluster.aks.name}" location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name cluster_name = azurerm_kubernetes_cluster.aks.name description = "Kubernetes Recording Rules Rule Group" rule_group_enabled = true interval = "PT1M" scopes = [azurerm_monitor_workspace.instance_amw.id, azurerm_kubernetes_cluster.aks.id] rule { enabled = true record = "node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate" expression = <<EOF sum by (cluster, namespace, pod, container) ( irate(container_cpu_usage_seconds_total{job="cadvisor", image!=""}[5m])) * on (cluster, namespace, pod) group_left(node) topk by (cluster, namespace, pod) ( 1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "node_namespace_pod_container:container_memory_working_set_bytes" expression = <<EOF container_memory_working_set_bytes{job="cadvisor", image!=""}* on (namespace, pod) group_left(node) topk by(namespace, pod) (1, max by(namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "node_namespace_pod_container:container_memory_rss" expression = <<EOF container_memory_rss{job="cadvisor", image!=""}* on (namespace, pod) group_left(node) topk by(namespace, pod) (1, max by(namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "node_namespace_pod_container:container_memory_cache" expression = <<EOF container_memory_cache{job="cadvisor", image!=""}* on (namespace, pod) group_left(node) topk by(namespace, pod) (1, max by(namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "node_namespace_pod_container:container_memory_swap" expression = <<EOF container_memory_swap{job="cadvisor", image!=""}* on (namespace, pod) group_left(node) topk by(namespace, pod) (1, max by(namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "cluster:namespace:pod_memory:active:kube_pod_container_resource_requests" expression = <<EOF kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"} * on (namespace, pod, cluster)group_left() max by (namespace, pod, cluster) ( (kube_pod_status_phase{phase=~"Pending|Running"} == 1)) EOF } rule { enabled = true record = "namespace_memory:kube_pod_container_resource_requests:sum" expression = <<EOF sum by (namespace, cluster) ( sum by (namespace, pod, cluster) ( max by (namespace, pod, container, cluster) ( kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"} ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( kube_pod_status_phase{phase=~"Pending|Running"} == 1 ) )) EOF } rule { enabled = true record = "cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests" expression = <<EOF kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"} * on (namespace, pod, cluster)group_left() max by (namespace, pod, cluster) ( (kube_pod_status_phase{phase=~"Pending|Running"} == 1)) EOF } rule { enabled = true record = "namespace_cpu:kube_pod_container_resource_requests:sum" expression = <<EOF sum by (namespace, cluster) ( sum by (namespace, pod, cluster) ( max by (namespace, pod, container, cluster) ( kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"} ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( kube_pod_status_phase{phase=~"Pending|Running"} == 1 ) )) EOF } rule { enabled = true record = "cluster:namespace:pod_memory:active:kube_pod_container_resource_limits" expression = <<EOF kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} * on (namespace, pod, cluster)group_left() max by (namespace, pod, cluster) ( (kube_pod_status_phase{phase=~"Pending|Running"} == 1)) EOF } rule { enabled = true record = "namespace_memory:kube_pod_container_resource_limits:sum" expression = <<EOF sum by (namespace, cluster) ( sum by (namespace, pod, cluster) ( max by (namespace, pod, container, cluster) ( kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( kube_pod_status_phase{phase=~"Pending|Running"} == 1 ) )) EOF } rule { enabled = true record = "cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits" expression = <<EOF kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} * on (namespace, pod, cluster)group_left() max by (namespace, pod, cluster) ( (kube_pod_status_phase{phase=~"Pending|Running"} == 1) ) EOF } rule { enabled = true record = "namespace_cpu:kube_pod_container_resource_limits:sum" expression = <<EOF sum by (namespace, cluster) ( sum by (namespace, pod, cluster) ( max by (namespace, pod, container, cluster) ( kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( kube_pod_status_phase{phase=~"Pending|Running"} == 1 ) )) EOF } rule { enabled = true record = "namespace_workload_pod:kube_pod_owner:relabel" expression = <<EOF max by (cluster, namespace, workload, pod) ( label_replace( label_replace( kube_pod_owner{job="kube-state-metrics", owner_kind="ReplicaSet"}, "replicaset", "$1", "owner_name", "(.*)" ) * on(replicaset, namespace) group_left(owner_name) topk by(replicaset, namespace) ( 1, max by (replicaset, namespace, owner_name) ( kube_replicaset_owner{job="kube-state-metrics"} ) ), "workload", "$1", "owner_name", "(.*)" )) EOF labels = { workload_type = "deployment" } } rule { enabled = true record = "namespace_workload_pod:kube_pod_owner:relabel" expression = <<EOF max by (cluster, namespace, workload, pod) ( label_replace( kube_pod_owner{job="kube-state-metrics", owner_kind="DaemonSet"}, "workload", "$1", "owner_name", "(.*)" )) EOF labels = { workload_type = "daemonset" } } rule { enabled = true record = "namespace_workload_pod:kube_pod_owner:relabel" expression = <<EOF max by (cluster, namespace, workload, pod) ( label_replace( kube_pod_owner{job="kube-state-metrics", owner_kind="StatefulSet"}, "workload", "$1", "owner_name", "(.*)" )) EOF labels = { workload_type = "statefulset" } } rule { enabled = true record = "namespace_workload_pod:kube_pod_owner:relabel" expression = <<EOF max by (cluster, namespace, workload, pod) ( label_replace( kube_pod_owner{job="kube-state-metrics", owner_kind="Job"}, "workload", "$1", "owner_name", "(.*)" )) EOF labels = { workload_type = "job" } } rule { enabled = true record = ":node_memory_MemAvailable_bytes:sum" expression = <<EOF sum( node_memory_MemAvailable_bytes{job="node"} or ( node_memory_Buffers_bytes{job="node"} + node_memory_Cached_bytes{job="node"} + node_memory_MemFree_bytes{job="node"} + node_memory_Slab_bytes{job="node"} )) by (cluster) EOF } rule { enabled = true record = "cluster:node_cpu:ratio_rate5m" expression = <<EOF sum(rate(node_cpu_seconds_total{job="node",mode!="idle",mode!="iowait",mode!="steal"}[5m])) by (cluster) /count(sum(node_cpu_seconds_total{job="node"}) by (cluster, instance, cpu)) by (cluster) EOF } depends_on = [ azurerm_monitor_workspace.instance_amw, azurerm_kubernetes_cluster.aks, azurerm_monitor_data_collection_endpoint.dce, azurerm_monitor_data_collection_rule.prometheus_dcr, azurerm_monitor_data_collection_rule_association.prometheus_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "node_and_kubernetes_recording_rules_rule_group_win" { name = "NodeAndKubernetesRecordingRulesRuleGroup-Win-${azurerm_kubernetes_cluster.aks.name}" location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name cluster_name = azurerm_kubernetes_cluster.aks.name description = "Node and Kubernetes Recording Rules Rule Group for Windows Nodes" rule_group_enabled = false # set as true if windows nodes need this rule interval = "PT1M" scopes = [azurerm_monitor_workspace.instance_amw.id, azurerm_kubernetes_cluster.aks.id] rule { enabled = true record = "node:windows_node_filesystem_usage:" expression = <<EOF max by (instance,volume)((windows_logical_disk_size_bytes{job="windows-exporter"} - windows_logical_disk_free_bytes{job="windows-exporter"}) / windows_logical_disk_size_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_filesystem_avail:" expression = <<EOF max by (instance, volume) (windows_logical_disk_free_bytes{job="windows-exporter"} / windows_logical_disk_size_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = ":windows_node_net_utilisation:sum_irate" expression = <<EOF sum(irate(windows_net_bytes_total{job="windows-exporter"}[5m])) EOF } rule { enabled = true record = "node:windows_node_net_utilisation:sum_irate" expression = <<EOF sum by (instance) ((irate(windows_net_bytes_total{job="windows-exporter"}[5m]))) EOF } rule { enabled = true record = ":windows_node_net_saturation:sum_irate" expression = <<EOF sum(irate(windows_net_packets_received_discarded_total{job="windows-exporter"}[5m])) + sum(irate(windows_net_packets_outbound_discarded_total{job="windows-exporter"}[5m])) EOF } rule { enabled = true record = "node:windows_node_net_saturation:sum_irate" expression = <<EOF sum by (instance) ((irate(windows_net_packets_received_discarded_total{job="windows-exporter"}[5m]) + irate(windows_net_packets_outbound_discarded_total{job="windows-exporter"}[5m]))) EOF } rule { enabled = true record = "windows_pod_container_available" expression = <<EOF windows_container_available{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_total_runtime" expression = <<EOF windows_container_cpu_usage_seconds_total{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_memory_usage" expression = <<EOF windows_container_memory_usage_commit_bytes{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_private_working_set_usage" expression = <<EOF windows_container_memory_usage_private_working_set_bytes{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_network_received_bytes_total" expression = <<EOF windows_container_network_receive_bytes_total{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_network_transmitted_bytes_total" expression = <<EOF windows_container_network_transmit_bytes_total{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "kube_pod_windows_container_resource_memory_request" expression = <<EOF max by (namespace, pod, container) (kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"}) * on(container,pod,namespace) (windows_pod_container_available) EOF } rule { enabled = true record = "kube_pod_windows_container_resource_memory_limit" expression = <<EOF kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} * on(container,pod,namespace) (windows_pod_container_available) EOF } rule { enabled = true record = "kube_pod_windows_container_resource_cpu_cores_request" expression = <<EOF max by (namespace, pod, container) ( kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"}) * on(container,pod,namespace) (windows_pod_container_available) EOF } rule { enabled = true record = "kube_pod_windows_container_resource_cpu_cores_limit" expression = <<EOF kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} * on(container,pod,namespace) (windows_pod_container_available) EOF } rule { enabled = true record = "namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate" expression = <<EOF sum by (namespace, pod, container) (rate(windows_container_total_runtime{}[5m])) EOF } depends_on = [ azurerm_monitor_workspace.instance_amw, azurerm_kubernetes_cluster.aks, azurerm_monitor_data_collection_endpoint.dce, azurerm_monitor_data_collection_rule.prometheus_dcr, azurerm_monitor_data_collection_rule_association.prometheus_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "node_recording_rules_rule_group_win" { name = "NodeRecordingRulesRuleGroup-Win-${azurerm_kubernetes_cluster.aks.name}" location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name cluster_name = azurerm_kubernetes_cluster.aks.name description = "Node and Kubernetes Recording Rules Rule Group for Windows Nodes" rule_group_enabled = false # set as true if windows nodes need this rule interval = "PT1M" scopes = [azurerm_monitor_workspace.instance_amw.id, azurerm_kubernetes_cluster.aks.id] rule { enabled = true record = "node:windows_node:sum" expression = <<EOF count (windows_system_boot_time_timestamp_seconds{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_num_cpu:sum" expression = <<EOF count by (instance) (sum by (instance, core) (windows_cpu_time_total{job="windows-exporter"})) EOF } rule { enabled = true record = ":windows_node_cpu_utilisation:avg5m" expression = <<EOF 1 - avg(rate(windows_cpu_time_total{job="windows-exporter",mode="idle"}[5m])) EOF } rule { enabled = true record = "node:windows_node_cpu_utilisation:avg5m" expression = <<EOF 1 - avg by (instance) (rate(windows_cpu_time_total{job="windows-exporter",mode="idle"}[5m])) EOF } rule { enabled = true record = ":windows_node_memory_utilisation:" expression = <<EOF 1 -sum(windows_memory_available_bytes{job="windows-exporter"})/sum(windows_os_visible_memory_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = ":windows_node_memory_MemFreeCached_bytes:sum" expression = <<EOF sum(windows_memory_available_bytes{job="windows-exporter"} + windows_memory_cache_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_memory_totalCached_bytes:sum" expression = <<EOF (windows_memory_cache_bytes{job="windows-exporter"} + windows_memory_modified_page_list_bytes{job="windows-exporter"} + windows_memory_standby_cache_core_bytes{job="windows-exporter"} + windows_memory_standby_cache_normal_priority_bytes{job="windows-exporter"} + windows_memory_standby_cache_reserve_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = ":windows_node_memory_MemTotal_bytes:sum" expression = <<EOF sum(windows_os_visible_memory_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_memory_bytes_available:sum" expression = <<EOF sum by (instance) ((windows_memory_available_bytes{job="windows-exporter"})) EOF } rule { enabled = true record = "node:windows_node_memory_bytes_total:sum" expression = <<EOF sum by (instance) (windows_os_visible_memory_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_memory_utilisation:ratio" expression = <<EOF (node:windows_node_memory_bytes_total:sum - node:windows_node_memory_bytes_available:sum) / scalar(sum(node:windows_node_memory_bytes_total:sum)) EOF } rule { enabled = true record = "node:windows_node_memory_utilisation:" expression = <<EOF 1 - (node:windows_node_memory_bytes_available:sum / node:windows_node_memory_bytes_total:sum) EOF } rule { enabled = true record = "node:windows_node_memory_swap_io_pages:irate" expression = <<EOF irate(windows_memory_swap_page_operations_total{job="windows-exporter"}[5m]) EOF } rule { enabled = true record = ":windows_node_disk_utilisation:avg_irate" expression = <<EOF avg(irate(windows_logical_disk_read_seconds_total{job="windows-exporter"}[5m]) + irate(windows_logical_disk_write_seconds_total{job="windows-exporter"}[5m])) EOF } rule { enabled = true record = "node:windows_node_disk_utilisation:avg_irate" expression = <<EOF avg by (instance) ((irate(windows_logical_disk_read_seconds_total{job="windows-exporter"}[5m]) + irate(windows_logical_disk_write_seconds_total{job="windows-exporter"}[5m]))) EOF } depends_on = [ azurerm_monitor_workspace.instance_amw, azurerm_kubernetes_cluster.aks, azurerm_monitor_data_collection_endpoint.dce, azurerm_monitor_data_collection_rule.prometheus_dcr, azurerm_monitor_data_collection_rule_association.prometheus_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "ux_recording_rules_rule_group" { name = "UXRecordingRulesRuleGroup - ${azurerm_kubernetes_cluster.aks.name}" location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name cluster_name = azurerm_kubernetes_cluster.aks.name description = "UX recording rules for Linux" rule_group_enabled = true interval = "PT1M" scopes = [azurerm_monitor_workspace.instance_amw.id, azurerm_kubernetes_cluster.aks.id] rule { enabled = true record = "ux:pod_cpu_usage:sum_irate" expression = <<EOF (sum by (namespace, pod, cluster, microsoft_resourceid) ( irate(container_cpu_usage_seconds_total{container != "", pod != "", job = "cadvisor"}[5m]) )) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) (max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) (kube_pod_info{pod != "", job = "kube-state-metrics"})) EOF } rule { enabled = true record = "ux:controller_cpu_usage:sum_irate" expression = <<EOF sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) ( ux:pod_cpu_usage:sum_irate ) EOF } rule { enabled = true record = "ux:pod_workingset_memory:sum" expression = <<EOF ( sum by (namespace, pod, cluster, microsoft_resourceid) ( container_memory_working_set_bytes{container != "", pod != "", job = "cadvisor"} ) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) (max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) (kube_pod_info{pod != "", job = "kube-state-metrics"})) EOF } rule { enabled = true record = "ux:controller_workingset_memory:sum" expression = <<EOF sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) ( ux:pod_workingset_memory:sum ) EOF } rule { enabled = true record = "ux:pod_rss_memory:sum" expression = <<EOF ( sum by (namespace, pod, cluster, microsoft_resourceid) ( container_memory_rss{container != "", pod != "", job = "cadvisor"} ) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) (max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) (kube_pod_info{pod != "", job = "kube-state-metrics"})) EOF } rule { enabled = true record = "ux:controller_rss_memory:sum" expression = <<EOF sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) ( ux:pod_rss_memory:sum ) EOF } rule { enabled = true record = "ux:pod_container_count:sum" expression = <<EOF sum by (node, created_by_name, created_by_kind, namespace, cluster, pod, microsoft_resourceid) ( (( sum by (container, pod, namespace, cluster, microsoft_resourceid) (kube_pod_container_info{container != "", pod != "", container_id != "", job = "kube-state-metrics"}) or sum by (container, pod, namespace, cluster, microsoft_resourceid) (kube_pod_init_container_info{container != "", pod != "", container_id != "", job = "kube-state-metrics"}) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{pod != "", job = "kube-state-metrics"} ) ) ) ) EOF } rule { enabled = true record = "ux:controller_container_count:sum" expression = <<EOF sum by (node, created_by_name, created_by_kind, namespace, cluster, microsoft_resourceid) ( ux:pod_container_count:sum ) EOF } rule { enabled = true record = "ux:pod_container_restarts:max" expression = <<EOF max by (node, created_by_name, created_by_kind, namespace, cluster, pod, microsoft_resourceid) ( (( max by (container, pod, namespace, cluster, microsoft_resourceid) (kube_pod_container_status_restarts_total{container != "", pod != "", job = "kube-state-metrics"}) or sum by (container, pod, namespace, cluster, microsoft_resourceid) (kube_pod_init_status_restarts_total{container != "", pod != "", job = "kube-state-metrics"}) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{pod != "", job = "kube-state-metrics"} ) ) ) ) EOF } rule { enabled = true record = "ux:controller_container_restarts:max" expression = <<EOF max by (node, created_by_name, created_by_kind, namespace, cluster, microsoft_resourceid) ( ux:pod_container_restarts:max ) EOF } rule { enabled = true record = "ux:pod_resource_limit:sum" expression = <<EOF (sum by (cluster, pod, namespace, resource, microsoft_resourceid) ( ( max by (cluster, microsoft_resourceid, pod, container, namespace, resource) (kube_pod_container_resource_limits{container != "", pod != "", job = "kube-state-metrics"}) ) )unless (count by (pod, namespace, cluster, resource, microsoft_resourceid) (kube_pod_container_resource_limits{container != "", pod != "", job = "kube-state-metrics"}) != on (pod, namespace, cluster, microsoft_resourceid) group_left() sum by (pod, namespace, cluster, microsoft_resourceid) (kube_pod_container_info{container != "", pod != "", job = "kube-state-metrics"}) ) )* on (namespace, pod, cluster, microsoft_resourceid) group_left (node, created_by_kind, created_by_name) ( kube_pod_info{pod != "", job = "kube-state-metrics"} ) EOF } rule { enabled = true record = "ux:controller_resource_limit:sum" expression = <<EOF sum by (cluster, namespace, created_by_name, created_by_kind, node, resource, microsoft_resourceid) ( ux:pod_resource_limit:sum ) EOF } rule { enabled = true record = "ux:controller_pod_phase_count:sum" expression = <<EOF sum by (cluster, phase, node, created_by_kind, created_by_name, namespace, microsoft_resourceid) ( ( (kube_pod_status_phase{job="kube-state-metrics",pod!=""}) or (label_replace((count(kube_pod_deletion_timestamp{job="kube-state-metrics",pod!=""}) by (namespace, pod, cluster, microsoft_resourceid) * count(kube_pod_status_reason{reason="NodeLost", job="kube-state-metrics"} == 0) by (namespace, pod, cluster, microsoft_resourceid)), "phase", "terminating", "", ""))) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{job="kube-state-metrics",pod!=""} ) ) ) EOF } rule { enabled = true record = "ux:cluster_pod_phase_count:sum" expression = <<EOF sum by (cluster, phase, node, namespace, microsoft_resourceid) ( ux:controller_pod_phase_count:sum ) EOF } rule { enabled = true record = "ux:node_cpu_usage:sum_irate" expression = <<EOF sum by (instance, cluster, microsoft_resourceid) ( (1 - irate(node_cpu_seconds_total{job="node", mode="idle"}[5m])) ) EOF } rule { enabled = true record = "ux:node_memory_usage:sum" expression = <<EOF sum by (instance, cluster, microsoft_resourceid) (( node_memory_MemTotal_bytes{job = "node"} - node_memory_MemFree_bytes{job = "node"} - node_memory_cached_bytes{job = "node"} - node_memory_buffers_bytes{job = "node"} )) EOF } rule { enabled = true record = "ux:node_network_receive_drop_total:sum_irate" expression = <<EOF sum by (instance, cluster, microsoft_resourceid) (irate(node_network_receive_drop_total{job="node", device!="lo"}[5m])) EOF } rule { enabled = true record = "ux:node_network_transmit_drop_total:sum_irate" expression = <<EOF sum by (instance, cluster, microsoft_resourceid) (irate(node_network_transmit_drop_total{job="node", device!="lo"}[5m])) EOF } depends_on = [ azurerm_monitor_workspace.instance_amw, azurerm_kubernetes_cluster.aks, azurerm_monitor_data_collection_endpoint.dce, azurerm_monitor_data_collection_rule.prometheus_dcr, azurerm_monitor_data_collection_rule_association.prometheus_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "ux_recording_rules_rule_group_windows" { name = "UXRecordingRulesRuleGroup-Win - ${azurerm_kubernetes_cluster.aks.name}" location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name cluster_name = azurerm_kubernetes_cluster.aks.name description = "UX recording rules for Windows" rule_group_enabled = false # set as true if windows nodes need this rule interval = "PT1M" scopes = [ azurerm_monitor_workspace.instance_amw.id, azurerm_kubernetes_cluster.aks.id ] rule { enabled = true record = "ux:pod_cpu_usage_windows:sum_irate" expression = <<EOF sum by (cluster, pod, namespace, node, created_by_kind, created_by_name, microsoft_resourceid) ( ( max by (instance, container_id, cluster, microsoft_resourceid) ( irate(windows_container_cpu_usage_seconds_total{ container_id != "", job = "windows-exporter"}[5m]) ) * on (container_id, cluster, microsoft_resourceid) group_left (container, pod, namespace) ( max by (container, container_id, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_container_info{container != "", pod != "", container_id != "", job = "kube-state-metrics"} ) ) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{ pod != "", job = "kube-state-metrics"} ) ) ) EOF } rule { enabled = true record = "ux:controller_cpu_usage_windows:sum_irate" expression = "sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) (ux:pod_cpu_usage_windows:sum_irate)" } rule { enabled = true record = "ux:pod_workingset_memory_windows:sum" expression = <<EOF sum by (cluster, pod, namespace, node, created_by_kind, created_by_name, microsoft_resourceid) ( ( max by (instance, container_id, cluster, microsoft_resourceid) ( windows_container_memory_usage_private_working_set_bytes{ container_id != "", job = "windows-exporter"} ) * on (container_id, cluster, microsoft_resourceid) group_left (container, pod, namespace) ( max by (container, container_id, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_container_info{container != "", pod != "", container_id != "", job = "kube-state-metrics"} ) ) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{ pod != "", job = "kube-state-metrics"} ) ) ) EOF } rule { enabled = true record = "ux:controller_workingset_memory_windows:sum" expression = "sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) (ux:pod_workingset_memory_windows:sum)" } rule { enabled = true record = "ux:node_cpu_usage_windows:sum_irate" expression = "sum by (instance, cluster, microsoft_resourceid) ((1 - irate(windows_cpu_time_total{job=\"windows-exporter\", mode=\"idle\"}[5m])))" } rule { enabled = true record = "ux:node_memory_usage_windows:sum" expression = "sum by (instance, cluster, microsoft_resourceid) ((windows_os_visible_memory_bytes{job = \"windows-exporter\"}- windows_memory_available_bytes{job = \"windows-exporter\"}))" } rule { enabled = true record = "ux:node_network_packets_received_drop_total_windows:sum_irate" expression = "sum by (instance, cluster, microsoft_resourceid) (irate(windows_net_packets_received_discarded_total{job=\"windows-exporter\", device!=\"lo\"}[5m]))" } rule { enabled = true record = "ux:node_network_packets_outbound_drop_total_windows:sum_irate" expression = "sum by (instance, cluster, microsoft_resourceid) (irate(windows_net_packets_outbound_discarded_total{job=\"windows-exporter\", device!=\"lo\"}[5m]))" } depends_on = [ azurerm_monitor_workspace.instance_amw, azurerm_kubernetes_cluster.aks, azurerm_monitor_data_collection_endpoint.dce, azurerm_monitor_data_collection_rule.prometheus_dcr, azurerm_monitor_data_collection_rule_association.prometheus_dcra ] } #endregion Managed Prometheus setup
You can further enhance it to use shared Azure monitor workspace with multiple AKS clsuters say you have blue green deployments and want to monitor blue and green AKS clsuters when they are available.
So you can have comon montroing workspace, data collection endpoint and rules setup as below.
# Refer https://learn.microsoft.com/en-us/azure/azure-monitor/containers/kubernetes-monitoring-enable?tabs=terraform # Azure monitor workspace resource "azurerm_monitor_workspace" "instance_amw" { name = "${var.PREFIX}-${var.PROJECT}-${var.ENVNAME}-amw" location = azurerm_resource_group.instancerg.location resource_group_name = azurerm_resource_group.instancerg.name tags = merge(tomap({ Service = "monitoring workspace" }), local.tags) } # Common data collection endpoint for prometheus and container insights resource "azurerm_monitor_data_collection_endpoint" "dce" { name = "${var.PREFIX}-${var.PROJECT}-${var.ENVNAME}-dce" resource_group_name = azurerm_resource_group.instancerg.name location = azurerm_resource_group.instancerg.location tags = merge(tomap({ Service = "monitoring data collection endpoint" }), local.tags) } # Prometheus data collection rule # Refer https://github.com/Azure/prometheus-collector/blob/main/AddonTerraformTemplate/main.tf resource "azurerm_monitor_data_collection_rule" "prometheus_dcr" { name = "${var.PREFIX}-${var.PROJECT}-${var.ENVNAME}-prometheus-dcr" resource_group_name = azurerm_resource_group.instancerg.name location = azurerm_resource_group.instancerg.location data_collection_endpoint_id = azurerm_monitor_data_collection_endpoint.dce.id destinations { monitor_account { monitor_account_id = azurerm_monitor_workspace.instance_amw.id name = "MonitoringAccount1" } } data_flow { streams = ["Microsoft-PrometheusMetrics"] destinations = ["MonitoringAccount1"] } data_sources { prometheus_forwarder { streams = ["Microsoft-PrometheusMetrics"] name = "PrometheusDataSource" } } description = "DCR for Azure Monitor Metrics Profile (Managed Prometheus)" tags = merge(tomap({ Service = "monitoring AKS prometheus data collection rule" }), local.tags) depends_on = [ azurerm_monitor_data_collection_endpoint.dce ] } # Container Insights data collection rule # Refer https://learn.microsoft.com/en-us/azure/azure-monitor/containers/kubernetes-monitoring-enable?tabs=terraform#new-aks-cluster resource "azurerm_monitor_data_collection_rule" "ci_dcr" { name = "${var.PREFIX}-${var.PROJECT}-${var.ENVNAME}-ci-dcr" resource_group_name = azurerm_resource_group.instancerg.name location = azurerm_resource_group.instancerg.location destinations { log_analytics { workspace_resource_id = azurerm_log_analytics_workspace.instance_log.id name = "ciworkspace" } } data_flow { streams = local.log_dataflow_streams destinations = ["ciworkspace"] } data_sources { extension { streams = local.log_dataflow_streams extension_name = "ContainerInsights" extension_json = jsonencode({ "dataCollectionSettings" : { "interval" : "1m", "namespaceFilteringMode" : "Off", "namespaces" : ["kube-system", "gatekeeper-system"] "enableContainerLogV2" : true } }) name = "ContainerInsightsExtension" } } data_collection_endpoint_id = local.enable_high_log_scale_mode ? azurerm_monitor_data_collection_endpoint.dce.id : null description = "DCR for Azure Monitor Container Insights" tags = merge(tomap({ Service = "monitoring AKS container insights data collection rule" }), local.tags) depends_on = [ azurerm_monitor_data_collection_endpoint.dce ] } # Managed Grafana setup data "azurerm_resource_group" "grafana_rg" { provider = azurerm.mgmt name = "ch-demo-grafana-shared-rg" } data "azurerm_dashboard_grafana" "grafana" { provider = azurerm.mgmt name = "ch-demo-shared-dg-001" resource_group_name = data.azurerm_resource_group.grafana_rg.name } # Managed Grafana integration with Azure Monitor Workspace resource "null_resource" "amw_grafana" { triggers = { amw_id = azurerm_monitor_workspace.instance_amw.id } depends_on = [ azurerm_monitor_workspace.instance_amw, data.azurerm_dashboard_grafana.grafana ] provisioner "local-exec" { command = <<-SHELL az login --service-principal -u ${var.DEVOPSSERVICECONNECTIONAID} -p ${var.DEVOPSSERVICECONNECTIONPW} --tenant ${var.TENANTID} az extension add --name amg --upgrade --yes az grafana integrations monitor add --monitor-name ${azurerm_monitor_workspace.instance_amw.name} --monitor-resource-group-name ${azurerm_resource_group.instancerg.name} --monitor-subscription-id ${var.SUBSCRIPTIONID} --name ${data.azurerm_dashboard_grafana.grafana.name} --resource-group ${data.azurerm_resource_group.grafana_rg.name} --subscription ${var.MANAGEMENTSUBSCRIPTIONID} SHELL interpreter = ["PowerShell"] } } # Assign "Monitoring Data Reader" role to the Azure monitor workspace for Grafana # https://www.azadvertizer.net/azrolesadvertizer/b0d8363b-8ddd-447d-831f-62ca05bff136.html resource "azurerm_role_assignment" "datareaderrole" { scope = azurerm_monitor_workspace.instance_amw.id role_definition_id = "/subscriptions/${var.SUBSCRIPTIONID}/providers/Microsoft.Authorization/roleDefinitions/b0d8363b-8ddd-447d-831f-62ca05bff136" principal_id = data.azurerm_dashboard_grafana.grafana.identity.0.principal_id }
Then in the AKS module you can setup associations and rules for individual AKS instance as shown below.
# Prometheus data collection rule association resource "azurerm_monitor_data_collection_rule_association" "prometheus_dcra" { name = "${azurerm_kubernetes_cluster.aks_cluster.name}-prometheus-dcra" target_resource_id = azurerm_kubernetes_cluster.aks_cluster.id data_collection_rule_id = var.prometheus_dcr_id description = "Association of data collection rule. Deleting this association will break the data collection for this AKS Cluster ${var.deployment_name}." depends_on = [ azurerm_kubernetes_cluster.aks_cluster, azurerm_kubernetes_cluster_node_pool.windows_pool ] } # Container Insights data collection rule association resource "azurerm_monitor_data_collection_rule_association" "ci_dcra" { name = "${azurerm_kubernetes_cluster.aks_cluster.name}-ci-dcra" target_resource_id = azurerm_kubernetes_cluster.aks_cluster.id data_collection_rule_id = var.container_insights_dcr_id description = "Association of container insights data collection rule. Deleting this association will break the data collection for this AKS Cluster ${var.deployment_name}." depends_on = [ azurerm_kubernetes_cluster.aks_cluster, azurerm_kubernetes_cluster_node_pool.windows_pool ] } #region Managed Prometheus recording rules for AKS # Refer https://github.com/Azure/prometheus-collector/blob/main/AddonTerraformTemplate/main.tf resource "azurerm_monitor_alert_prometheus_rule_group" "node_recording_rules_rule_group" { name = "NodeRecordingRulesRuleGroup-${azurerm_kubernetes_cluster.aks_cluster.name}" location = var.location resource_group_name = var.rg_name cluster_name = azurerm_kubernetes_cluster.aks_cluster.name description = "Node Recording Rules Rule Group" rule_group_enabled = true interval = "PT1M" scopes = [var.monitoring_workspace_id, azurerm_kubernetes_cluster.aks_cluster.id] rule { enabled = true record = "instance:node_num_cpu:sum" expression = <<EOF count without (cpu, mode) ( node_cpu_seconds_total{job="node",mode="idle"}) EOF } rule { enabled = true record = "instance:node_cpu_utilisation:rate5m" expression = <<EOF 1 - avg without (cpu) ( sum without (mode) (rate(node_cpu_seconds_total{job="node", mode=~"idle|iowait|steal"}[5m]))) EOF } rule { enabled = true record = "instance:node_load1_per_cpu:ratio" expression = <<EOF ( node_load1{job="node"}/ instance:node_num_cpu:sum{job="node"}) EOF } rule { enabled = true record = "instance:node_memory_utilisation:ratio" expression = <<EOF 1 - ( ( node_memory_MemAvailable_bytes{job="node"} or ( node_memory_Buffers_bytes{job="node"} + node_memory_Cached_bytes{job="node"} + node_memory_MemFree_bytes{job="node"} + node_memory_Slab_bytes{job="node"} ) )/ node_memory_MemTotal_bytes{job="node"}) EOF } rule { enabled = true record = "instance:node_vmstat_pgmajfault:rate5m" expression = <<EOF rate(node_vmstat_pgmajfault{job="node"}[5m]) EOF } rule { enabled = true record = "instance_device:node_disk_io_time_seconds:rate5m" expression = <<EOF rate(node_disk_io_time_seconds_total{job="node", device!=""}[5m]) EOF } rule { enabled = true record = "instance_device:node_disk_io_time_weighted_seconds:rate5m" expression = <<EOF rate(node_disk_io_time_weighted_seconds_total{job="node", device!=""}[5m]) EOF } rule { enabled = true record = "instance:node_network_receive_bytes_excluding_lo:rate5m" expression = <<EOF sum without (device) ( rate(node_network_receive_bytes_total{job="node", device!="lo"}[5m])) EOF } rule { enabled = true record = "instance:node_network_transmit_bytes_excluding_lo:rate5m" expression = <<EOF sum without (device) ( rate(node_network_transmit_bytes_total{job="node", device!="lo"}[5m])) EOF } rule { enabled = true record = "instance:node_network_receive_drop_excluding_lo:rate5m" expression = <<EOF sum without (device) ( rate(node_network_receive_drop_total{job="node", device!="lo"}[5m])) EOF } rule { enabled = true record = "instance:node_network_transmit_drop_excluding_lo:rate5m" expression = <<EOF sum without (device) ( rate(node_network_transmit_drop_total{job="node", device!="lo"}[5m])) EOF } tags = merge(tomap({ Service = "AKS monitoring rules" }), var.tags) depends_on = [ azurerm_kubernetes_cluster.aks_cluster, azurerm_monitor_data_collection_rule_association.prometheus_dcra, azurerm_monitor_data_collection_rule_association.ci_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "kubernetes_recording_rules_rule_group" { name = "KubernetesRecordingRulesRuleGroup-${azurerm_kubernetes_cluster.aks_cluster.name}" location = var.location resource_group_name = var.rg_name cluster_name = azurerm_kubernetes_cluster.aks_cluster.name description = "Kubernetes Recording Rules Rule Group" rule_group_enabled = true interval = "PT1M" scopes = [var.monitoring_workspace_id, azurerm_kubernetes_cluster.aks_cluster.id] rule { enabled = true record = "node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate" expression = <<EOF sum by (cluster, namespace, pod, container) ( irate(container_cpu_usage_seconds_total{job="cadvisor", image!=""}[5m])) * on (cluster, namespace, pod) group_left(node) topk by (cluster, namespace, pod) ( 1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "node_namespace_pod_container:container_memory_working_set_bytes" expression = <<EOF container_memory_working_set_bytes{job="cadvisor", image!=""}* on (namespace, pod) group_left(node) topk by(namespace, pod) (1, max by(namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "node_namespace_pod_container:container_memory_rss" expression = <<EOF container_memory_rss{job="cadvisor", image!=""}* on (namespace, pod) group_left(node) topk by(namespace, pod) (1, max by(namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "node_namespace_pod_container:container_memory_cache" expression = <<EOF container_memory_cache{job="cadvisor", image!=""}* on (namespace, pod) group_left(node) topk by(namespace, pod) (1, max by(namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "node_namespace_pod_container:container_memory_swap" expression = <<EOF container_memory_swap{job="cadvisor", image!=""}* on (namespace, pod) group_left(node) topk by(namespace, pod) (1, max by(namespace, pod, node) (kube_pod_info{node!=""})) EOF } rule { enabled = true record = "cluster:namespace:pod_memory:active:kube_pod_container_resource_requests" expression = <<EOF kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"} * on (namespace, pod, cluster)group_left() max by (namespace, pod, cluster) ( (kube_pod_status_phase{phase=~"Pending|Running"} == 1)) EOF } rule { enabled = true record = "namespace_memory:kube_pod_container_resource_requests:sum" expression = <<EOF sum by (namespace, cluster) ( sum by (namespace, pod, cluster) ( max by (namespace, pod, container, cluster) ( kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"} ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( kube_pod_status_phase{phase=~"Pending|Running"} == 1 ) )) EOF } rule { enabled = true record = "cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests" expression = <<EOF kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"} * on (namespace, pod, cluster)group_left() max by (namespace, pod, cluster) ( (kube_pod_status_phase{phase=~"Pending|Running"} == 1)) EOF } rule { enabled = true record = "namespace_cpu:kube_pod_container_resource_requests:sum" expression = <<EOF sum by (namespace, cluster) ( sum by (namespace, pod, cluster) ( max by (namespace, pod, container, cluster) ( kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"} ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( kube_pod_status_phase{phase=~"Pending|Running"} == 1 ) )) EOF } rule { enabled = true record = "cluster:namespace:pod_memory:active:kube_pod_container_resource_limits" expression = <<EOF kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} * on (namespace, pod, cluster)group_left() max by (namespace, pod, cluster) ( (kube_pod_status_phase{phase=~"Pending|Running"} == 1)) EOF } rule { enabled = true record = "namespace_memory:kube_pod_container_resource_limits:sum" expression = <<EOF sum by (namespace, cluster) ( sum by (namespace, pod, cluster) ( max by (namespace, pod, container, cluster) ( kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( kube_pod_status_phase{phase=~"Pending|Running"} == 1 ) )) EOF } rule { enabled = true record = "cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits" expression = <<EOF kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} * on (namespace, pod, cluster)group_left() max by (namespace, pod, cluster) ( (kube_pod_status_phase{phase=~"Pending|Running"} == 1) ) EOF } rule { enabled = true record = "namespace_cpu:kube_pod_container_resource_limits:sum" expression = <<EOF sum by (namespace, cluster) ( sum by (namespace, pod, cluster) ( max by (namespace, pod, container, cluster) ( kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( kube_pod_status_phase{phase=~"Pending|Running"} == 1 ) )) EOF } rule { enabled = true record = "namespace_workload_pod:kube_pod_owner:relabel" expression = <<EOF max by (cluster, namespace, workload, pod) ( label_replace( label_replace( kube_pod_owner{job="kube-state-metrics", owner_kind="ReplicaSet"}, "replicaset", "$1", "owner_name", "(.*)" ) * on(replicaset, namespace) group_left(owner_name) topk by(replicaset, namespace) ( 1, max by (replicaset, namespace, owner_name) ( kube_replicaset_owner{job="kube-state-metrics"} ) ), "workload", "$1", "owner_name", "(.*)" )) EOF labels = { workload_type = "deployment" } } rule { enabled = true record = "namespace_workload_pod:kube_pod_owner:relabel" expression = <<EOF max by (cluster, namespace, workload, pod) ( label_replace( kube_pod_owner{job="kube-state-metrics", owner_kind="DaemonSet"}, "workload", "$1", "owner_name", "(.*)" )) EOF labels = { workload_type = "daemonset" } } rule { enabled = true record = "namespace_workload_pod:kube_pod_owner:relabel" expression = <<EOF max by (cluster, namespace, workload, pod) ( label_replace( kube_pod_owner{job="kube-state-metrics", owner_kind="StatefulSet"}, "workload", "$1", "owner_name", "(.*)" )) EOF labels = { workload_type = "statefulset" } } rule { enabled = true record = "namespace_workload_pod:kube_pod_owner:relabel" expression = <<EOF max by (cluster, namespace, workload, pod) ( label_replace( kube_pod_owner{job="kube-state-metrics", owner_kind="Job"}, "workload", "$1", "owner_name", "(.*)" )) EOF labels = { workload_type = "job" } } rule { enabled = true record = ":node_memory_MemAvailable_bytes:sum" expression = <<EOF sum( node_memory_MemAvailable_bytes{job="node"} or ( node_memory_Buffers_bytes{job="node"} + node_memory_Cached_bytes{job="node"} + node_memory_MemFree_bytes{job="node"} + node_memory_Slab_bytes{job="node"} )) by (cluster) EOF } rule { enabled = true record = "cluster:node_cpu:ratio_rate5m" expression = <<EOF sum(rate(node_cpu_seconds_total{job="node",mode!="idle",mode!="iowait",mode!="steal"}[5m])) by (cluster) /count(sum(node_cpu_seconds_total{job="node"}) by (cluster, instance, cpu)) by (cluster) EOF } tags = merge(tomap({ Service = "AKS monitoring rules" }), var.tags) depends_on = [ azurerm_kubernetes_cluster.aks_cluster, azurerm_monitor_data_collection_rule_association.prometheus_dcra, azurerm_monitor_data_collection_rule_association.ci_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "node_and_kubernetes_recording_rules_rule_group_win" { name = "NodeAndKubernetesRecordingRulesRuleGroup-Win-${azurerm_kubernetes_cluster.aks_cluster.name}" location = var.location resource_group_name = var.rg_name cluster_name = azurerm_kubernetes_cluster.aks_cluster.name description = "Node and Kubernetes Recording Rules Rule Group for Windows Nodes" rule_group_enabled = true interval = "PT1M" scopes = [var.monitoring_workspace_id, azurerm_kubernetes_cluster.aks_cluster.id] rule { enabled = true record = "node:windows_node_filesystem_usage:" expression = <<EOF max by (instance,volume)((windows_logical_disk_size_bytes{job="windows-exporter"} - windows_logical_disk_free_bytes{job="windows-exporter"}) / windows_logical_disk_size_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_filesystem_avail:" expression = <<EOF max by (instance, volume) (windows_logical_disk_free_bytes{job="windows-exporter"} / windows_logical_disk_size_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = ":windows_node_net_utilisation:sum_irate" expression = <<EOF sum(irate(windows_net_bytes_total{job="windows-exporter"}[5m])) EOF } rule { enabled = true record = "node:windows_node_net_utilisation:sum_irate" expression = <<EOF sum by (instance) ((irate(windows_net_bytes_total{job="windows-exporter"}[5m]))) EOF } rule { enabled = true record = ":windows_node_net_saturation:sum_irate" expression = <<EOF sum(irate(windows_net_packets_received_discarded_total{job="windows-exporter"}[5m])) + sum(irate(windows_net_packets_outbound_discarded_total{job="windows-exporter"}[5m])) EOF } rule { enabled = true record = "node:windows_node_net_saturation:sum_irate" expression = <<EOF sum by (instance) ((irate(windows_net_packets_received_discarded_total{job="windows-exporter"}[5m]) + irate(windows_net_packets_outbound_discarded_total{job="windows-exporter"}[5m]))) EOF } rule { enabled = true record = "windows_pod_container_available" expression = <<EOF windows_container_available{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_total_runtime" expression = <<EOF windows_container_cpu_usage_seconds_total{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_memory_usage" expression = <<EOF windows_container_memory_usage_commit_bytes{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_private_working_set_usage" expression = <<EOF windows_container_memory_usage_private_working_set_bytes{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_network_received_bytes_total" expression = <<EOF windows_container_network_receive_bytes_total{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "windows_container_network_transmitted_bytes_total" expression = <<EOF windows_container_network_transmit_bytes_total{job="windows-exporter", container_id != ""} * on(container_id) group_left(container, pod, namespace) max(kube_pod_container_info{job="kube-state-metrics", container_id != ""}) by(container, container_id, pod, namespace) EOF } rule { enabled = true record = "kube_pod_windows_container_resource_memory_request" expression = <<EOF max by (namespace, pod, container) (kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"}) * on(container,pod,namespace) (windows_pod_container_available) EOF } rule { enabled = true record = "kube_pod_windows_container_resource_memory_limit" expression = <<EOF kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} * on(container,pod,namespace) (windows_pod_container_available) EOF } rule { enabled = true record = "kube_pod_windows_container_resource_cpu_cores_request" expression = <<EOF max by (namespace, pod, container) ( kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"}) * on(container,pod,namespace) (windows_pod_container_available) EOF } rule { enabled = true record = "kube_pod_windows_container_resource_cpu_cores_limit" expression = <<EOF kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} * on(container,pod,namespace) (windows_pod_container_available) EOF } rule { enabled = true record = "namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate" expression = <<EOF sum by (namespace, pod, container) (rate(windows_container_total_runtime{}[5m])) EOF } tags = merge(tomap({ Service = "AKS monitoring rules" }), var.tags) depends_on = [ azurerm_kubernetes_cluster.aks_cluster, azurerm_monitor_data_collection_rule_association.prometheus_dcra, azurerm_monitor_data_collection_rule_association.ci_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "node_recording_rules_rule_group_win" { name = "NodeRecordingRulesRuleGroup-Win-${azurerm_kubernetes_cluster.aks_cluster.name}" location = var.location resource_group_name = var.rg_name cluster_name = azurerm_kubernetes_cluster.aks_cluster.name description = "Node and Kubernetes Recording Rules Rule Group for Windows Nodes" rule_group_enabled = true interval = "PT1M" scopes = [var.monitoring_workspace_id, azurerm_kubernetes_cluster.aks_cluster.id] rule { enabled = true record = "node:windows_node:sum" expression = <<EOF count (windows_system_boot_time_timestamp_seconds{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_num_cpu:sum" expression = <<EOF count by (instance) (sum by (instance, core) (windows_cpu_time_total{job="windows-exporter"})) EOF } rule { enabled = true record = ":windows_node_cpu_utilisation:avg5m" expression = <<EOF 1 - avg(rate(windows_cpu_time_total{job="windows-exporter",mode="idle"}[5m])) EOF } rule { enabled = true record = "node:windows_node_cpu_utilisation:avg5m" expression = <<EOF 1 - avg by (instance) (rate(windows_cpu_time_total{job="windows-exporter",mode="idle"}[5m])) EOF } rule { enabled = true record = ":windows_node_memory_utilisation:" expression = <<EOF 1 -sum(windows_memory_available_bytes{job="windows-exporter"})/sum(windows_os_visible_memory_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = ":windows_node_memory_MemFreeCached_bytes:sum" expression = <<EOF sum(windows_memory_available_bytes{job="windows-exporter"} + windows_memory_cache_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_memory_totalCached_bytes:sum" expression = <<EOF (windows_memory_cache_bytes{job="windows-exporter"} + windows_memory_modified_page_list_bytes{job="windows-exporter"} + windows_memory_standby_cache_core_bytes{job="windows-exporter"} + windows_memory_standby_cache_normal_priority_bytes{job="windows-exporter"} + windows_memory_standby_cache_reserve_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = ":windows_node_memory_MemTotal_bytes:sum" expression = <<EOF sum(windows_os_visible_memory_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_memory_bytes_available:sum" expression = <<EOF sum by (instance) ((windows_memory_available_bytes{job="windows-exporter"})) EOF } rule { enabled = true record = "node:windows_node_memory_bytes_total:sum" expression = <<EOF sum by (instance) (windows_os_visible_memory_bytes{job="windows-exporter"}) EOF } rule { enabled = true record = "node:windows_node_memory_utilisation:ratio" expression = <<EOF (node:windows_node_memory_bytes_total:sum - node:windows_node_memory_bytes_available:sum) / scalar(sum(node:windows_node_memory_bytes_total:sum)) EOF } rule { enabled = true record = "node:windows_node_memory_utilisation:" expression = <<EOF 1 - (node:windows_node_memory_bytes_available:sum / node:windows_node_memory_bytes_total:sum) EOF } rule { enabled = true record = "node:windows_node_memory_swap_io_pages:irate" expression = <<EOF irate(windows_memory_swap_page_operations_total{job="windows-exporter"}[5m]) EOF } rule { enabled = true record = ":windows_node_disk_utilisation:avg_irate" expression = <<EOF avg(irate(windows_logical_disk_read_seconds_total{job="windows-exporter"}[5m]) + irate(windows_logical_disk_write_seconds_total{job="windows-exporter"}[5m])) EOF } rule { enabled = true record = "node:windows_node_disk_utilisation:avg_irate" expression = <<EOF avg by (instance) ((irate(windows_logical_disk_read_seconds_total{job="windows-exporter"}[5m]) + irate(windows_logical_disk_write_seconds_total{job="windows-exporter"}[5m]))) EOF } tags = merge(tomap({ Service = "AKS monitoring rules" }), var.tags) depends_on = [ azurerm_kubernetes_cluster.aks_cluster, azurerm_monitor_data_collection_rule_association.prometheus_dcra, azurerm_monitor_data_collection_rule_association.ci_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "ux_recording_rules_rule_group" { name = "UXRecordingRulesRuleGroup - ${azurerm_kubernetes_cluster.aks_cluster.name}" location = var.location resource_group_name = var.rg_name cluster_name = azurerm_kubernetes_cluster.aks_cluster.name description = "UX recording rules for Linux" rule_group_enabled = true interval = "PT1M" scopes = [var.monitoring_workspace_id, azurerm_kubernetes_cluster.aks_cluster.id] rule { enabled = true record = "ux:pod_cpu_usage:sum_irate" expression = <<EOF (sum by (namespace, pod, cluster, microsoft_resourceid) ( irate(container_cpu_usage_seconds_total{container != "", pod != "", job = "cadvisor"}[5m]) )) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) (max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) (kube_pod_info{pod != "", job = "kube-state-metrics"})) EOF } rule { enabled = true record = "ux:controller_cpu_usage:sum_irate" expression = <<EOF sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) ( ux:pod_cpu_usage:sum_irate ) EOF } rule { enabled = true record = "ux:pod_workingset_memory:sum" expression = <<EOF ( sum by (namespace, pod, cluster, microsoft_resourceid) ( container_memory_working_set_bytes{container != "", pod != "", job = "cadvisor"} ) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) (max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) (kube_pod_info{pod != "", job = "kube-state-metrics"})) EOF } rule { enabled = true record = "ux:controller_workingset_memory:sum" expression = <<EOF sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) ( ux:pod_workingset_memory:sum ) EOF } rule { enabled = true record = "ux:pod_rss_memory:sum" expression = <<EOF ( sum by (namespace, pod, cluster, microsoft_resourceid) ( container_memory_rss{container != "", pod != "", job = "cadvisor"} ) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) (max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) (kube_pod_info{pod != "", job = "kube-state-metrics"})) EOF } rule { enabled = true record = "ux:controller_rss_memory:sum" expression = <<EOF sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) ( ux:pod_rss_memory:sum ) EOF } rule { enabled = true record = "ux:pod_container_count:sum" expression = <<EOF sum by (node, created_by_name, created_by_kind, namespace, cluster, pod, microsoft_resourceid) ( (( sum by (container, pod, namespace, cluster, microsoft_resourceid) (kube_pod_container_info{container != "", pod != "", container_id != "", job = "kube-state-metrics"}) or sum by (container, pod, namespace, cluster, microsoft_resourceid) (kube_pod_init_container_info{container != "", pod != "", container_id != "", job = "kube-state-metrics"}) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{pod != "", job = "kube-state-metrics"} ) ) ) ) EOF } rule { enabled = true record = "ux:controller_container_count:sum" expression = <<EOF sum by (node, created_by_name, created_by_kind, namespace, cluster, microsoft_resourceid) ( ux:pod_container_count:sum ) EOF } rule { enabled = true record = "ux:pod_container_restarts:max" expression = <<EOF max by (node, created_by_name, created_by_kind, namespace, cluster, pod, microsoft_resourceid) ( (( max by (container, pod, namespace, cluster, microsoft_resourceid) (kube_pod_container_status_restarts_total{container != "", pod != "", job = "kube-state-metrics"}) or sum by (container, pod, namespace, cluster, microsoft_resourceid) (kube_pod_init_status_restarts_total{container != "", pod != "", job = "kube-state-metrics"}) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{pod != "", job = "kube-state-metrics"} ) ) ) ) EOF } rule { enabled = true record = "ux:controller_container_restarts:max" expression = <<EOF max by (node, created_by_name, created_by_kind, namespace, cluster, microsoft_resourceid) ( ux:pod_container_restarts:max ) EOF } rule { enabled = true record = "ux:pod_resource_limit:sum" expression = <<EOF (sum by (cluster, pod, namespace, resource, microsoft_resourceid) ( ( max by (cluster, microsoft_resourceid, pod, container, namespace, resource) (kube_pod_container_resource_limits{container != "", pod != "", job = "kube-state-metrics"}) ) )unless (count by (pod, namespace, cluster, resource, microsoft_resourceid) (kube_pod_container_resource_limits{container != "", pod != "", job = "kube-state-metrics"}) != on (pod, namespace, cluster, microsoft_resourceid) group_left() sum by (pod, namespace, cluster, microsoft_resourceid) (kube_pod_container_info{container != "", pod != "", job = "kube-state-metrics"}) ) )* on (namespace, pod, cluster, microsoft_resourceid) group_left (node, created_by_kind, created_by_name) ( kube_pod_info{pod != "", job = "kube-state-metrics"} ) EOF } rule { enabled = true record = "ux:controller_resource_limit:sum" expression = <<EOF sum by (cluster, namespace, created_by_name, created_by_kind, node, resource, microsoft_resourceid) ( ux:pod_resource_limit:sum ) EOF } rule { enabled = true record = "ux:controller_pod_phase_count:sum" expression = <<EOF sum by (cluster, phase, node, created_by_kind, created_by_name, namespace, microsoft_resourceid) ( ( (kube_pod_status_phase{job="kube-state-metrics",pod!=""}) or (label_replace((count(kube_pod_deletion_timestamp{job="kube-state-metrics",pod!=""}) by (namespace, pod, cluster, microsoft_resourceid) * count(kube_pod_status_reason{reason="NodeLost", job="kube-state-metrics"} == 0) by (namespace, pod, cluster, microsoft_resourceid)), "phase", "terminating", "", ""))) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{job="kube-state-metrics",pod!=""} ) ) ) EOF } rule { enabled = true record = "ux:cluster_pod_phase_count:sum" expression = <<EOF sum by (cluster, phase, node, namespace, microsoft_resourceid) ( ux:controller_pod_phase_count:sum ) EOF } rule { enabled = true record = "ux:node_cpu_usage:sum_irate" expression = <<EOF sum by (instance, cluster, microsoft_resourceid) ( (1 - irate(node_cpu_seconds_total{job="node", mode="idle"}[5m])) ) EOF } rule { enabled = true record = "ux:node_memory_usage:sum" expression = <<EOF sum by (instance, cluster, microsoft_resourceid) (( node_memory_MemTotal_bytes{job = "node"} - node_memory_MemFree_bytes{job = "node"} - node_memory_cached_bytes{job = "node"} - node_memory_buffers_bytes{job = "node"} )) EOF } rule { enabled = true record = "ux:node_network_receive_drop_total:sum_irate" expression = <<EOF sum by (instance, cluster, microsoft_resourceid) (irate(node_network_receive_drop_total{job="node", device!="lo"}[5m])) EOF } rule { enabled = true record = "ux:node_network_transmit_drop_total:sum_irate" expression = <<EOF sum by (instance, cluster, microsoft_resourceid) (irate(node_network_transmit_drop_total{job="node", device!="lo"}[5m])) EOF } tags = merge(tomap({ Service = "AKS monitoring rules" }), var.tags) depends_on = [ azurerm_kubernetes_cluster.aks_cluster, azurerm_monitor_data_collection_rule_association.prometheus_dcra, azurerm_monitor_data_collection_rule_association.ci_dcra ] } resource "azurerm_monitor_alert_prometheus_rule_group" "ux_recording_rules_rule_group_windows" { name = "UXRecordingRulesRuleGroup-Win - ${azurerm_kubernetes_cluster.aks_cluster.name}" location = var.location resource_group_name = var.rg_name cluster_name = azurerm_kubernetes_cluster.aks_cluster.name description = "UX recording rules for Windows" rule_group_enabled = true interval = "PT1M" scopes = [ var.monitoring_workspace_id, azurerm_kubernetes_cluster.aks_cluster.id ] rule { enabled = true record = "ux:pod_cpu_usage_windows:sum_irate" expression = <<EOF sum by (cluster, pod, namespace, node, created_by_kind, created_by_name, microsoft_resourceid) ( ( max by (instance, container_id, cluster, microsoft_resourceid) ( irate(windows_container_cpu_usage_seconds_total{ container_id != "", job = "windows-exporter"}[5m]) ) * on (container_id, cluster, microsoft_resourceid) group_left (container, pod, namespace) ( max by (container, container_id, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_container_info{container != "", pod != "", container_id != "", job = "kube-state-metrics"} ) ) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{ pod != "", job = "kube-state-metrics"} ) ) ) EOF } rule { enabled = true record = "ux:controller_cpu_usage_windows:sum_irate" expression = "sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) (ux:pod_cpu_usage_windows:sum_irate)" } rule { enabled = true record = "ux:pod_workingset_memory_windows:sum" expression = <<EOF sum by (cluster, pod, namespace, node, created_by_kind, created_by_name, microsoft_resourceid) ( ( max by (instance, container_id, cluster, microsoft_resourceid) ( windows_container_memory_usage_private_working_set_bytes{ container_id != "", job = "windows-exporter"} ) * on (container_id, cluster, microsoft_resourceid) group_left (container, pod, namespace) ( max by (container, container_id, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_container_info{container != "", pod != "", container_id != "", job = "kube-state-metrics"} ) ) ) * on (pod, namespace, cluster, microsoft_resourceid) group_left (node, created_by_name, created_by_kind) ( max by (node, created_by_name, created_by_kind, pod, namespace, cluster, microsoft_resourceid) ( kube_pod_info{ pod != "", job = "kube-state-metrics"} ) ) ) EOF } rule { enabled = true record = "ux:controller_workingset_memory_windows:sum" expression = "sum by (namespace, node, cluster, created_by_name, created_by_kind, microsoft_resourceid) (ux:pod_workingset_memory_windows:sum)" } rule { enabled = true record = "ux:node_cpu_usage_windows:sum_irate" expression = "sum by (instance, cluster, microsoft_resourceid) ((1 - irate(windows_cpu_time_total{job=\"windows-exporter\", mode=\"idle\"}[5m])))" } rule { enabled = true record = "ux:node_memory_usage_windows:sum" expression = "sum by (instance, cluster, microsoft_resourceid) ((windows_os_visible_memory_bytes{job = \"windows-exporter\"}- windows_memory_available_bytes{job = \"windows-exporter\"}))" } rule { enabled = true record = "ux:node_network_packets_received_drop_total_windows:sum_irate" expression = "sum by (instance, cluster, microsoft_resourceid) (irate(windows_net_packets_received_discarded_total{job=\"windows-exporter\", device!=\"lo\"}[5m]))" } rule { enabled = true record = "ux:node_network_packets_outbound_drop_total_windows:sum_irate" expression = "sum by (instance, cluster, microsoft_resourceid) (irate(windows_net_packets_outbound_discarded_total{job=\"windows-exporter\", device!=\"lo\"}[5m]))" } tags = merge(tomap({ Service = "AKS monitoring rules" }), var.tags) depends_on = [ azurerm_kubernetes_cluster.aks_cluster, azurerm_monitor_data_collection_rule_association.prometheus_dcra, azurerm_monitor_data_collection_rule_association.ci_dcra ] } #endregion Managed Prometheus Rule Groups
After setting up check your managed grafana and you would be able to see thethe Azure minotr workspace prometheus data source is available in managed grafana as shown below.
Then we can adda variable in a Grafana dashboard as shown below to dynamically select the prometheus data source.
No comments:
Post a Comment