Администрирование кластера

Lower-level detail relevant to creating or administering a Kubernetes cluster.

Обзор администрирования кластера предназначен для всех, кто создает или администрирует кластер Kubernetes. Это предполагает некоторое знакомство с основными концепциями Kubernetes.

Планирование кластера

См. Руководства в разделе настройка для получения примеров того, как планировать, устанавливать и настраивать кластеры Kubernetes. Решения, перечисленные в этой статье, называются distros.

Примечание:

не все дистрибутивы активно поддерживаются. Выбирайте дистрибутивы, протестированные с последней версией Kubernetes.

Прежде чем выбрать руководство, вот некоторые соображения:

Управление кластером

Обеспечение безопасности кластера

Обеспечение безопасности kubelet

Дополнительные кластерные услуги

1 - Сертификаты

Чтобы узнать, как генерировать сертификаты для кластера, см. раздел Сертификаты.

2 - Управление ресурсами

Итак, вы развернули приложение и настроили доступ к нему с помощью сервиса. Что дальше? Kubernetes предоставляет ряд инструментов, помогающих управлять развертыванием приложений, включая их масштабирование и обновление. Среди особенностей, которые мы обсудим более подробно, — конфигурационные файлы и лейблы.

Организация конфигураций ресурсов

Многие приложения требуют создания нескольких ресурсов типа Deployment и Service. Управление ими можно упростить, сгруппировав в один YAML-файл (со строкой "---" в качестве разделителя). Например:

application/nginx-app.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    app: nginx
spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Можно создавать сразу несколько ресурсов:

kubectl apply -f https://k8s.io/examples/application/nginx-app.yaml
service/my-nginx-svc created
deployment.apps/my-nginx created

Ресурсы будут создаваться в порядке, в котором они описаны в файле. Таким образом, первым лучше всего описать сервис — это позволит планировщику распределять Pod'ы этого сервиса по мере их создания контроллером (контроллерами), например, Deployment'ом.

kubectl apply также может принимать сразу несколько аргументов -f:

kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml

Кроме того, можно указывать директории вместо отдельных файлов или в дополнение ним:

kubectl apply -f https://k8s.io/examples/application/nginx/

kubectl прочитает все файлы с расширениями .yaml, .yml или .json.

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

Также в качестве источника конфигурации можно указать URL — это удобно при создании/настройке с использованием конфигурационных файлов, размещенных на GitHub:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx created

Пакетные операции в kubectl

Создание ресурсов — не единственная операция, которую kubectl может выполнять в рамках одной команды. Этот инструмент также способен извлекать имена ресурсов из конфигурационных файлов для выполнения других операций, в частности, для удаления созданных ресурсов:

kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted

В случае двух ресурсов их можно перечислить в командной строке, используя синтаксис вида resource/name:

kubectl delete deployments/my-nginx services/my-nginx-svc

При большем количестве ресурсов удобнее указать селектор (запрос по лейблу) с помощью -l или --selector, который отфильтрует ресурсы по их лейблам:

kubectl delete deployment,services -l app=nginx
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted

Поскольку kubectl выводит имена ресурсов в том же синтаксисе, что и получает, можно выстраивать цепочки операций с помощью $() или xargs:

kubectl get $(kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service)
kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service | xargs -i kubectl get {}
NAME           TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)      AGE
my-nginx-svc   LoadBalancer   10.0.0.208   <pending>     80/TCP       0s

Приведенные выше команды сначала создают ресурсы в разделе examples/application/nginx/, выводят о них информацию в формате -o name (то есть в виде пары resource/name). Затем в результатах производится поиск по "service" (grep), и информация о найденных ресурсах выводится с помощью kubectl get.

Если ресурсы хранятся в нескольких поддиректориях в пределах одной директории, можно рекурсивно выполнять операции и в этих поддиректориях, указав --recursive или -R наряду с флагом --filename, -f.

Предположим, что существует директория project/k8s/development, в которой хранятся все манифесты, необходимые для dev-окружения, организованные по типу ресурсов:

