Jak zapytania dotyczące dzienników z usługi Container Insights

Szczegółowe informacje o kontenerze zbierają metryki wydajności, dane spisu i informacje o stanie kondycji z hostów i kontenerów kontenerów. Dane są zbierane co trzy minuty i przekazywane do obszaru roboczego usługi Log Analytics Azure Monitor, gdzie są dostępne dla zapytań dzienników przy użyciu usługi Log Analytics w Azure Monitor. Te dane można zastosować do scenariuszy, które obejmują planowanie migracji, analizę pojemności, odnajdywanie i rozwiązywanie problemów z wydajnością na żądanie. Azure Monitor dzienniki mogą pomóc w wyszukiwaniach trendów, diagnozowaniu wąskich gardeł, prognozie lub korelowania danych, co może pomóc w ustaleniu, czy bieżąca konfiguracja klastra działa optymalnie.

Aby uzyskać informacje na temat używania tych zapytań i samouczek usługi Log Analytics, zobacz Temat Using queries in Azure Monitor Log Analytics (Korzystanie z zapytań w programie Azure Monitor Log Analytics), a także samouczek usługi Log Analytics, aby uzyskać pełny samouczek dotyczący używania usługi Log Analytics do uruchamiania zapytań i pracy z ich wynikami.

Otwieranie usługi Log Analytics

Istnieje wiele opcji uruchamiania usługi Log Analytics, z których każda zaczyna się od innego zakresu. Aby uzyskać dostęp do wszystkich danych w obszarze roboczym, wybierz pozycję Dzienniki z menu Monitoruj. Aby ograniczyć dane do jednego klastra Kubernetes, wybierz pozycję Dzienniki z menu tego klastra.

Uruchamianie usługi Log Analytics

Istniejące zapytania dotyczące dzienników

Nie musisz wiedzieć, jak napisać zapytanie dziennika w celu korzystania z usługi Log Analytics. Istnieje wiele wstępnie utworzonych zapytań, które można wybrać i uruchomić bez modyfikacji lub użyć jako początek zapytania niestandardowego. Kliknij pozycję Zapytania w górnej części ekranu usługi Log Analytics i wyświetl zapytania z typem zasobu usługi Kubernetes Services.

Zapytania usługi Log Analytics dla rozwiązania Kubernetes

Tabele kontenerów

Zobacz Azure Monitor tabel, aby uzyskać listę tabel i ich szczegółowe opisy używane przez usługę Container Insights. Wszystkie te tabele są dostępne dla zapytań dziennika.

Przykładowe zapytania dotyczące dzienników

Często warto tworzyć zapytania, które zaczynają się od przykładu lub dwóch, a następnie modyfikować je zgodnie z wymaganiami. Aby ułatwić tworzenie bardziej zaawansowanych zapytań, możesz poeksperymentować z następującymi przykładami zapytań:

Lista wszystkich informacji o cyklu życia kontenera

ContainerInventory
| project Computer, Name, Image, ImageTag, ContainerState, CreatedTime, StartedTime, FinishedTime
| render table

Zdarzenia kubernetes

KubeEvents
| where not(isempty(Namespace))
| sort by TimeGenerated desc
| render table

Procesor CPU kontenera

Perf
| where ObjectName == "K8SContainer" and CounterName == "cpuUsageNanoCores" 
| summarize AvgCPUUsageNanoCores = avg(CounterValue) by bin(TimeGenerated, 30m), InstanceName 

Pamięć kontenera

Perf
| where ObjectName == "K8SContainer" and CounterName == "memoryRssBytes"
| summarize AvgUsedRssMemoryBytes = avg(CounterValue) by bin(TimeGenerated, 30m), InstanceName

Żądania na minutę z metrykami niestandardowymi

InsightsMetrics
| where Name == "requests_count"
| summarize Val=any(Val) by TimeGenerated=bin(TimeGenerated, 1m)
| sort by TimeGenerated asc
| project RequestsPerMinute = Val - prev(Val), TimeGenerated
| render barchart 

Zasobniki według nazwy i przestrzeni nazw

let startTimestamp = ago(1h);
KubePodInventory
| where TimeGenerated > startTimestamp
| project ContainerID, PodName=Name, Namespace
| where PodName contains "name" and Namespace startswith "namespace"
| distinct ContainerID, PodName
| join
(
    ContainerLog
    | where TimeGenerated > startTimestamp
)
on ContainerID
// at this point before the next pipe, columns from both tables are available to be "projected". Due to both
// tables having a "Name" column, we assign an alias as PodName to one column which we actually want
| project TimeGenerated, PodName, LogEntry, LogEntrySource
| summarize by TimeGenerated, LogEntry
| order by TimeGenerated desc

