Создание оповещений поиска по журналам из аналитики контейнеров

Аналитика для контейнеров отслеживает производительность рабочих нагрузок контейнеров, развернутых на кластерах управляемой или самостоятельно управляемой среды Kubernetes. Чтобы сообщить о том, что важно, в этой статье описывается создание оповещений на основе журналов для следующих ситуаций с кластерами Служба Azure Kubernetes (AKS):

  • Если использование ЦП или памяти на узлах кластера превышает порог.
  • Если использование ЦП или памяти для любого контейнера в контроллере превышает порог ограничения для соответствующего ресурса.
  • NotReady Количество узлов состояния
  • Failed, , Pending, RunningUnknownили Succeeded количество этапов pod
  • Если свободное дисковое пространство на узлах кластера превышает порог.

Чтобы оповестить о высоком использовании ЦП или памяти, а также о нехватке дискового пространства на узлах кластера, используйте предоставленные запросы для создания оповещения метрики или оповещения измерения метрики. Оповещения метрик имеют более низкую задержку, чем оповещения поиска по журналам, но оповещения поиска по журналам обеспечивают расширенные запросы и более высокую точность. Запросы генерации оповещений поиска журнала сравнивают дату и время, с помощью now оператора и возвращаясь через час. (Аналитика контейнеров сохраняет все даты в формате UTC.)

Внимание

Запросы в этой статье зависят от данных, собранных аналитикой контейнеров и хранящимися в рабочей области Log Analytics. Если вы изменили параметры сбора данных по умолчанию, запросы могут не возвращать ожидаемые результаты. В частности, если вы отключили сбор данных о производительности, так как вы включили метрики Prometheus для кластера, все запросы, использующие таблицу Perf , не будут возвращать результаты.

Сведения о настройке сбора данных в службе "Аналитика контейнеров" с помощью правила сбора данных для предварительно настроенных конфигураций, включая отключение сбора данных о производительности. Дополнительные параметры сбора данных см. в статье "Настройка сбора данных в аналитике контейнеров" с помощью ConfigMap .

Если вы не знакомы с оповещениями Azure Monitor, ознакомьтесь с обзором оповещений в Microsoft Azure перед началом работы. Дополнительные сведения об оповещениях, использующих запросы журналов, см. в статье "Оповещения поиска по журналам" в Azure Monitor. Узнайте больше об оповещениях метрик в Azure Monitor в этой статье.

Измерения запросов к журналу

Оповещения поиска по журналам могут измерять два разных способа, которые можно использовать для мониторинга виртуальных машин в разных сценариях:

  • Число результатов: подсчитывает количество строк, возвращаемых запросом, и может использоваться для работы с такими событиями, как журналы событий Windows, системный журнал и исключения приложений.
  • Вычисление значения: делает вычисление на основе числового столбца и может использоваться для включения любого количества ресурсов. Примером является процент ЦП.

Целевые ресурсы и измерения

Одно правило можно использовать для отслеживания значений нескольких экземпляров с помощью измерений. Например, можно использовать измерения, если вы хотите отслеживать использование ЦП на нескольких экземплярах, работающих на веб-сайте или приложении, и создать оповещение об использовании ЦП более чем на 80 %.

Чтобы создать оповещения, ориентированные на ресурсы, масштабируемые для подписки или группы ресурсов, можно разделить по измерениям. Если вы хотите отслеживать одно и то же условие для нескольких ресурсов Azure, разделение по измерениям разбивает оповещения на отдельные оповещения путем группировки уникальных сочетаний с помощью числовых или строковых столбцов. Разделение столбца идентификатора ресурса Azure делает указанный ресурс целевым объектом оповещения.

Вы также можете не разделить условие для нескольких ресурсов в области. Например, может потребоваться создать оповещение, если в области группы ресурсов по крайней мере пять компьютеров имеют использование ЦП более 80 %.

Снимок экрана: новое правило генерации оповещений поиска по журналам с разделением по измерениям.

Возможно, вам потребуется просмотреть список оповещений для затронутого компьютера. Для предоставления этого представления можно использовать пользовательскую книгу, использующую настраиваемый граф ресурсов. Для отображения в книге оповещений используйте следующий запрос и Azure Resource Graph источника данных:

Создание правила генерации оповещений поиска по журналам

Чтобы создать правило генерации оповещений поиска по журналам с помощью портала, ознакомьтесь с этим примером оповещения поиска по журналам, которое предоставляет полное пошаговое руководство. Эти же процессы можно использовать для создания правил генерации оповещений для кластеров AKS с помощью запросов, аналогичных тем, которые описаны в этой статье.