project/k8s/development
├── configmap
│   └── my-configmap.yaml
├── deployment
│   └── my-deployment.yaml
└── pvc
    └── my-pvc.yaml

По умолчанию при выполнении массовых операций над project/k8s/development команда остановится на первом уровне, не обрабатывая поддиректории. К примеру, попытка создать ресурсы, описанные в этой директории, приведет к ошибке:

kubectl apply -f project/k8s/development
error: you must provide one or more resources by argument or filename (.json|.yaml|.yml|stdin)

Вместо этого следует указать флаг --recursive или -R с флагом --filename, -f:

kubectl apply -f project/k8s/development --recursive
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created

Флаг --recursive работает с любыми операциями, принимающими флаг --filename, -f, например: kubectl {create, get, delete, describe, rollout} и т.д.

Флаг --recursive также работает для нескольких аргументов -f:

kubectl apply -f project/k8s/namespaces -f project/k8s/development --recursive
namespace/development created
namespace/staging created
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created

В разделе Инструмент командной строки kubectl доступна дополнительная информация о kubectl.

Эффективное использование лейблов

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

Например, разные приложения могут использовать разные значения для лейбла app, а в случае многоуровневого приложения вроде гостевой книги лейблы могут указывать на соответствующий уровень. Например, у фронтенда могут быть следующие лейблы:

     labels:
        app: guestbook
        tier: frontend

в то время как у master'а и slave'а Redis будут лейблы tier и, возможно, даже дополнительный лейбл role:

     labels:
        app: guestbook
        tier: backend
        role: master

и

     labels:
        app: guestbook
        tier: backend
        role: slave

Лейблы позволяют группировать ресурсы по любому параметру с соответствующим лейблом:

kubectl apply -f examples/guestbook/all-in-one/guestbook-all-in-one.yaml
kubectl get pods -Lapp -Ltier -Lrole
NAME                           READY     STATUS    RESTARTS   AGE       APP         TIER       ROLE
guestbook-fe-4nlpb             1/1       Running   0          1m        guestbook   frontend   <none>
guestbook-fe-ght6d             1/1       Running   0          1m        guestbook   frontend   <none>
guestbook-fe-jpy62             1/1       Running   0          1m        guestbook   frontend   <none>
guestbook-redis-master-5pg3b   1/1       Running   0          1m        guestbook   backend    master
guestbook-redis-slave-2q2yf    1/1       Running   0          1m        guestbook   backend    slave
guestbook-redis-slave-qgazl    1/1       Running   0          1m        guestbook   backend    slave
my-nginx-divi2                 1/1       Running   0          29m       nginx       <none>     <none>
my-nginx-o0ef1                 1/1       Running   0          29m       nginx       <none>     <none>
kubectl get pods -lapp=guestbook,role=slave
NAME                          READY     STATUS    RESTARTS   AGE
guestbook-redis-slave-2q2yf   1/1       Running   0          3m
guestbook-redis-slave-qgazl   1/1       Running   0          3m

Канареечные развертывания

