2 - Архитектура для сбора логов
Логи помогают понять, что происходит внутри приложения. Они особенно полезны для отладки проблем и мониторинга деятельности кластера. У большинства современных приложений имеется тот или иной механизм сбора логов. Контейнерные движки в этом смысле не исключение. Самый простой и наиболее распространенный метод сбора логов для контейнерных приложений задействует потоки stdout
и stderr
.
Однако встроенной функциональности контейнерного движка или среды исполнения обычно недостаточно для организации полноценного решения по сбору логов.
Например, может возникнуть необходимость просмотреть логи приложения при аварийном завершении работы Pod'а, его вытеснении (eviction) или "падении" узла.
В кластере у логов должно быть отдельное хранилище и жизненный цикл, не зависящий от узлов, Pod'ов или контейнеров. Эта концепция называется сбор логов на уровне кластера.
Архитектуры для сбора логов на уровне кластера требуют отдельного бэкенда для их хранения, анализа и выполнения запросов. Kubernetes не имеет собственного решения для хранения такого типа данных. Вместо этого существует множество продуктов для сбора логов, которые прекрасно с ним интегрируются. В последующих разделах описано, как обрабатывать логи и хранить их на узлах.
Основы сбора логов в Kubernetes
В примере ниже используется спецификация Pod
с контейнером для отправки текста в стандартный поток вывода раз в секунду.
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
args: [/bin/sh, -c,
'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
Запустить его можно с помощью следующей команды:
kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml
Результат будет таким:
Получить логи можно с помощью команды kubectl logs
, как показано ниже:
Результат будет таким:
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...
Команда kubectl logs --previous
позволяет извлечь логи из предыдущего воплощения контейнера. Если в Pod'е несколько контейнеров, выбрать нужный для извлечения логов можно с помощью флага -c
:
kubectl logs counter -c count
Для получения дополнительной информации см. документацию по kubectl logs
.
Сбор логов на уровне узла
Среда исполнения для контейнера обрабатывает и перенаправляет любой вывод в потоки stdout
и stderr
приложения. Docker Engine, например, перенаправляет эти потоки драйверу журналирования, который в Kubernetes настроен на запись в файл в формате JSON.
Примечание: JSON-драйвер Docker для сбора логов рассматривает каждую строку как отдельное сообщение. В данном случае поддержка многострочных сообщений отсутствует. Обработка многострочных сообщений должна выполняться на уровне лог-агента или выше.
По умолчанию, если контейнер перезапускается, kubelet сохраняет один завершенный контейнер с его логами. Если Pod вытесняется с узла, все соответствующие контейнеры также вытесняются вместе с их логами.
Важным моментом при сборе логов на уровне узла является их ротация, чтобы логи не занимали все доступное место на узле. Kubernetes не отвечает за ротацию логов, но способен развернуть инструмент для решения этой проблемы. Например, в кластерах Kubernetes, развертываемых с помощью скрипта kube-up.sh
, имеется инструмент logrotate
, настроенный на ежечасный запуск. Также можно настроить среду исполнения контейнера на автоматическую ротацию логов приложения.
Подробную информацию о том, как kube-up.sh
настраивает логирование для образа COS на GCP, можно найти в соответствующем скрипте configure-helper
.
При использовании среды исполнения контейнера CRI kubelet отвечает за ротацию логов и управление структурой их директории. kubelet передает данные среде исполнения контейнера CRI, а та сохраняет логи контейнера в указанное место. С помощью параметров containerLogMaxSize
и containerLogMaxFiles
в конфигурационном файле kubelet'а можно настроить максимальный размер каждого лог-файла и максимальное число таких файлов для каждого контейнера соответственно.
При выполнении команды kubectl logs
(как в примере из раздела про основы сбора логов) kubelet на узле обрабатывает запрос и считывает данные непосредственно из файла журнала. Затем он возвращает его содержимое.
Примечание: Если ротацию выполнила внешняя система или используется среда исполнения контейнера CRI, команде kubectl logs
будет доступно содержимое только последнего лог-файла. Например, имеется файл размером 10 МБ, logrotate
выполняет ротацию, и получается два файла: первый размером 10 МБ, второй - пустой. В этом случае kubectl logs
вернет второй лог-файл (пустой).
Логи системных компонентов
Существует два типа системных компонентов: те, которые работают в контейнере, и те, которые работают за пределами контейнера. Например:
- планировщик Kubernetes и kube-proxy выполняются в контейнере;
- kubelet и среда исполнения контейнера работают за пределами контейнера.
На машинах с systemd среда исполнения и kubelet пишут в journald. Если systemd отсутствует, среда исполнения и kubelet пишут в файлы .log
в директории /var/log
. Системные компоненты внутри контейнеров всегда пишут в директорию /var/log
, обходя механизм ведения логов по умолчанию. Они используют библиотеку для сбора логов klog
. Правила сбора логов и рекомендации можно найти в соответствующей документации.
Как и логи контейнеров, логи системных компонентов в директории /var/log
необходимо ротировать. В кластерах Kubernetes, созданных с помощью скрипта kube-up.sh
, эти файлы настроены на ежедневную ротацию с помощью инструмента logrotate
или при достижении 100 МБ.
Архитектуры для сбора логов на уровне кластера
Kubernetes не имеет собственного решения для сбора логов на уровне кластера, но есть общие подходы, которые можно рассмотреть. Вот некоторые из них:
- использовать агент на уровне узлов (запускается на каждом узле);
- внедрить в Pod с приложением специальный sidecar-контейнер для сбора логов;
- отправлять логи из приложения непосредственно в бэкенд.
Использование агента на уровне узлов
Сбор логов на уровне кластера можно реализовать, запустив node-level-агент на каждом узле. Лог-агент — это специальный инструмент, который предоставляет доступ к логам или передает их бэкенду. Как правило, лог-агент представляет собой контейнер с доступом к директории с файлами логов всех контейнеров приложений на этом узле.
Поскольку лог-агент должен работать на каждом узле, рекомендуется запускать его как DaemonSet
.
Сбор логов на уровне узла предусматривает запуск одного агента на узел и не требует изменений в приложениях, работающих на узле.
Контейнеры пишут в stdout
и stderr
, но без согласованного формата. Агент на уровне узла собирает эти логи и направляет их на агрегацию.
Сбор логов с помощью sidecar-контейнера с лог-агентом
Sidecar-контейнер можно использовать одним из следующих способов:
- sidecar-контейнер транслирует логи приложений на свой собственный
stdout
; - в sidecar-контейнере работает агент, настроенный на сбор логов из контейнера приложения.
Транслирующий sidecar-контейнер
Настроив sidecar-контейнеры на вывод в их собственные потоки stdout
и stderr
, можно воспользоваться преимуществами kubelet и лог-агента, которые уже работают на каждом узле. Sidecar-контейнеры считывают логи из файла, сокета или journald. Затем каждый из них пишет логи в собственный поток stdout
или stderr
.
Такой подход позволяет разграничить потоки логов от разных частей приложения, некоторые из которых могут не поддерживать запись в stdout
или stderr
. Логика, управляющая перенаправлением логов, проста и не требует значительных ресурсов. Кроме того, поскольку stdout
и stderr
обрабатываются kubelet'ом, можно использовать встроенные инструменты вроде kubectl logs
.
Предположим, к примеру, что в Pod'е работает один контейнер, который пишет логи в два разных файла в двух разных форматах. Вот пример конфигурации такого Pod'а:
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$i: $(date)" >> /var/log/1.log;
echo "$(date) INFO $i" >> /var/log/2.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir: {}
Не рекомендуется писать логи разных форматов в один и тот же поток, даже если удалось перенаправить оба компонента в stdout
контейнера. Вместо этого можно создать два sidecar-контейнера. Каждый из них будет забирать определенный лог-файл с общего тома и перенаправлять логи в свой stdout
.
Вот пример конфигурации Pod'а с двумя sidecar-контейнерами:
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$i: $(date)" >> /var/log/1.log;
echo "$(date) INFO $i" >> /var/log/2.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- name: varlog
mountPath: /var/log
- name: count-log-1
image: busybox:1.28
args: [/bin/sh, -c, 'tail -n+1 -F /var/log/1.log']
volumeMounts:
- name: varlog
mountPath: /var/log
- name: count-log-2
image: busybox:1.28
args: [/bin/sh, -c, 'tail -n+1 -F /var/log/2.log']
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir: {}
Доступ к каждому потоку логов такого Pod'а можно получить отдельно, выполнив следующие команды:
kubectl logs counter count-log-1
Результат будет таким:
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...
kubectl logs counter count-log-2
Результат будет таким:
Mon Jan 1 00:00:00 UTC 2001 INFO 0
Mon Jan 1 00:00:01 UTC 2001 INFO 1
Mon Jan 1 00:00:02 UTC 2001 INFO 2
...
Агент на уровне узла, установленный в кластере, подхватывает эти потоки логов автоматически без дополнительной настройки. При желании можно настроить агент на парсинг логов в зависимости от контейнера-источника.
Обратите внимание: несмотря на низкое использование процессора и памяти (порядка нескольких milliCPU для процессора и пары мегабайт памяти), запись логов в файл и их последующая потоковая передача в stdout
может вдвое увеличить нагрузку на диск. Если приложение пишет в один файл, рекомендуется установить /dev/stdout
в качестве адресата, нежели использовать подход с транслирующим контейнером.
Sidecar-контейнеры также можно использовать для ротации файлов логов, которые не могут быть ротированы самим приложением. В качестве примера можно привести небольшой контейнер, периодически запускающий logrotate
. Однако рекомендуется использовать stdout
и stderr
напрямую, а управление политиками ротации и хранения оставить kubelet'у.
Sidecar-контейнер с лог-агентом
Если лог-агент на уровне узла недостаточно гибок для ваших потребностей, можно создать sidecar-контейнер с отдельным лог-агентом, специально настроенным на работу с приложением.
Примечание: Работа лог-агента в sidecar-контейнере может привести к значительному потреблению ресурсов. Более того, доступ к этим журналам с помощью kubectl logs
будет невозможен, поскольку они не контролируются kubelet'ом.
Ниже приведены два файла конфигурации sidecar-контейнера с лог-агентом. Первый содержит ConfigMap
для настройки fluentd.
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
data:
fluentd.conf: |
<source>
type tail
format none
path /var/log/1.log
pos_file /var/log/1.log.pos
tag count.format1
</source>
<source>
type tail
format none
path /var/log/2.log
pos_file /var/log/2.log.pos
tag count.format2
</source>
<match **>
type google_cloud
</match>
Примечание: За информацией о настройке fluentd обратитесь к его
документации.
Второй файл описывает Pod с sidecar-контейнером, в котором работает fluentd. Pod монтирует том с конфигурацией fluentd.
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$i: $(date)" >> /var/log/1.log;
echo "$(date) INFO $i" >> /var/log/2.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- name: varlog
mountPath: /var/log
- name: count-agent
image: registry.k8s.io/fluentd-gcp:1.30
env:
- name: FLUENTD_ARGS
value: -c /etc/fluentd-config/fluentd.conf
volumeMounts:
- name: varlog
mountPath: /var/log
- name: config-volume
mountPath: /etc/fluentd-config
volumes:
- name: varlog
emptyDir: {}
- name: config-volume
configMap:
name: fluentd-config
В приведенных выше примерах fluentd можно заменить на другой лог-агент, считывающий данные из любого источника в контейнере приложения.
Прямой доступ к логам из приложения
Сбор логов приложения на уровне кластера, при котором доступ к ним осуществляется напрямую, выходит за рамки Kubernetes.
3 - Логи системных компонентов
Логи системных компонентов регистрируют события, происходящие в кластере, что может быть очень полезно при отладке. Степень детализации логов настраивается. Так, в логах низкой детализации будет содержаться только информация об ошибках внутри компонента, в то время как логи высокой детализации будут содержать пошаговую трассировку событий (доступ по HTTP, изменения состояния Pod'а, действия контроллера, решения планировщика).
Klog
klog — библиотека Kubernetes для сбора логов. Отвечает за генерацию соответствующих сообщений для системных компонентов оркестратора.
Дополнительные сведения о настройке klog можно получить в Справке по CLI.
В настоящее время ведется работа по упрощению процесса сбора логов в компонентах Kubernetes. Приведенные ниже флаги командной строки klog устарели, начиная с версии Kubernetes 1.23, и будут удалены в одном из будущих релизов:
--add-dir-header
--alsologtostderr
--log-backtrace-at
--log-dir
--log-file
--log-file-max-size
--logtostderr
--one-output
--skip-headers
--skip-log-headers
--stderrthreshold
Вывод всегда будет записываться в stderr независимо от его формата. Перенаправление вывода должно осуществляться компонентом, который вызывает компонент Kubernetes, например, POSIX-совместимой командной оболочкой или инструментом вроде systemd.
Иногда эти опции недоступны — например, в случае контейнера без дистрибутива (distroless) или системной службы Windows. Тогда kube-log-runner
можно использовать в качестве обертки вокруг компонента Kubernetes для перенаправления вывода. Его предварительно собранный исполняемый файл включен в некоторые базовые образы Kubernetes под старым именем /go-runner
, а в актуальных бинарных релизах архивов с kubernetes-server и kubernetes-node он называется kube-log-runner
.
В таблице ниже показаны соответствия между вызовами kube-log-runner
и логикой перенаправления командной оболочки:
Использование | Оболочка POSIX (например, Bash) | kube-log-runner <options> <cmd> |
---|
Объединить stderr и stdout, вывести в stdout | 2>&1 | kube-log-runner (default behavior) |
Перенаправить оба потока в файл лога | 1>>/tmp/log 2>&1 | kube-log-runner -log-file=/tmp/log |
Скопировать в файл лога и в stdout | 2>&1 | tee -a /tmp/log | kube-log-runner -log-file=/tmp/log -also-stdout |
Перенаправить только stdout в файл лога | >/tmp/log | kube-log-runner -log-file=/tmp/log -redirect-stderr=false |
Вывод klog
Пример оригинального "родного" формата klog:
I1025 00:15:15.525108 1 httplog.go:79] GET /api/v1/namespaces/kube-system/pods/metrics-server-v0.3.1-57c75779f-9p8wg: (1.512ms) 200 [pod_nanny/v0.0.0 (linux/amd64) kubernetes/$Format 10.56.1.19:51756]
Сообщение может содержать переносы строк:
I1025 00:15:15.525108 1 example.go:79] This is a message
which has a line break.
Структурированное логирование
СТАТУС ФИЧИ: Kubernetes v1.23 [beta]
Предупреждение:Переход на структурированное логирование — продолжающийся процесс. Не все сообщения структурированы в текущей версии Kubernetes. При парсинге файлов логов необходимо также обрабатывать неструктурированные сообщения.
Формат логов и сериализация значений могут измениться в будущем.
Структурированное логирование придает определенную структуру сообщениям логов, упрощая программное извлечение информации и сокращая затраты и усилия на их обработку. Код, который генерирует сообщение лога, определяет, используется ли обычный неструктурированный вывод klog или структурированное логирование.
По умолчанию структурированные сообщения форматируются как текст, при этом его формат обратно совместим с традиционным форматом klog:
<klog header> "<message>" <key1>="<value1>" <key2>="<value2>" ...
Пример:
I1025 00:15:15.525108 1 controller_utils.go:116] "Pod status updated" pod="kube-system/kubedns" status="ready"
Строки заключаются в кавычки. Другие значения форматируются с помощью %+v
. В результате сообщение может продолжиться на следующей строке в зависимости от типа данных.
I1025 00:15:15.525108 1 example.go:116] "Example" data="This is text with a line break\nand \"quotation marks\"." someInt=1 someFloat=0.1 someStruct={StringField: First line,
second line.}
Контекстное логирование
СТАТУС ФИЧИ: Kubernetes v1.24 [alpha]
Контекстное логирование базируется на структурированном логировании. Речь идет в первую очередь о том, как разработчики используют лог-вызовы: код, основанный на этой концепции, более гибок и поддерживает дополнительные сценарии использования (см. Contextual Logging KEP).
При использовании в компонентах дополнительных функций, таких как WithValues
или WithName
, записи лога содержат дополнительную информацию, которая передается в функции вызывающей стороной.
В настоящее время за включение контекстного логирования отвечает переключатель функционала StructuredLogging
. По умолчанию оно отключено. Соответствующая инфраструктура появилась в версии 1.24 и она не потребовала изменений в компонентах. Команда component-base/logs/example
показывает, как использовать новые лог-вызовы и как ведет себя компонент, поддерживающий контекстное логирование.
$ cd $GOPATH/src/k8s.io/kubernetes/staging/src/k8s.io/component-base/logs/example/cmd/
$ go run . --help
...
--feature-gates mapStringBool A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:
AllAlpha=true|false (ALPHA - default=false)
AllBeta=true|false (BETA - default=false)
ContextualLogging=true|false (ALPHA - default=false)
$ go run . --feature-gates ContextualLogging=true
...
I0404 18:00:02.916429 451895 logger.go:94] "example/myname: runtime" foo="bar" duration="1m0s"
I0404 18:00:02.916447 451895 logger.go:95] "example: another runtime" foo="bar" duration="1m0s"
Префикс example
и foo="bar"
были добавлены вызовом функции, которая пишет в лог сообщение runtime
и значение duration="1m0s"
, при этом вносить изменения в эту функцию не потребовалось.
При отключенном контекстном логировании WithValues
и WithName
ничего не делают, а вызовы журнала проходят через глобальный логгер klog. Соответственно, эта дополнительная информация более не отображается в логе:
$ go run . --feature-gates ContextualLogging=false
...
I0404 18:03:31.171945 452150 logger.go:94] "runtime" duration="1m0s"
I0404 18:03:31.171962 452150 logger.go:95] "another runtime" duration="1m0s"
Логи в формате JSON
СТАТУС ФИЧИ: Kubernetes v1.19 [alpha]
Предупреждение:Вывод в формате JSON не поддерживает многие стандартные флаги klog. Список неподдерживаемых флагов klog см. в Справочнике по CLI.
Кроме того, запись в формате JSON не гарантируется (например, во время запуска процесса). Таким образом, если планируется дальнейший парсинг логов, убедитесь, что ваш парсер способен обрабатывать строки лога, которые не являются JSON.
Имена полей и сериализация JSON могут измениться в будущем.
Флаг --logging-format=json
переключает формат логов с родного формата klog на JSON. Пример лога в формате JSON (стилистически отформатированном):
{
"ts": 1580306777.04728,
"v": 4,
"msg": "Pod status updated",
"pod":{
"name": "nginx-1",
"namespace": "default"
},
"status": "ready"
}
Специальные ключи:
ts
— временная метка в формате времени Unix (обязательный параметр, float);v
— детализация (для общей информации — не для сообщений об ошибках, int);err
— ошибка (опциональный параметр, string);msg
— сообщение (обязательный параметр, string).
Список компонентов, поддерживающих формат JSON:
Уровень детализации лога
Флаг -v
задает степень детализации лога. Увеличение значения увеличивает количество регистрируемых событий. Уменьшение значения уменьшает количество регистрируемых событий. Увеличение детализации приводит к тому, что регистрируются все менее значимые события. При уровне детализации, равном 0, регистрируются только критические события.
Местоположение лога
Существует два типа системных компонентов: те, которые работают в контейнере, и те, которые работают за пределами контейнера. Например:
На машинах с systemd среда исполнения и kubelet пишут в journald. В противном случае ведется запись в файлы .log
в директории /var/log
. Системные компоненты внутри контейнеров всегда пишут в файлы .log
в директории /var/log
, обходя механизм логирования по умолчанию. Как и логи контейнеров, логи системных компонентов в /var/log
нуждаются в ротации. В кластерах Kubernetes, созданных с использованием скрипта kube-up.sh
, ротация логов настраивается с помощью инструмента logrotate
. logrotate
ротирует логи ежедневно или при достижении ими размера в 100 МБ.
Что дальше
5 - Равноправный доступ к API
СТАТУС ФИЧИ: Kubernetes v1.20 [beta]
Контроль за поведением API-сервера Kubernetes в условиях высокой нагрузки — ключевая задача для администраторов кластера. В kube-apiserver имеются некоторые механизмы управления (например, флаги командной строки --max-requests-inflight
и --max-mutating-requests-inflight
) для ограничения нагрузки на сервер. Они предотвращают наплыв входящих запросов и потенциальный отказ сервера API, но не позволяют гарантировать прохождение наиболее важных запросов в периоды высокой нагрузки.
Функция регулирования приоритета и обеспечения равноправного доступа к API (API Priority and Fairness), или РДА, — отличная альтернатива флагам. Она оптимизирует вышеупомянутые ограничения на максимальное количество запросов. РДА тщательнее классифицирует запросы и изолирует их. Также она поддерживает механизм очередей, который помогает обрабатывать запросы при краткосрочных всплесках нагрузки. Отправка запросов из очередей осуществляется на основе метода организации равноправных очередей, поэтому плохо работающий контроллер не будет мешать работе других (даже с аналогичным уровнем приоритета).
Эта функция предназначена для корректной работы со стандартными контроллерами, которые используют информеры и реагируют на неудачные API-запросы, экспоненциально увеличивая выдержку (back-off) между ними, а также клиентами, устроенными аналогичным образом.
Внимание: Запросы, отнесенные к категории "long-running" — в первую очередь следящие, — не подпадают под действие фильтра функции равноправного доступа к API. Это также верно для флага --max-requests-inflight
без включенной функции РДА.
Включение/отключение равноправного доступа к API
Управление РДА осуществляется с помощью переключателя функционала (feature gate); по умолчанию функция включена. В разделе Переключатели функционала приведено их общее описание и способы включения/отключения. В случае РДА соответствующий переключатель называется "APIPriorityAndFairness". Данная функция также включает группу API, при этом: (a) версия v1alpha1
по умолчанию отключена, (b) версии v1beta1
и v1beta2
по умолчанию включены. Чтобы отключить РДА и бета-версии групп API, добавьте следующие флаги командной строки в вызов kube-apiserver
:
kube-apiserver \
--feature-gates=APIPriorityAndFairness=false \
--runtime-config=flowcontrol.apiserver.k8s.io/v1beta1=false,flowcontrol.apiserver.k8s.io/v1beta2=false \
# …и остальные флаги, как обычно
Кроме того, версию v1alpha1 группы API можно включить с помощью --runtime-config=flowcontrol.apiserver.k8s.io/v1alpha1=true
.
Флаг командной строки --enable-priority-and-fairness=false
отключит функцию равноправного доступа к API, даже если другие флаги ее активировали.
Основные понятия
Функция равноправного доступа к API в своей работе использует несколько базовых понятий/механизмов. Входящие запросы классифицируются по атрибутам с помощью т.н. FlowSchemas, после чего им присваиваются уровни приоритета. Уровни приоритета обеспечивают некоторую степень изоляции, обеспечивая различные пределы параллелизма, предотвращая влияние запросов с разными уровнями приоритета друг на друга. В пределах одного приоритета алгоритм равнодоступного формирования очереди предотвращает взаимное влияние запросов из разных потоков и формирует очередь запросов, снижая число неудачных запросов во время всплесков трафика при приемлемо низкой средней нагрузке.
Уровни приоритета
Без включенного равноправного доступа к API управление общим параллелизмом в API-сервере осуществляется флагами --max-requests-inflight
и --max-mutating-requests-inflight
для kube-apiserver
. При включенном равноправном доступе к API пределы параллелизма, заданные этими флагами, суммируются, а затем сумма распределяется по настраиваемому набору уровней приоритета. Каждому входящему запросу присваивается определенный уровень приоритета, причем каждый уровень приоритета может отправлять только такое количество параллельных запросов, которое прописано в его конфигурации.
Конфигурация по умолчанию, например, предусматривает отдельные уровни приоритета для запросов на выборы лидера, запросов от встроенных контроллеров и запросов от Pod'ов. Это означает, что Pod, ведущий себя некорректно и переполняющий API-сервер запросами, не сможет помешать выборам лидера или оказать влияние на действия встроенных контроллеров.
Очереди
Каждый уровень приоритета может включать большое количество различных источников трафика. Во время перегрузки важно предотвратить негативное влияние одного потока запросов на остальные (например, в идеале один сбойный клиент, переполняющий kube-apiserver своими запросами, не должен оказывать заметного влияния на других клиентов). Для этого при обработке запросов с одинаковым уровнем приоритета используется алгоритм равнодоступной очереди. Каждый запрос приписывается к потоку, который идентифицируется по имени соответствующей FlowSchema и дифференциатору потока: пользователю-источнику запроса, пространству имен целевого ресурса или пустым значением. Система старается придать примерно равный вес запросам в разных потоках с одинаковым уровнем приоритета.
Для раздельной обработки различных инстансов контроллеры с большим их числом должны аутентифицироваться под разными именами пользователей.
Распределив запрос в некоторый поток, РДА приписывает его к очереди. Этот процесс базируется на методе, известном как shuffle sharding (тасование между шардами), который относительно эффективно изолирует потоки низкой интенсивности от потоков высокой интенсивности с помощью очередей.
Параметры алгоритма постановки в очередь можно настраивать для каждого уровня приоритетов. В результате администратор может выбирать между использованием памяти, равнодоступностью (свойством, которое обеспечивает продвижение независимых потоков, когда совокупный трафик превышает пропускную способность), толерантностью к всплескам трафика и дополнительной задержкой, вызванной постановкой в очередь.
Запросы-исключения
Некоторые запросы считаются настолько важными, что на них не распространяется ни одно из ограничений, налагаемых этой функцией. Механизм исключений не позволяет ошибочно настроенной конфигурации управления потоком полностью вывести сервер API из строя.
Ресурсы
API управления потоками включает в себя два вида ресурсов. PriorityLevelConfigurations определяет доступные классы изоляции, долю доступного бюджета параллелизма, которая выделяется для каждого класса, и позволяет выполнять тонкую настройку работы с очередями. FlowSchema используется для классификации отдельных входящих запросов, сопоставляя каждый из них с одной из конфигураций PriorityLevelConfiguration. Кроме того, существует версия v1alpha1
данной группы API, с аналогичными Kinds с теми же синтаксисом и семантикой.
PriorityLevelConfiguration
PriorityLevelConfiguration представляет отдельный класс изоляции. У каждой конфигурации PriorityLevelConfiguration имеется независимый предел на количество активных запросов и ограничения на число запросов в очереди.
Пределы параллелизма для PriorityLevelConfigurations указываются не в виде абсолютного количества запросов, а в виде "долей параллелизма" (concurrency shares). Совокупный объем ресурсов API-сервера, доступных для параллелизма, распределяется между существующими PriorityLevelConfigurations пропорционально этим долям. Администратор кластера может увеличить или уменьшить совокупный объем трафика на сервер, просто перезапустив kube-apiserver с другим значением --max-requests-inflight
(или --max-mutating-requests-inflight
). В результате пропускная способность каждой PriorityLevelConfigurations возрастет (или снизится) соразмерно ее доле.
Внимание: При включенной функции Priority and Fairness суммарный предел параллелизма для сервера равен сумме --max-requests-inflight
и --max-mutating-requests-inflight
. При этом мутирующие и не мутирующие запросы рассматриваются вместе; чтобы обрабатывать их независимо для некоторого ресурса, создайте отдельные FlowSchemas для мутирующих и не мутирующих действий (verbs).
Поле type
спецификации PriorityLevelConfiguration определяет судьбу избыточных запросов, когда их объем, отнесенный к одной PriorityLevelConfiguration, превышает ее допустимый уровень параллелизма. Тип Reject
означает, что избыточный трафик будет немедленно отклонен с ошибкой HTTP 429 (Too Many Requests). Тип Queue
означает, что запросы, превышающие пороговое значение, будут поставлены в очередь, при этом для балансировки прогресса между потоками запросов будут использоваться методы тасования между шардами и равноправных очередей.
Конфигурация очередей позволяет настроить алгоритм равноправных очередей для каждого уровня приоритета. Подробности об алгоритме можно узнать из предложения по улучшению; если вкратце:
Увеличение queues
снижает количество конфликтов между различными потоками за счет повышенного использования памяти. При единице логика равнодоступной очереди отключается, но запросы все равно могут быть поставлены в очередь.
Увеличение длины очереди (queueLengthLimit
) позволяет выдерживать большие всплески трафика без потери запросов за счет увеличения задержек и повышенного потребления памяти.
Изменение handSize
позволяет регулировать вероятность конфликтов между различными потоками и общий параллелизм, доступный для одного потока в условиях чрезмерной нагрузки.
Примечание: Больший handSize
снижает вероятность конфликта двух отдельных потоков (и, следовательно, вероятность того, что один из них подавит другой), но повышает вероятность того, что малое число потоков загрузят API-сервер. Больший handSize
также потенциально увеличивает задержку, которую может вызвать один поток с высоким трафиком. Максимальное возможное количество запросов в очереди от одного потока равно handSize * queueLengthLimit
.
Ниже приведена таблица с различными конфигурациями, показывающая вероятность того, что "мышь" (поток низкой интенсивности) будет раздавлена "слонами" (потоками высокой интенсивности) в зависимости от числа "слонов" при тасовании потоков между шардами. Скрипт для расчета таблицы доступен по ссылке.
Конфигурации shuffle shardinghandSize | Число очередей | 1 слон | 4 слона | 16 слонов |
---|
12 | 32 | 4.428838398950118e-09 | 0.11431348830099144 | 0.9935089607656024 |
10 | 32 | 1.550093439632541e-08 | 0.0626479840223545 | 0.9753101519027554 |
10 | 64 | 6.601827268370426e-12 | 0.00045571320990370776 | 0.49999929150089345 |
9 | 64 | 3.6310049976037345e-11 | 0.00045501212304112273 | 0.4282314876454858 |
8 | 64 | 2.25929199850899e-10 | 0.0004886697053040446 | 0.35935114681123076 |
8 | 128 | 6.994461389026097e-13 | 3.4055790161620863e-06 | 0.02746173137155063 |
7 | 128 | 1.0579122850901972e-11 | 6.960839379258192e-06 | 0.02406157386340147 |
7 | 256 | 7.597695465552631e-14 | 6.728547142019406e-08 | 0.0006709661542533682 |
6 | 256 | 2.7134626662687968e-12 | 2.9516464018476436e-07 | 0.0008895654642000348 |
6 | 512 | 4.116062922897309e-14 | 4.982983350480894e-09 | 2.26025764343413e-05 |
6 | 1024 | 6.337324016514285e-16 | 8.09060164312957e-11 | 4.517408062903668e-07 |
FlowSchema
FlowSchema сопоставляется со входящими запросами; по результатам данного действия тем приписывается определенный уровень приоритета. Каждый входящий запрос по очереди проверяется на соответствие каждой FlowSchema, начиная с тех, у которых наименьшее численное значение matchingPrecedence
(т.е., логически наивысший приоритет). Проверка ведется до первого совпадения.
Внимание: Учитывается только первая подходящая FlowSchema для данного запроса. Если одному входящему запросу соответствует несколько FlowSchemas, он попадет в ту, у которой наивысший matchingPrecedence
. Если несколько FlowSchema с одинаковым matchingPrecedence
соответствуют одному запросу, предпочтение будет отдано той, у которой лексикографически меньшее имя (name
). Впрочем, лучше не полагаться на это, а убедиться, что matchingPrecedence
уникален для всех FlowSchema.
Схема FlowSchema подходит определенному запросу, если хотя бы одно из ее правил (rules
) подходит ему. В свою очередь, правило соответствует запросу, если ему соответствует хотя бы один из его субъектов (subjects
) и хотя бы одно из его правил resourceRules
или nonResourceRules
(в зависимости от того, является ли входящий запрос ресурсным или нересурсным URL).
Для поля name
в субъектах (subjects) и полей verbs
, apiGroups
, resources
, namespaces
и nonResourceURLs
в ресурсных и нересурсных правилах может быть указан универсальный символ *
, который будет соответствовать всем значениям для данного поля, фактически исключая его из рассмотрения.
Параметр distinguisherMethod.type
схемы FlowSchema определяет, как запросы, соответствующие этой схеме, будут разделяться на потоки. Он может быть либо ByUser
(в этом случае один запрашивающий пользователь не сможет лишить других пользователей ресурсов), либо ByNamespace
(в этом случае запросы на ресурсы в одном пространстве имен не смогут помешать запросам на ресурсы в других пространствах имен), либо он может быть пустым (или distinguisherMethod
может быть опущен) (в этом случае все запросы, соответствующие данной FlowSchema, будут считаться частью одного потока). Правильный выбор для определенной FlowSchema зависит от ресурса и конкретной среды.
Значения по умолчанию
kube-apiserver поддерживает два вида объектов конфигурации РДА: обязательные и рекомендуемые.
Обязательные объекты конфигурации
Четыре обязательных объекта конфигурации отражают защитное поведение, встроенное в серверы. Оно реализуется независимо от этих объектов; параметры последних просто его отражают.
Обязательный уровень приоритета exempt
используется для запросов, которые вообще не подчиняются контролю потока: они всегда будут доставляться немедленно. Обязательная FlowSchema exempt
относит к этому уровню приоритета все запросы из группы system:masters
. При необходимости можно задать другие FlowSchemas, которые будут наделять другие запросы данным уровнем приоритета.
Обязательный уровень приоритета catch-all
используется в сочетании с обязательной FlowSchema catch-all
, гарантируя, что каждый запрос получит какую-либо классификацию. Как правило, полагаться на эту универсальную конфигурацию не следует. Рекомендуется создать свои собственные универсальные FlowSchema и PriorityLevelConfiguration (или использовать опциональный уровень приоритета global-default
, доступный по умолчанию). Поскольку предполагается, что обязательный уровень приоритета catch-all
будет использоваться редко, его доля параллелизма невысока, кроме того, он не ставит запросы в очередь.
Опциональные объекты конфигурации
Опциональные объекты FlowSchemas и PriorityLevelConfigurations образуют оптимальную конфигурацию по умолчанию. При желании их можно изменить и/или создать дополнительные объекты конфигурации. Если велика вероятность высокой нагрузки на кластер, следует решить, какая конфигурация будет работать лучше всего.
Опциональная конфигурация группирует запросы по шести уровням приоритета:
Уровень приоритета node-high
предназначен для проверки здоровья узлов.
Уровень приоритета system
предназначен для запросов от группы system:nodes
, не связанных с состоянием узлов, а именно: от kubelet'ов, которые должны иметь возможность связываться с сервером API для планирования рабочих нагрузок.
Уровень приоритета leader-election
предназначен для запросов на выборы лидера от встроенных контроллеров (в частности, запросы на объекты типа Endpoint
, ConfigMap
или Lease
, поступающие от пользователей system:kube-controller-manager
или system:kube-scheduler
и служебных учетных записей в пространстве имен kube-system
). Их важно изолировать от другого трафика, поскольку сбои при выборе лидеров приводят к перезагрузкам контроллеров. Соответственно, новые контроллеры потребляют трафик, синхронизируя свои информеры.
Уровень приоритета workload-high
предназначен для прочих запросов от встроенных контроллеров.
Уровень приоритета workload-low
предназначен для запросов от остальных учетных записей служб, которые обычно включают все запросы от контроллеров, работающих в Pod'ах.
Уровень приоритета global-default
обрабатывает весь остальной трафик, например, интерактивные команды kubectl
, выполняемые непривилегированными пользователями.
Опциональные FlowSchemas служат для направления запросов на вышеуказанные уровни приоритета и здесь не перечисляются.
Обслуживание обязательных и опциональных объектов конфигурации
Каждый kube-apiserver
самостоятельно обслуживает обязательные и опциональные объекты конфигурации, используя стратегию начальных/периодических проходов. Таким образом, в ситуации с серверами разных версий может возникнуть пробуксовка (thrashing) из-за разного представления серверов о правильном содержании этих объектов.
Каждый kube-apiserver
выполняет начальный проход по обязательным и опциональным объектам конфигурации, а затем периодически (раз в минуту) обходит их.
Для обязательных объектов обслуживание заключается в проверке того, что объект существует и имеет надлежащую спецификацию (spec). Сервер не разрешает создавать или обновлять объекты со spec, которая не соответствует его защитному поведению.
Обслуживание опциональных объектов конфигурации предусматривает возможность переопределения их спецификации (spec). Кроме того, удаление носит непостоянный характер: объект будет восстановлен в процессе обслуживания. Если опциональный объект конфигурации не нужен, его не нужно удалять, но достаточно настроить spec'и так, чтобы последствия были минимальными. Обслуживание опциональных объектов также рассчитано на поддержку автоматической миграции при выходе новой версии kube-apiserver
, при этом вероятны конфликты (thrashing), пока группировка серверов остается смешанной.
Обслуживание опционального объекта конфигурации предусматривает его создание — с рекомендуемой спецификацией сервера — если тот не существует. В то же время, если объект уже существует, поведение при обслуживании зависит от того, кто им управляет — kube-apiserver
'ы или пользователи. В первом случае сервер гарантирует, что спецификация объекта соответствует рекомендуемой; во втором случае спецификация не анализируется.
Чтобы узнать, кто управляет объектом, необходимо найти аннотацию с ключом apf.kubernetes.io/autoupdate-spec
. Если такая аннотация существует и ее значение равно true
, то объект контролируется kube-apiserver'ами. Если аннотация существует и ее значение равно false
, объект контролируется пользователями. Если ни одно из этих условий не выполняется, выполняется обращение к metadata.generation
объекта. Если этот параметр равен 1, объект контролируется kube-apiserver'ами. В противном случае объект контролируют пользователи. Эти правила были введены в версии 1.22, и использование metadata.generation
обусловлено переходом от более простого предыдущего поведения. Пользователи, желающие контролировать опциональный объект конфигурации, должны убедиться, что его аннотация apf.kubernetes.io/autoupdate-spec
имеет значение false
.
Обслуживание обязательного или опционального объекта конфигурации также предусматривает проверку наличия у него аннотации apf.kubernetes.io/autoupdate-spec
, которая позволяет понять, контролируют ли его kube-apiserver'ы.
Обслуживание также предусматривает удаление объектов, которые не являются ни обязательными, ни опциональными, но имеют аннотацию apf.kubernetes.io/autoupdate-spec=true
.
Освобождение проверок работоспособности от параллелизма
Опциональная конфигурация не предусматривает особого отношения к health check-запросам на kube-apiserver'ы от их локальных kubelet'ов. В данном случае обычно используется защищенный порт, но учетные данные не передаются. В опциональной конфигурации такие запросы относятся к FlowSchema global-default
и соответствующему уровню приоритета global-default
, где другой трафик может мешать их прохождению.
Чтобы освободить такие запросы от частотных ограничений, можно добавить FlowSchema, приведенную ниже.
Внимание: Добавление данной FlowSchema позволит злоумышленникам отправлять удовлетворяющие ей health-check-запросы в любом количестве. При наличии фильтра веб-трафика или аналогичного внешнего механизма безопасности для защиты API-сервера кластера от интернет-трафика можно настроить правила для блокировки любых health-check-запросов, поступающих из-за пределов кластера.
apiVersion: flowcontrol.apiserver.k8s.io/v1beta2
kind: FlowSchema
metadata:
name: health-for-strangers
spec:
matchingPrecedence: 1000
priorityLevelConfiguration:
name: exempt
rules:
- nonResourceRules:
- nonResourceURLs:
- "/healthz"
- "/livez"
- "/readyz"
verbs:
- "*"
subjects:
- kind: Group
group:
name: system:unauthenticated
Диагностика
Каждый HTTP-ответ от сервера API с включенной функцией РДА содержит два дополнительных заголовка: X-Kubernetes-PF-FlowSchema-UID
и X-Kubernetes-PF-PriorityLevel-UID
. В них указываются схема потока и уровень приоритета соответственно. Имена объектов API не включаются в эти заголовки на случай, если запрашивающий пользователь не обладает правами на их просмотр, поэтому при отладке можно использовать команду типа:
kubectl get flowschemas -o custom-columns="uid:{metadata.uid},name:{metadata.name}"
kubectl get prioritylevelconfigurations -o custom-columns="uid:{metadata.uid},name:{metadata.name}"
чтобы привязать UID к именам для FlowSchemas и PriorityLevelConfigurations.
Наблюдаемость
Метрики
Примечание: В Kubernetes до версии v1.20 лейблы flow_schema
и priority_level
также могли называться flowSchema
и priorityLevel
, соответственно. При использовании Kubernetes v1.19 и более ранних версий обратитесь к документации для соответствующей версии.
При включении функции равноправного доступа к API kube-apiserver начинает экспортировать дополнительные метрики. Их мониторинг помогает выявить негативное влияние (throttling) текущей конфигурации на важный трафик или найти неэффективные рабочие нагрузки, которые вредят здоровью системы.
apiserver_flowcontrol_rejected_requests_total
— вектор-счетчик (кумулятивный с момента запуска сервера) запросов, которые были отклонены, с разбивкой по лейблам flow_schema
(указывает на FlowSchema у запросов, попавших под соответствие), priority_level
(уровень приоритета, который был присвоен этим запросам) и reason
. Лейбл reason
будет иметь одно из следующих значений:
queue-full
— в очереди уже слишком много запросов;concurrency-limit
— PriorityLevelConfiguration настроена на отклонение, а не на постановку в очередь избыточных запросов;time-out
— запрос все еще находился в очереди, когда истек его лимит ожидания.
apiserver_flowcontrol_dispatched_requests_total
— вектор-счетчик (кумулятивный с момента запуска сервера) запросов, которые начали выполняться, сгруппированный по лейблам flow_schema
(указывает на FlowSchema у запросов, попавших под соответствие) и priority_level
(уровень приоритета, который был присвоен этим запросам).
apiserver_current_inqueue_requests
— вектор предыдущего максимума числа запросов в очереди, сгруппированных по лейблу request_kind
, значение которого mutating
или readOnly
. Эти максимумы описывают наибольшее число, наблюдавшееся в последнем завершенном односекундном окне. Они дополняют более старый вектор apiserver_current_inflight_requests
, который показывает максимум активно обслуживаемых запросов в последнем окне.
apiserver_flowcontrol_read_vs_write_request_count_samples
— вектор-гистограмма наблюдений за тогда-текущим количеством запросов с разбивкой по лейблам phase
(принимает значения waiting
и executing
) и request_kind
(принимает значения mutating
и readOnly
). Наблюдения проводятся периодически с высокой частотой. Каждое наблюдаемое значение представляет собой число в диапазоне от 0 до 1, равное отношению числа запросов к соответствующему ограничению на их количество (ограничение длины очереди в случае ожидания и лимит параллелизма в случае выполнения).
apiserver_flowcontrol_read_vs_write_request_count_watermarks
— вектор-гистограмма максимумов или минимумов количества запросов (число запросов, деленное на соответствующее ограничение) с разбивкой по лейблам phase
(принимает значения waiting
и executing
) и request_kind
(принимает значения mutating
и readOnly
); лейбл mark
принимает значения high
и low
. Минимумы и максимумы собираются в окнах, ограниченных временем, когда наблюдение было добавлено в apiserver_flowcontrol_read_vs_write_request_count_samples
. Эти экстремумы помогают определить разброс диапазона значений, наблюдавшийся в разных сэмплах.
apiserver_flowcontrol_current_inqueue_requests
— gauge-вектор, содержащий количество стоящих в очереди (не выполняющихся) запросов в каждый момент с разбивкой по лейблам priority_level
и flow_schema
.
apiserver_flowcontrol_current_executing_requests
— gauge-вектор, содержащий количество исполняемых (не ожидающих в очереди) запросов в каждый момент с разбивкой по лейблам priority_level
и flow_schema
.
apiserver_flowcontrol_request_concurrency_in_use
— gauge-вектор, содержащий количество занятых мест в каждый момент с разбивкой по лейблам priority_level
и flow_schema
.
apiserver_flowcontrol_priority_level_request_count_samples
— вектор-гистограмма наблюдений за текущим-на-тот-момент количеством запросов с разбивкой по лейблам phase
(принимает значения waiting
и executing
) и priority_level
. Каждая гистограмма получает наблюдения, сделанные периодически, вплоть до последней активности соответствующего рода. Наблюдения проводятся с высокой частотой. Каждое наблюдаемое значение представляет собой число в диапазоне от 0 до 1, равное отношению числа запросов к соответствующему ограничению на их количество (ограничение длины очереди в случае ожидания и лимит параллелизма в случае выполнения).
apiserver_flowcontrol_priority_level_request_count_watermarks
— вектор-гистограмма максимумов или минимумов количества запросов с разбивкой по лейблам phase
(принимает значения waiting
и executing
) и priority_level
; лейбл mark
принимает значения high
и low
. Минимумы и максимумы собираются в окнах, ограниченных временем, когда наблюдение было добавлено в apiserver_flowcontrol_priority_level_request_count_samples
. Эти экстремумы показывают диапазон значений, наблюдавшийся в разных сэмплах.
apiserver_flowcontrol_priority_level_seat_count_samples
— вектор-гистограмма наблюдений за использованием лимита параллелизма для уровня приоритета с разбивкой по priority_level
. Использование — отношение (количество занятых мест) / (предел параллелизма). Метрика учитывает все стадии выполнения (как обычную, так и дополнительную задержку в конце записи для покрытия соответствующей работы по уведомлению) всех запросов, кроме WATCHes; для этих запросов учитывается только начальная стадия по доставке уведомлений о ранее существующих объектах. Каждая гистограмма в векторе также помечена лейблом phase: executing
(количество мест для фазы ожидания не ограничено). Каждая гистограмма получает наблюдения, сделанные периодически, вплоть до последней активности соответствующего рода. Наблюдения производятся с высокой частотой.
apiserver_flowcontrol_priority_level_seat_count_watermarks
— вектор-гистограмма минимумов и максимумов использования предела параллелизма для уровня приоритета с разбивкой по priority_leve
и mark
(принимает значения high
и low
). Каждая гистограмма в векторе также помечена лейблом phase: executing
(для фазы ожидания предел на места отсутствует). Максимумы и минимумы собираются в окнах, ограниченных временем, когда наблюдение было добавлено в apiserver_flowcontrol_priority_level_seat_count_samples
. Эти экстремумы помогают определить разброс диапазона значений, наблюдавшийся в разных сэмплах.
apiserver_flowcontrol_request_queue_length_after_enqueue
— вектор-гистограмма длины очереди для очередей с разбивкой по лейблам priority_level
и flow_schema
как выборки по поставленным в очередь запросам. Каждый запрос при постановке в очередь вносит один сэмпл в гистограмму, сообщая о длине очереди сразу после добавления запроса. Обратите внимание, что это дает иную статистику, чем при объективном исследовании.
Примечание: В данном случае выброс в гистограмме означает, что, скорее всего, один поток (т.е. запросы от одного пользователя или для одного пространства имен, в зависимости от конфигурации) переполняет сервер API и "срезается" (throttled). И наоборот, если гистограмма одного уровня приоритета показывает, что все очереди для этого уровня приоритета длиннее, чем для других уровней приоритета, возможно, следует увеличить долю параллелизма для этого уровня приоритета в PriorityLevelConfiguration.
apiserver_flowcontrol_request_concurrency_limit
— gauge-вектор, содержащий вычисленный лимит параллелизма (основанный на общем лимите параллелизма сервера API и долях параллелизма PriorityLevelConfigurations), с разбивкой по лейблу priority_level
.
apiserver_flowcontrol_request_wait_duration_seconds
— вектор-гистограмма времени ожидания запросов в очереди с разбивкой по лейблам flow_schema
(указывает, какая схема соответствует запросу), priority_level
(указывает, к какому уровню был отнесен запрос) и execute
(указывает, начал ли запрос выполняться).
Примечание: Поскольку каждая FlowSchema всегда относит запросы к одному PriorityLevelConfiguration, можно сложить гистограммы для всех FlowSchema для одного уровня приоритета, чтобы получить эффективную гистограмму для запросов, отнесенных к этому уровню приоритета.
apiserver_flowcontrol_request_execution_seconds
— вектор-гистограмма времени, затраченного на выполнение запросов, с разбивкой по по лейблам flow_schema
(указывает, какая схема соответствует запросу) и priority_level
(указывает, к какому уровню был отнесен запрос).
apiserver_flowcontrol_watch_count_samples
— вектор-гистограмма количества активных запросов WATCH, относящихся к данной записи, с разбивкой по flow_schema
и priority_level
.
apiserver_flowcontrol_work_estimated_seats
— вектор-гистограмма количества предполагаемых мест (максимум начального и конечного этапа выполнения), связанных с запросами, с разбивкой по flow_schema
и priority_level
.
apiserver_flowcontrol_request_dispatch_no_accommodation_total
— вектор-счетчик количества событий, которые в принципе могли бы привести к отправке запроса, но не привели из-за отсутствия доступного параллелизма, с разбивкой по flow_schema
и priority_level
. Соответствующими событиями являются поступление запроса и завершение запроса.
Отладочные endpoint'ы
При включении функции равноправного доступа к API kube-apiserver
предоставляет следующие дополнительные пути на своих HTTP[S]-портах.
/debug/api_priority_and_fairness/dump_priority_levels
— список всех уровней приоритета и текущее состояние каждого из них. Получить его можно следующим образом:
kubectl get --raw /debug/api_priority_and_fairness/dump_priority_levels
Вывод выглядит примерно так:
PriorityLevelName, ActiveQueues, IsIdle, IsQuiescing, WaitingRequests, ExecutingRequests,
workload-low, 0, true, false, 0, 0,
global-default, 0, true, false, 0, 0,
exempt, <none>, <none>, <none>, <none>, <none>,
catch-all, 0, true, false, 0, 0,
system, 0, true, false, 0, 0,
leader-election, 0, true, false, 0, 0,
workload-high, 0, true, false, 0, 0,
/debug/api_priority_and_fairness/dump_queues
— список всех очередей и их текущее состояние. Получить его можно следующим образом:
kubectl get --raw /debug/api_priority_and_fairness/dump_queues
Вывод выглядит примерно так:
PriorityLevelName, Index, PendingRequests, ExecutingRequests, VirtualStart,
workload-high, 0, 0, 0, 0.0000,
workload-high, 1, 0, 0, 0.0000,
workload-high, 2, 0, 0, 0.0000,
...
leader-election, 14, 0, 0, 0.0000,
leader-election, 15, 0, 0, 0.0000,
/debug/api_priority_and_fairness/dump_requests
— список всех запросов, которые в настоящее время ожидают в очереди. Получить его можно следующим образом:
kubectl get --raw /debug/api_priority_and_fairness/dump_requests
Вывод выглядит примерно так:
PriorityLevelName, FlowSchemaName, QueueIndex, RequestIndexInQueue, FlowDistingsher, ArriveTime,
exempt, <none>, <none>, <none>, <none>, <none>,
system, system-nodes, 12, 0, system:node:127.0.0.1, 2020-07-23T15:26:57.179170694Z,
В дополнение к запросам, стоящим в очереди, вывод включает одну фантомную строку для каждого уровня приоритета, на которую не распространяется ограничение.
Более подробный список можно получить с помощью следующей команды:
kubectl get --raw '/debug/api_priority_and_fairness/dump_requests?includeRequestDetails=1'
Вывод выглядит примерно так:
PriorityLevelName, FlowSchemaName, QueueIndex, RequestIndexInQueue, FlowDistingsher, ArriveTime, UserName, Verb, APIPath, Namespace, Name, APIVersion, Resource, SubResource,
system, system-nodes, 12, 0, system:node:127.0.0.1, 2020-07-23T15:31:03.583823404Z, system:node:127.0.0.1, create, /api/v1/namespaces/scaletest/configmaps,
system, system-nodes, 12, 1, system:node:127.0.0.1, 2020-07-23T15:31:03.594555947Z, system:node:127.0.0.1, create, /api/v1/namespaces/scaletest/configmaps,
Что дальше
Для получения подробной информации о функции равноправного доступа к API см. предложение по улучшению (KEP). Предложения и запросы функционала принимаются через SIG API Machinery или в специализированном канале Slack.