Skalowanie zasobników w zewnątrz (HPA)

Zwraca liczbę skalowanych replik w poszczególnych wdrożeniach. Oblicza wartość procentową skalowania w zewnątrz z maksymalną liczbą replik skonfigurowanych w hpa.

let _minthreshold = 70; // minimum threshold goes here if you want to setup as an alert
let _maxthreshold = 90; // maximum threshold goes here if you want to setup as an alert
let startDateTime = ago(60m);
KubePodInventory
| where TimeGenerated >= startDateTime 
| where Namespace !in('default', 'kube-system') // List of non system namespace filter goes here.
| extend labels = todynamic(PodLabel)
| extend deployment_hpa = reverse(substring(reverse(ControllerName), indexof(reverse(ControllerName), "-") + 1))
| distinct tostring(deployment_hpa)
| join kind=inner (InsightsMetrics 
    | where TimeGenerated > startDateTime 
    | where Name == 'kube_hpa_status_current_replicas'
    | extend pTags = todynamic(Tags) //parse the tags for values
    | extend ns = todynamic(pTags.k8sNamespace) //parse namespace value from tags
    | extend deployment_hpa = todynamic(pTags.targetName) //parse HPA target name from tags
    | extend max_reps = todynamic(pTags.spec_max_replicas) // Parse maximum replica settings from HPA deployment
    | extend desired_reps = todynamic(pTags.status_desired_replicas) // Parse desired replica settings from HPA deployment
    | summarize arg_max(TimeGenerated, *) by tostring(ns), tostring(deployment_hpa), Cluster=toupper(tostring(split(_ResourceId, '/')[8])), toint(desired_reps), toint(max_reps), scale_out_percentage=(desired_reps * 100 / max_reps)
    //| where scale_out_percentage > _minthreshold and scale_out_percentage <= _maxthreshold
    )
    on deployment_hpa

Skalowanie w zewnątrz puli węzłów

Zwraca liczbę aktywnych węzłów w każdej puli węzłów. Oblicza liczbę dostępnych aktywnych węzłów i maksymalną konfigurację węzłów w ustawieniach automatycznego skalowania w celu określenia wartości procentowej skalowania w zewnątrz. Zobacz wiersze z komentarzami w zapytaniu, aby użyć go dla reguły alertu dotyczącej wielu wyników.

let nodepoolMaxnodeCount = 10; // the maximum number of nodes in your auto scale setting goes here.
let _minthreshold = 20;
let _maxthreshold = 90;
let startDateTime = 60m;
KubeNodeInventory
| where TimeGenerated >= ago(startDateTime)
| extend nodepoolType = todynamic(Labels) //Parse the labels to get the list of node pool types
| extend nodepoolName = todynamic(nodepoolType[0].agentpool) // parse the label to get the nodepool name or set the specific nodepool name (like nodepoolName = 'agentpool)'
| summarize nodeCount = count(Computer) by ClusterName, tostring(nodepoolName), TimeGenerated
//(Uncomment the below two lines to set this as an log search alert)
//| extend scaledpercent = iff(((nodeCount * 100 / nodepoolMaxnodeCount) >= _minthreshold and (nodeCount * 100 / nodepoolMaxnodeCount) < _maxthreshold), "warn", "normal")
//| where scaledpercent == 'warn'
| summarize arg_max(TimeGenerated, *) by nodeCount, ClusterName, tostring(nodepoolName)
| project ClusterName, 
    TotalNodeCount= strcat("Total Node Count: ", nodeCount),
    ScaledOutPercentage = (nodeCount * 100 / nodepoolMaxnodeCount),  
    TimeGenerated, 
    nodepoolName

Dostępność kontenerów systemu (zestawu replik)

Zwraca kontenery systemowe (zestawy replik) i zgłasza niedostępną wartość procentową. Zobacz wiersze z komentarzami w zapytaniu, aby użyć go dla reguły alertu dotyczącej wielu wyników.

let startDateTime = 5m; // the minimum time interval goes here
let _minalertThreshold = 50; //Threshold for minimum and maximum unavailable or not running containers
let _maxalertThreshold = 70;
KubePodInventory
| where TimeGenerated >= ago(startDateTime)
| distinct ClusterName, TimeGenerated
| summarize Clustersnapshot = count() by ClusterName
| join kind=inner (
    KubePodInventory
    | where TimeGenerated >= ago(startDateTime)
    | where Namespace in('default', 'kube-system') and ControllerKind == 'ReplicaSet' // the system namespace filter goes here
    | distinct ClusterName, Computer, PodUid, TimeGenerated, PodStatus, ServiceName, PodLabel, Namespace, ContainerStatus
    | summarize arg_max(TimeGenerated, *), TotalPODCount = count(), podCount = sumif(1, PodStatus == 'Running' or PodStatus != 'Running'), containerNotrunning = sumif(1, ContainerStatus != 'running')
        by ClusterName, TimeGenerated, ServiceName, PodLabel, Namespace
    )
    on ClusterName