Еще один сценарий, в котором применение нескольких лейблов как нельзя кстати, — дифференциация развертываний отдельных релизов или конфигураций одного и того же компонента. Как правило, новая версия приложения (указанная с помощью тега образа в шаблоне Pod'а) запускается в так называемом канареечном (canary) развертывании параллельно с предыдущей версией. Далее на нее направляется часть реального production-трафика.

В примере ниже лейбл track помогает различить релизы.

У основного, стабильного релиза он будет иметь значение stable:

     name: frontend
     replicas: 3
     ...
     labels:
        app: guestbook
        tier: frontend
        track: stable
     ...
     image: gb-frontend:v3

У нового релиза фронтенда гостевой книги значение этого лейбла будет другим (canary), чтобы два набора Pod'ов не пересекались:

     name: frontend-canary
     replicas: 1
     ...
     labels:
        app: guestbook
        tier: frontend
        track: canary
     ...
     image: gb-frontend:v4

Чтобы охватить оба набора реплик, сервис фронтенда следует настроить на выбор общего подмножества их лейблов (т.е. опустить лейбл track). В результате трафик будет поступать на обе версии приложения:

  selector:
     app: guestbook
     tier: frontend

При этом число стабильных и канареечных реплик можно менять, регулируя долю production-трафика, которую будет получать каждая версия приложения (три к одному в нашем случае). Убедившись в стабильности новой версии, можно поменять значение ее лейбла track с canary на stable.

Более подробный пример доступен в руководстве по развертыванию Ghost.

Обновление лейблов

Иногда возникает необходимость поменять лейблы у существующих Pod'ов и других ресурсов перед созданием новых. Сделать это можно с помощью команды kubectl label. Например, чтобы промаркировать все Pod'ы NGINX как имеющие отношение к фронтенду, выполните следующую команду:

kubectl label pods -l app=nginx tier=fe
pod/my-nginx-2035384211-j5fhi labeled
pod/my-nginx-2035384211-u2c7e labeled
pod/my-nginx-2035384211-u3t6x labeled

Сначала она выберет все Pod'ы с лейблом app=nginx, а затем пометит их лейблом tier=fe. Чтобы просмотреть список этих Pod'ов, выполните:

kubectl get pods -l app=nginx -L tier
NAME                        READY     STATUS    RESTARTS   AGE       TIER
my-nginx-2035384211-j5fhi   1/1       Running   0          23m       fe
my-nginx-2035384211-u2c7e   1/1       Running   0          23m       fe
my-nginx-2035384211-u3t6x   1/1       Running   0          23m       fe

Будут выведены все Pod'ы app=nginx с дополнительным столбцом tier (задается с помощью -L или --label-columns).

Дополнительную информацию можно найти в разделах Лейблы и kubectl label.

Обновление аннотаций

Иногда возникает потребность навесить на ресурсы аннотации. Аннотации — это произвольные неидентифицирующие метаданные для извлечения клиентами API (инструментами, библиотеками и т.п.). Добавить аннотацию можно с помощью команды kubectl annotate. Например:

kubectl annotate pods my-nginx-v4-9gw19 description='my frontend running nginx'
kubectl get pods my-nginx-v4-9gw19 -o yaml
apiVersion: v1
kind: pod
metadata:
  annotations:
    description: my frontend running nginx
...

Для получения дополнительной информации обратитесь к разделу Аннотации и описанию команды kubectl annotate.

Масштабирование приложения

Для масштабирования приложения можно воспользоваться инструментом kubectl. Например, следующая команда уменьшит число реплик с 3 до 1:

kubectl scale deployment/my-nginx --replicas=1
deployment.apps/my-nginx scaled

После ее применения количество Pod'ов под управлением соответствующего объекта Deployment сократится до одного:

kubectl get pods -l app=nginx
NAME                        READY     STATUS    RESTARTS   AGE
my-nginx-2035384211-j5fhi   1/1       Running   0          30m

Чтобы система автоматически выбирала необходимое количество реплик NGINX в диапазоне от 1 до 3, выполните следующую команду:

kubectl autoscale deployment/my-nginx --min=1 --max=3
horizontalpodautoscaler.autoscaling/my-nginx autoscaled

Теперь количество реплик NGINX будет автоматически увеличиваться и уменьшаться по мере необходимости.

Для получения дополнительной информации см. разделы kubectl scale, kubectl autoscale и horizontal pod autoscaler.

Обновление ресурсов "на месте"

Иногда возникает необходимость внести мелкие обновления в созданные ресурсы, не требующие их пересоздания.

kubectl apply

Хранить конфигурационные файлы рекомендуемтся в системе контроля версий (см. конфигурация как код). В этом случае их можно будет поддерживать и версионировать вместе с кодом ресурсов, которые те конфигурируют. Далее с помощью команды kubectl apply изменения, внесенные в конфигурацию, можно применить к кластеру.

Она сравнит новую версию конфигурации с предыдущей и применит внесенные изменения, не меняя параметры, установленные автоматически, не затронутые новой редакцией конфигурации.

kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured

Обратите внимание, что kubectl apply добавляет к ресурсу аннотацию, помогающую отслеживать изменения в конфигурации с момента предыдущего вызова. При вызове kubectl apply проводит трехстороннее сравнение (three-way diff) предыдущей конфигурации, ее текущей и новой версий, которое определяет, какие правки следует внести в ресурс.

На данный момент ресурсы в Kubernetes создаются без данной аннотации, поэтому при первом вызове kubectl apply проведет двустороннее сравнение входных данных и текущей конфигурации ресурса. Кроме того, она не cможет определить, какие свойства, заданные при создании ресурса, требуют удаления (соответственно, не будет их удалять).

При всех последующих вызовах kubectl apply и других команд, меняющих конфигурацию, таких как kubectl replace и kubectl edit, аннотация будет обновляться. В результате kubectl apply сможет проводить трехстороннее сравнение (three-way diff), определяя, какие свойства требуют удаления, и удалять их.

kubectl edit

Ресурсы также можно обновлять с помощью команды kubectl edit:

kubectl edit deployment/my-nginx

По сути, kubectl edit объединяет в себе логику нескольких команд, упрощая жизнь пользователям: сначала она получает (get) ресурс, вызывает текстовый редактор, а затем применяет (apply) обновленную конфигурацию:

kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml
vi /tmp/nginx.yaml
# внесите правки и сохраните файл

kubectl apply -f /tmp/nginx.yaml
deployment.apps/my-nginx configured

rm /tmp/nginx.yaml

Обратите внимание, что задать предпочитаемый текстовый редактор можно с помощью переменных окружения EDITOR или KUBE_EDITOR.

За дополнительной информацией обратитесь к разделу kubectl edit.

kubectl patch

Команда kubectl patch обновляет объекты API "на месте". Она поддерживает форматы JSON patch, JSON merge patch и strategic merge patch. См. разделы Обновление объектов API "на месте" с помощью kubectl patch и kubectl patch.

Обновления, требующие перерыва в работе

Иногда может понадобиться обновить поля ресурса, которые нельзя изменить после инициализации, или возникнет необходимость немедленно внести рекурсивные изменения, например, "починить" сбойные Pod'ы, созданные Deployment'ом. Для этого можно воспользоваться командой replace --force, которая удалит и пересоздаст ресурс. Вот как можно внести правки в исходный файл конфигурации в нашем примере:

kubectl replace -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml --force
deployment.apps/my-nginx deleted
deployment.apps/my-nginx replaced

Обновление приложения без перерыва в работе

В какой-то момент возникнет необходимость обновить развернутое приложение. Обычно это делают, указывая новый образ или тег образа, как в приведенном выше сценарии канареечного развертывания. kubectl поддерживает несколько видов обновлений, каждый из которых подходит для разных сценариев.

Ниже будет рассказано, как создавать и обновлять приложения с помощью объектов Deployment.

Предположим, что в кластере используется версия NGINX 1.14.2:

kubectl create deployment my-nginx --image=nginx:1.14.2
deployment.apps/my-nginx created

с тремя репликами (чтобы старые и новые ревизии могли сосуществовать):

kubectl scale deployment my-nginx --current-replicas=1 --replicas=3
deployment.apps/my-nginx scaled

Чтобы перейти на версию 1.16.1, измените значение параметра .spec.template.spec.containers[0].image с nginx:1.14.2 на nginx:1.16.1:

kubectl edit deployment/my-nginx

Вот и все! Deployment декларативно обновит развернутое приложение NGINX "за кулисами". При этом Kubernetes проследит, чтобы число недоступных реплик в каждый момент времени не превышало определенного значения, а также за тем, чтобы количество новых реплик не превышало определенного предела, установленного для желаемого числа Pod'ов. Более подробную информацию об этом можно получить в разделе Deployment.

Что дальше

3 - Сеть в кластере

Сеть — важная часть Kubernetes, но понять, как именно она работает, бывает непросто. Существует 4 уникальных сетевых проблемы, которые требуют внимнаия:

  1. Высокосвязанные коммуникации между контейнерами: решается организацией коммуникации между Pod'ами и localhost.
  2. Связь Pod'ов друг с другом (Pod-to-Pod): именно ей уделяется основное внимание в этом документе.
  3. Связь Pod'ов с сервисами (Pod-to-Service): подробнее об этом можно почитать в разделе Сервисы.
  4. Связь внешних систем с сервисами (External-to-Service): информация о данных коммуникациях также приведена в разделе Сервисы.

Суть Kubernetes — в организации совместного использования хостов приложениями. Обычно совместное использование подразумевает, что два приложения не могут задействовать одни и те же порты. Создать единую глобальную схему использования портов очень сложно. В результате пользователи рискуют получить сложноустранимые проблемы на уровне кластера.

Динамическое распределение портов значительно усложняет систему: каждое приложение должно уметь принимать порты в виде флагов-параметров, серверы API должны уметь вставлять динамические номера портов в конфигурационные блоки, сервисы должны знать, как найти друг друга и т.п. Вместо того чтобы пытаться разобраться со всем этим, Kubernetes использует иной подход.

Больше узнать о сетевой модели Kubernetes можно в соответствующем разделе.

Реализация сетевой модели Kubernetes

Сетевая модель реализуется средой исполнения для контейнеров на узлах. Наиболее распространенные среды исполнения используют плагины Container Network Interface (CNI) для управления сетью и обеспечения безопаснояти коммуникаций. Существует множество различных плагинов CNI от разных разработчиков. Некоторые из них предлагают только базовые функции, такие как добавление и удаление сетевых интерфейсов. Другие позволяют проводить интеграцию с различныеми системами оркестрации контейнеров, поддерживают запуск нескольких CNI-плагинов/расширенные функции IPAM и т.д.

Неполный список сетевых аддонов, поддерживаемых Kubernetes, приведен на соответствующей странице в разделе "Сеть и сетевая политика".

Что дальше

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

4 - Архитектура для сбора логов

Логи помогают понять, что происходит внутри приложения. Они особенно полезны для отладки проблем и мониторинга деятельности кластера. У большинства современных приложений имеется тот или иной механизм сбора логов. Контейнерные движки в этом смысле не исключение. Самый простой и наиболее распространенный метод сбора логов для контейнерных приложений задействует потоки stdout и stderr.

Однако встроенной функциональности контейнерного движка или среды исполнения обычно недостаточно для организации полноценного решения по сбору логов.

Например, может возникнуть необходимость просмотреть логи приложения при аварийном завершении работы Pod'а, его вытеснении (eviction) или "падении" узла.

В кластере у логов должно быть отдельное хранилище и жизненный цикл, не зависящий от узлов, Pod'ов или контейнеров. Эта концепция называется сбор логов на уровне кластера.

Архитектуры для сбора логов на уровне кластера требуют отдельного бэкенда для их хранения, анализа и выполнения запросов. Kubernetes не имеет собственного решения для хранения такого типа данных. Вместо этого существует множество продуктов для сбора логов, которые прекрасно с ним интегрируются. В последующих разделах описано, как обрабатывать логи и хранить их на узлах.

Основы сбора логов в Kubernetes

В примере ниже используется спецификация Pod с контейнером для отправки текста в стандартный поток вывода раз в секунду.

debug/counter-pod.yaml
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

Результат будет таким:

pod/counter created

Получить логи можно с помощью команды kubectl logs, как показано ниже:

kubectl logs counter

Результат будет таким:

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 вернет второй лог-файл (пустой).

Логи системных компонентов

Существует два типа системных компонентов: те, которые работают в контейнере, и те, которые работают за пределами контейнера. Например:

На машинах с systemd среда исполнения и kubelet пишут в journald. Если systemd отсутствует, среда исполнения и kubelet пишут в файлы .log в директории /var/log. Системные компоненты внутри контейнеров всегда пишут в директорию /var/log, обходя механизм ведения логов по умолчанию. Они используют библиотеку для сбора логов klog. Правила сбора логов и рекомендации можно найти в соответствующей документации.

Как и логи контейнеров, логи системных компонентов в директории /var/log необходимо ротировать. В кластерах Kubernetes, созданных с помощью скрипта kube-up.sh, эти файлы настроены на ежедневную ротацию с помощью инструмента logrotate или при достижении 100 МБ.

Архитектуры для сбора логов на уровне кластера

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

Использование агента на уровне узлов

Использование агента на уровне узлов

Сбор логов на уровне кластера можно реализовать, запустив node-level-агент на каждом узле. Лог-агент — это специальный инструмент, который предоставляет доступ к логам или передает их бэкенду. Как правило, лог-агент представляет собой контейнер с доступом к директории с файлами логов всех контейнеров приложений на этом узле.

Поскольку лог-агент должен работать на каждом узле, рекомендуется запускать его как DaemonSet.

Сбор логов на уровне узла предусматривает запуск одного агента на узел и не требует изменений в приложениях, работающих на узле.

Контейнеры пишут в stdout и stderr, но без согласованного формата. Агент на уровне узла собирает эти логи и направляет их на агрегацию.

Сбор логов с помощью sidecar-контейнера с лог-агентом

Sidecar-контейнер можно использовать одним из следующих способов:

Транслирующий sidecar-контейнер

Sidecar-контейнер с транслирующим контейнером

Настроив sidecar-контейнеры на вывод в их собственные потоки stdout и stderr, можно воспользоваться преимуществами kubelet и лог-агента, которые уже работают на каждом узле. Sidecar-контейнеры считывают логи из файла, сокета или journald. Затем каждый из них пишет логи в собственный поток stdout или stderr.

Такой подход позволяет разграничить потоки логов от разных частей приложения, некоторые из которых могут не поддерживать запись в stdout или stderr. Логика, управляющая перенаправлением логов, проста и не требует значительных ресурсов. Кроме того, поскольку stdout и stderr обрабатываются kubelet'ом, можно использовать встроенные инструменты вроде kubectl logs.

Предположим, к примеру, что в Pod'е работает один контейнер, который пишет логи в два разных файла в двух разных форматах. Вот пример конфигурации такого Pod'а:

admin/logging/two-files-counter-pod.yaml
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-контейнерами:

admin/logging/two-files-counter-pod-streaming-sidecar.yaml
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-контейнер с отдельным лог-агентом, специально настроенным на работу с приложением.

Примечание:

Работа лог-агента в sidecar-контейнере может привести к значительному потреблению ресурсов. Более того, доступ к этим журналам с помощью kubectl logs будет невозможен, поскольку они не контролируются kubelet'ом.

Ниже приведены два файла конфигурации sidecar-контейнера с лог-агентом. Первый содержит ConfigMap для настройки fluentd.

admin/logging/fluentd-sidecar-config.yaml
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.

admin/logging/two-files-counter-pod-agent-sidecar.yaml
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.

5 - Логи системных компонентов

Логи системных компонентов регистрируют события, происходящие в кластере, что может быть очень полезно при отладке. Степень детализации логов настраивается. Так, в логах низкой детализации будет содержаться только информация об ошибках внутри компонента, в то время как логи высокой детализации будут содержать пошаговую трассировку событий (доступ по HTTP, изменения состояния Pod'а, действия контроллера, решения планировщика).

Klog

klog — библиотека Kubernetes для сбора логов. Отвечает за генерацию соответствующих сообщений для системных компонентов оркестратора.

Дополнительные сведения о настройке klog можно получить в Справке по CLI.

В настоящее время ведется работа по упрощению процесса сбора логов в компонентах Kubernetes. Приведенные ниже флаги командной строки klog устарели, начиная с версии Kubernetes 1.23, и будут удалены в одном из будущих релизов:

Вывод всегда будет записываться в 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"
}

Специальные ключи:

Список компонентов, поддерживающих формат JSON:

Уровень детализации лога

Флаг -v задает степень детализации лога. Увеличение значения увеличивает количество регистрируемых событий. Уменьшение значения уменьшает количество регистрируемых событий. Увеличение детализации приводит к тому, что регистрируются все менее значимые события. При уровне детализации, равном 0, регистрируются только критические события.

Местоположение лога

Существует два типа системных компонентов: те, которые работают в контейнере, и те, которые работают за пределами контейнера. Например:

На машинах с systemd среда исполнения и kubelet пишут в journald. В противном случае ведется запись в файлы .log в директории /var/log. Системные компоненты внутри контейнеров всегда пишут в файлы .log в директории /var/log, обходя механизм логирования по умолчанию. Как и логи контейнеров, логи системных компонентов в /var/log нуждаются в ротации. В кластерах Kubernetes, созданных с использованием скрипта kube-up.sh, ротация логов настраивается с помощью инструмента logrotate. logrotate ротирует логи ежедневно или при достижении ими размера в 100 МБ.

Что дальше

6 - Типы прокси-серверов в Kubernetes

На этой странице рассказывается о различных типах прокси-серверов, которые используются в Kubernetes.

Прокси-серверы

При работе с Kubernetes можно столкнуться со следующими типами прокси-серверов:

  1. kubectl:

  2. Прокси-сервер API:

  3. kube proxy:

  4. Прокси-сервер/балансировщик нагрузки перед API-сервером(-ами):

  5. Облачные балансировщики нагрузки на внешних сервисах:

Пользователи Kubernetes, как правило, в своей работе сталкиваются только с прокси-серверами первых двух типов. За настройку остальных типов обычно отвечает администратор кластера.

Запросы на перенаправления

На смену функциям перенаправления (редиректам) пришли прокси-серверы. Перенаправления устарели.

7 - Равноправный доступ к 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 означает, что запросы, превышающие пороговое значение, будут поставлены в очередь, при этом для балансировки прогресса между потоками запросов будут использоваться методы тасования между шардами и равноправных очередей.

Конфигурация очередей позволяет настроить алгоритм равноправных очередей для каждого уровня приоритета. Подробности об алгоритме можно узнать из предложения по улучшению; если вкратце:

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

Конфигурации shuffle sharding
handSize Число очередей 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 поддерживает два вида объектов конфигурации РДА: обязательные и рекомендуемые.

Обязательные объекты конфигурации

Четыре обязательных объекта конфигурации отражают защитное поведение, встроенное в серверы. Оно реализуется независимо от этих объектов; параметры последних просто его отражают.

Опциональные объекты конфигурации

Опциональные объекты FlowSchemas и PriorityLevelConfigurations образуют оптимальную конфигурацию по умолчанию. При желании их можно изменить и/или создать дополнительные объекты конфигурации. Если велика вероятность высокой нагрузки на кластер, следует решить, какая конфигурация будет работать лучше всего.

Опциональная конфигурация группирует запросы по шести уровням приоритета:

Опциональные 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-запросов, поступающих из-за пределов кластера.
priority-and-fairness/health-for-strangers.yaml
apiVersion: flowcontrol.apiserver.k8s.io/v1beta3
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) текущей конфигурации на важный трафик или найти неэффективные рабочие нагрузки, которые вредят здоровью системы.

Отладочные endpoint'ы

При включении функции равноправного доступа к API kube-apiserver предоставляет следующие дополнительные пути на своих HTTP[S]-портах.

Что дальше

Для получения подробной информации о функции равноправного доступа к API см. предложение по улучшению (KEP). Предложения и запросы функционала принимаются через SIG API Machinery или в специализированном канале Slack.

8 - Установка дополнений

Примечание: Этот раздел ссылается на сторонние проекты, реализующие функциональность, которая требуется Kubernetes. Авторы Kubernetes не несут ответственность за проекты, представленные здесь в алфавитном порядке. Чтобы добавить проект к этому списку, ознакомьтесь с руководством по контенту перед публикацией изменений. Подробнее.

Надстройки расширяют функциональность Kubernetes.

На этой странице перечислены некоторые из доступных надстроек и ссылки на соответствующие инструкции по установке.

Сеть и сетевая политика

Обнаружение служб

Визуализация и контроль

Инфраструктура

Legacy Add-ons

В устаревшем каталоге cluster/addons задокументировано несколько других дополнений.

Ссылки на те, в хорошем состоянии, должны быть здесь. Пул реквесты приветствуются!