Сведения о создании правила генерации оповещений запросов с помощью шаблона Azure Resource Manager (ARM) см. в примерах шаблонов Resource Manager для правил генерации оповещений поиска по журналам в Azure Monitor. Эти же процессы можно использовать для создания шаблонов ARM для запросов журнала в этой статье.

Загруженность ресурсов

Среднее использование ЦП в качестве среднего использования ЦП узлов-членов каждую минуту (измерение метрик):

let endDateTime = now();
let startDateTime = ago(1h);
let trendBinSize = 1m;
let capacityCounterName = 'cpuCapacityNanoCores';
let usageCounterName = 'cpuUsageNanoCores';
KubeNodeInventory
| where TimeGenerated < endDateTime
| where TimeGenerated >= startDateTime
// cluster filter would go here if multiple clusters are reporting to the same Log Analytics workspace
| distinct ClusterName, Computer
| join hint.strategy=shuffle (
  Perf
  | where TimeGenerated < endDateTime
  | where TimeGenerated >= startDateTime
  | where ObjectName == 'K8SNode'
  | where CounterName == capacityCounterName
  | summarize LimitValue = max(CounterValue) by Computer, CounterName, bin(TimeGenerated, trendBinSize)
  | project Computer, CapacityStartTime = TimeGenerated, CapacityEndTime = TimeGenerated + trendBinSize, LimitValue
) on Computer
| join kind=inner hint.strategy=shuffle (
  Perf
  | where TimeGenerated < endDateTime + trendBinSize
  | where TimeGenerated >= startDateTime - trendBinSize
  | where ObjectName == 'K8SNode'
  | where CounterName == usageCounterName
  | project Computer, UsageValue = CounterValue, TimeGenerated
) on Computer
| where TimeGenerated >= CapacityStartTime and TimeGenerated < CapacityEndTime
| project ClusterName, Computer, TimeGenerated, UsagePercent = UsageValue * 100.0 / LimitValue
| summarize AggValue = avg(UsagePercent) by bin(TimeGenerated, trendBinSize), ClusterName

Среднее использование памяти в качестве среднего использования памяти узлов-членов каждую минуту (измерение метрик):

let endDateTime = now();
let startDateTime = ago(1h);
let trendBinSize = 1m;
let capacityCounterName = 'memoryCapacityBytes';
let usageCounterName = 'memoryRssBytes';
KubeNodeInventory
| where TimeGenerated < endDateTime
| where TimeGenerated >= startDateTime
// cluster filter would go here if multiple clusters are reporting to the same Log Analytics workspace
| distinct ClusterName, Computer
| join hint.strategy=shuffle (
  Perf
  | where TimeGenerated < endDateTime
  | where TimeGenerated >= startDateTime
  | where ObjectName == 'K8SNode'
  | where CounterName == capacityCounterName
  | summarize LimitValue = max(CounterValue) by Computer, CounterName, bin(TimeGenerated, trendBinSize)
  | project Computer, CapacityStartTime = TimeGenerated, CapacityEndTime = TimeGenerated + trendBinSize, LimitValue
) on Computer
| join kind=inner hint.strategy=shuffle (
  Perf
  | where TimeGenerated < endDateTime + trendBinSize
  | where TimeGenerated >= startDateTime - trendBinSize
  | where ObjectName == 'K8SNode'
  | where CounterName == usageCounterName
  | project Computer, UsageValue = CounterValue, TimeGenerated
) on Computer
| where TimeGenerated >= CapacityStartTime and TimeGenerated < CapacityEndTime
| project ClusterName, Computer, TimeGenerated, UsagePercent = UsageValue * 100.0 / LimitValue
| summarize AggValue = avg(UsagePercent) by bin(TimeGenerated, trendBinSize), ClusterName

Внимание

В следующих запросах значения заполнителей <your-cluster-name> и <your-controller-name> обозначают ваш кластер и контроллер. При настройке оповещений замените их значениями для вашей среды.

Среднее использование ЦП всех контейнеров в контроллере в среднем по использованию ЦП каждого экземпляра контейнера в контроллере каждую минуту (измерение метрик):

let endDateTime = now();
let startDateTime = ago(1h);
let trendBinSize = 1m;
let capacityCounterName = 'cpuLimitNanoCores';
let usageCounterName = 'cpuUsageNanoCores';
let clusterName = '<your-cluster-name>';
let controllerName = '<your-controller-name>';
KubePodInventory
| where TimeGenerated < endDateTime
| where TimeGenerated >= startDateTime
| where ClusterName == clusterName
| where ControllerName == controllerName
| extend InstanceName = strcat(ClusterId, '/', ContainerName),
         ContainerName = strcat(controllerName, '/', tostring(split(ContainerName, '/')[1]))