| project ClusterName, ServiceName, podCount, containerNotrunning, containerNotrunningPercent = (containerNotrunning * 100 / podCount), TimeGenerated, PodStatus, PodLabel, Namespace, Environment = tostring(split(ClusterName, '-')[3]), Location = tostring(split(ClusterName, '-')[4]), ContainerStatus
//Uncomment the below line to set for automated alert
//| where PodStatus == "Running" and containerNotrunningPercent > _minalertThreshold and containerNotrunningPercent < _maxalertThreshold
| summarize arg_max(TimeGenerated, *), c_entry=count() by PodLabel, ServiceName, ClusterName
//Below lines are to parse the labels to identify the impacted service/component name
| extend parseLabel = replace(@'k8s-app', @'k8sapp', PodLabel)
| extend parseLabel = replace(@'app.kubernetes.io/component', @'appkubernetesiocomponent', parseLabel)
| extend parseLabel = replace(@'app.kubernetes.io/instance', @'appkubernetesioinstance', parseLabel)
| extend tags = todynamic(parseLabel)
| extend tag01 = todynamic(tags[0].app)
| extend tag02 = todynamic(tags[0].k8sapp)
| extend tag03 = todynamic(tags[0].appkubernetesiocomponent)
| extend tag04 = todynamic(tags[0].aadpodidbinding)
| extend tag05 = todynamic(tags[0].appkubernetesioinstance)
| extend tag06 = todynamic(tags[0].component)
| project ClusterName, TimeGenerated,
    ServiceName = strcat( ServiceName, tag01, tag02, tag03, tag04, tag05, tag06),
    ContainerUnavailable = strcat("Unavailable Percentage: ", containerNotrunningPercent),
    PodStatus = strcat("PodStatus: ", PodStatus), 
    ContainerStatus = strcat("Container Status: ", ContainerStatus)

Dostępność kontenerów systemu (demonów)

Zwraca kontenery systemowe (demony) i zgłasza niedostępną wartość procentową. Zobacz wiersze z komentarzami w zapytaniu, aby użyć go dla reguły alertu dotyczącej wielu wyników.

let startDateTime = 5m; // the minimum time interval goes here
let _minalertThreshold = 50; //Threshold for minimum and maximum unavailable or not running containers
let _maxalertThreshold = 70;
KubePodInventory
| where TimeGenerated >= ago(startDateTime)
| distinct ClusterName, TimeGenerated
| summarize Clustersnapshot = count() by ClusterName
| join kind=inner (
    KubePodInventory
    | where TimeGenerated >= ago(startDateTime)
    | where Namespace in('default', 'kube-system') and ControllerKind == 'DaemonSet' // the system namespace filter goes here
    | distinct ClusterName, Computer, PodUid, TimeGenerated, PodStatus, ServiceName, PodLabel, Namespace, ContainerStatus
    | summarize arg_max(TimeGenerated, *), TotalPODCount = count(), podCount = sumif(1, PodStatus == 'Running' or PodStatus != 'Running'), containerNotrunning = sumif(1, ContainerStatus != 'running')
        by ClusterName, TimeGenerated, ServiceName, PodLabel, Namespace
    )
    on ClusterName