| distinct Computer, InstanceName, ContainerName
| join hint.strategy=shuffle (
    Perf
    | where TimeGenerated < endDateTime
    | where TimeGenerated >= startDateTime
    | where ObjectName == 'K8SContainer'
    | where CounterName == capacityCounterName
    | summarize LimitValue = max(CounterValue) by Computer, InstanceName, bin(TimeGenerated, trendBinSize)
    | project Computer, InstanceName, LimitStartTime = TimeGenerated, LimitEndTime = TimeGenerated + trendBinSize, LimitValue
) on Computer, InstanceName
| join kind=inner hint.strategy=shuffle (
    Perf
    | where TimeGenerated < endDateTime + trendBinSize
    | where TimeGenerated >= startDateTime - trendBinSize
    | where ObjectName == 'K8SContainer'
    | where CounterName == usageCounterName
    | project Computer, InstanceName, UsageValue = CounterValue, TimeGenerated
) on Computer, InstanceName
| where TimeGenerated >= LimitStartTime and TimeGenerated < LimitEndTime
| project Computer, ContainerName, TimeGenerated, UsagePercent = UsageValue * 100.0 / LimitValue
| summarize AggValue = avg(UsagePercent) by bin(TimeGenerated, trendBinSize) , ContainerName

Среднее использование памяти всех контейнеров в контроллере в среднем по использованию памяти каждого экземпляра контейнера в контроллере каждую минуту (измерение метрик):

let endDateTime = now();
let startDateTime = ago(1h);
let trendBinSize = 1m;
let capacityCounterName = 'memoryLimitBytes';
let usageCounterName = 'memoryRssBytes';
let clusterName = '<your-cluster-name>';
let controllerName = '<your-controller-name>';
KubePodInventory
| where TimeGenerated < endDateTime
| where TimeGenerated >= startDateTime
| where ClusterName == clusterName
| where ControllerName == controllerName
| extend InstanceName = strcat(ClusterId, '/', ContainerName),
         ContainerName = strcat(controllerName, '/', tostring(split(ContainerName, '/')[1]))
| distinct Computer, InstanceName, ContainerName
| join hint.strategy=shuffle (
    Perf
    | where TimeGenerated < endDateTime
    | where TimeGenerated >= startDateTime
    | where ObjectName == 'K8SContainer'
    | where CounterName == capacityCounterName
    | summarize LimitValue = max(CounterValue) by Computer, InstanceName, bin(TimeGenerated, trendBinSize)
    | project Computer, InstanceName, LimitStartTime = TimeGenerated, LimitEndTime = TimeGenerated + trendBinSize, LimitValue
) on Computer, InstanceName
| join kind=inner hint.strategy=shuffle (
    Perf
    | where TimeGenerated < endDateTime + trendBinSize
    | where TimeGenerated >= startDateTime - trendBinSize
    | where ObjectName == 'K8SContainer'
    | where CounterName == usageCounterName
    | project Computer, InstanceName, UsageValue = CounterValue, TimeGenerated
) on Computer, InstanceName
| where TimeGenerated >= LimitStartTime and TimeGenerated < LimitEndTime
| project Computer, ContainerName, TimeGenerated, UsagePercent = UsageValue * 100.0 / LimitValue
| summarize AggValue = avg(UsagePercent) by bin(TimeGenerated, trendBinSize) , ContainerName

Доступность ресурсов

Узлы и счетчики с состоянием Ready и NotReady (измерение метрик):

let endDateTime = now();
let startDateTime = ago(1h);
let trendBinSize = 1m;
let clusterName = '<your-cluster-name>';
KubeNodeInventory
| where TimeGenerated < endDateTime
| where TimeGenerated >= startDateTime
| distinct ClusterName, Computer, TimeGenerated
| summarize ClusterSnapshotCount = count() by bin(TimeGenerated, trendBinSize), ClusterName, Computer
| join hint.strategy=broadcast kind=inner (
    KubeNodeInventory
    | where TimeGenerated < endDateTime
    | where TimeGenerated >= startDateTime
    | summarize TotalCount = count(), ReadyCount = sumif(1, Status contains ('Ready'))
                by ClusterName, Computer,  bin(TimeGenerated, trendBinSize)
    | extend NotReadyCount = TotalCount - ReadyCount
) on ClusterName, Computer, TimeGenerated
| project   TimeGenerated,
            ClusterName,
            Computer,
            ReadyCount = todouble(ReadyCount) / ClusterSnapshotCount,
            NotReadyCount = todouble(NotReadyCount) / ClusterSnapshotCount
| order by ClusterName asc, Computer asc, TimeGenerated desc

Следующий запрос возвращает количество этапов pod на основе всех этапов: Failed, , Pending, UnknownRunningили Succeeded.

let endDateTime = now(); 
let startDateTime = ago(1h);
let trendBinSize = 1m;
let clusterName = '<your-cluster-name>';
KubePodInventory
    | where TimeGenerated < endDateTime
    | where TimeGenerated >= startDateTime
    | where ClusterName == clusterName
    | distinct ClusterName, TimeGenerated
    | summarize ClusterSnapshotCount = count() by bin(TimeGenerated, trendBinSize), ClusterName
    | join hint.strategy=broadcast (
        KubePodInventory
        | where TimeGenerated < endDateTime
        | where TimeGenerated >= startDateTime
        | summarize PodStatus=any(PodStatus) by TimeGenerated, PodUid, ClusterName
        | summarize TotalCount = count(),
                    PendingCount = sumif(1, PodStatus =~ 'Pending'),
                    RunningCount = sumif(1, PodStatus =~ 'Running'),
                    SucceededCount = sumif(1, PodStatus =~ 'Succeeded'),
                    FailedCount = sumif(1, PodStatus =~ 'Failed')
                by ClusterName, bin(TimeGenerated, trendBinSize)
    ) on ClusterName, TimeGenerated
    | extend UnknownCount = TotalCount - PendingCount - RunningCount - SucceededCount - FailedCount
    | project TimeGenerated,
              TotalCount = todouble(TotalCount) / ClusterSnapshotCount,
              PendingCount = todouble(PendingCount) / ClusterSnapshotCount,
              RunningCount = todouble(RunningCount) / ClusterSnapshotCount,
              SucceededCount = todouble(SucceededCount) / ClusterSnapshotCount,
              FailedCount = todouble(FailedCount) / ClusterSnapshotCount,
              UnknownCount = todouble(UnknownCount) / ClusterSnapshotCount
| summarize AggValue = avg(PendingCount) by bin(TimeGenerated, trendBinSize)

Примечание.

Чтобы оповещать на определенных этапах pod, например Pending, Failedили Unknownизмените последнюю строку запроса. Например, чтобы оповещать , FailedCountиспользуйте | summarize AggValue = avg(FailedCount) by bin(TimeGenerated, trendBinSize).

Следующий запрос возвращает диски узлов кластера с объемом использования свободного места более 90 %. Чтобы получить идентификатор кластера, сначала выполните следующий запрос и скопируйте значение из свойства ClusterId:

InsightsMetrics
| extend Tags = todynamic(Tags)            
| project ClusterId = Tags['container.azm.ms/clusterId']   
| distinct tostring(ClusterId)   
let clusterId = '<cluster-id>';
let endDateTime = now();
let startDateTime = ago(1h);
let trendBinSize = 1m;
InsightsMetrics
| where TimeGenerated < endDateTime
| where TimeGenerated >= startDateTime
| where Origin == 'container.azm.ms/telegraf'            
| where Namespace == 'container.azm.ms/disk'            
| extend Tags = todynamic(Tags)            
| project TimeGenerated, ClusterId = Tags['container.azm.ms/clusterId'], Computer = tostring(Tags.hostName), Device = tostring(Tags.device), Path = tostring(Tags.path), DiskMetricName = Name, DiskMetricValue = Val   
| where ClusterId =~ clusterId       
| where DiskMetricName == 'used_percent'
| summarize AggValue = max(DiskMetricValue) by bin(TimeGenerated, trendBinSize)
| where AggValue >= 90

Каждое оповещение о перезапуске контейнера (число результатов) при превышении количества отдельных системных перезапусков превышает пороговое значение за последние 10 минут:

let _threshold = 10m; 
let _alertThreshold = 2;
let Timenow = (datetime(now) - _threshold); 
let starttime = ago(5m); 
KubePodInventory
| where TimeGenerated >= starttime
| where Namespace in ('default', 'kube-system') // the namespace filter goes here
| where ContainerRestartCount > _alertThreshold
| extend Tags = todynamic(ContainerLastStatus)
| extend startedAt = todynamic(Tags.startedAt)
| where startedAt >= Timenow
| summarize arg_max(TimeGenerated, *) by Name

Следующие шаги