| project ClusterName, ServiceName, podCount, containerNotrunning, containerNotrunningPercent = (containerNotrunning * 100 / podCount), TimeGenerated, PodStatus, PodLabel, Namespace, Environment = tostring(split(ClusterName, '-')[3]), Location = tostring(split(ClusterName, '-')[4]), ContainerStatus
//Uncomment the below line to set for automated alert
//| where PodStatus == "Running" and containerNotrunningPercent > _minalertThreshold and containerNotrunningPercent < _maxalertThreshold
| summarize arg_max(TimeGenerated, *), c_entry=count() by PodLabel, ServiceName, ClusterName
//Below lines are to parse the labels to identify the impacted service/component name
| extend parseLabel = replace(@'k8s-app', @'k8sapp', PodLabel)
| extend parseLabel = replace(@'app.kubernetes.io/component', @'appkubernetesiocomponent', parseLabel)
| extend parseLabel = replace(@'app.kubernetes.io/instance', @'appkubernetesioinstance', parseLabel)
| extend tags = todynamic(parseLabel)
| extend tag01 = todynamic(tags[0].app)
| extend tag02 = todynamic(tags[0].k8sapp)
| extend tag03 = todynamic(tags[0].appkubernetesiocomponent)
| extend tag04 = todynamic(tags[0].aadpodidbinding)
| extend tag05 = todynamic(tags[0].appkubernetesioinstance)
| extend tag06 = todynamic(tags[0].component)
| project ClusterName, TimeGenerated,
    ServiceName = strcat( ServiceName, tag01, tag02, tag03, tag04, tag05, tag06),
    ContainerUnavailable = strcat("Unavailable Percentage: ", containerNotrunningPercent),
    PodStatus = strcat("PodStatus: ", PodStatus), 
    ContainerStatus = strcat("Container Status: ", ContainerStatus)

Dzienniki zasobów

Dzienniki zasobów dla usługi AKS są przechowywane w tabeli AzureDiagnostics. Różne dzienniki można rozróżnić za pomocą kolumny Category. Opis każdej kategorii zawiera temat Dzienniki zasobów referencyjnych usługi AKS. Poniższe przykłady wymagają rozszerzenia diagnostycznego do wysyłania dzienników zasobów dla klastra usługi AKS do obszaru roboczego usługi Log Analytics. Aby uzyskać szczegółowe informacje, zobacz Konfigurowanie monitorowania.

Dzienniki serwera interfejsu API

AzureDiagnostics 
| where Category == "kube-apiserver"

Liczba dzienników dla każdej kategorii

AzureDiagnostics
| where ResourceType == "MANAGEDCLUSTERS"
| summarize count() by Category

Wykonywanie zapytań dotyczących danych metryk Prometheus

Poniższy przykład to zapytanie metryk Prometheus przedstawiające odczyty dysku na sekundę na dysk na węzeł.

InsightsMetrics
| where Namespace == 'container.azm.ms/diskio'
| where TimeGenerated > ago(1h)
| where Name == 'reads'
| extend Tags = todynamic(Tags)
| extend HostName = tostring(Tags.hostName), Device = Tags.name
| extend NodeDisk = strcat(Device, "/", HostName)
| order by NodeDisk asc, TimeGenerated asc
| serialize
| extend PrevVal = iif(prev(NodeDisk) != NodeDisk, 0.0, prev(Val)), PrevTimeGenerated = iif(prev(NodeDisk) != NodeDisk, datetime(null), prev(TimeGenerated))
| where isnotnull(PrevTimeGenerated) and PrevTimeGenerated != TimeGenerated
| extend Rate = iif(PrevVal > Val, Val / (datetime_diff('Second', TimeGenerated, PrevTimeGenerated) * 1), iif(PrevVal == Val, 0.0, (Val - PrevVal) / (datetime_diff('Second', TimeGenerated, PrevTimeGenerated) * 1)))
| where isnotnull(Rate)
| project TimeGenerated, NodeDisk, Rate
| render timechart

Aby wyświetlić metryki Prometheus zdjęte przez Azure Monitor filtrowane według przestrzeni nazw, określ wartość "prometheus". Oto przykładowe zapytanie służące do wyświetlania metryk Prometheus z przestrzeni default nazw kubernetes.

InsightsMetrics 
| where Namespace == "prometheus"
| extend tags=parse_json(Tags)
| summarize count() by Name

Dane Prometheus mogą być również bezpośrednio wyszukiwane według nazwy.

InsightsMetrics 
| where Namespace == "prometheus"
| where Name contains "some_prometheus_metric"

Błędy konfiguracji zapytania lub wycinki

Aby zbadać błędy konfiguracji lub wycinki, następujące przykładowe zapytanie zwraca zdarzenia informacyjne z KubeMonAgentEvents tabeli.

KubeMonAgentEvents | where Level != "Info" 

Dane wyjściowe pokazują wyniki podobne do następujących:

Rejestrowanie wyników zapytań dotyczących zdarzeń informacyjnych z agenta

Następne kroki

Szczegółowe informacje o kontenerze nie zawierają wstępnie zdefiniowanego zestawu alertów. Zapoznaj się z tematem Create performance alerts with Container insights (Tworzenie alertów wydajności za pomocą usługi Container Insights), aby dowiedzieć się, jak tworzyć zalecane alerty dotyczące wysokiego wykorzystania procesora CPU i pamięci w celu obsługi DevOps procesów i procedur operacyjnych.