Задача 9. Прожорливый etcd

Кластер начинает тормозить на всех операциях kubectl, хотя ноды свободны. Разбираем лимит объекта в 1.5 МиБ, квоту базы в 2 ГиБ, историю ревизий и почему ConfigMap в цикле роняет control plane.
Опубликовано:

Задача

kubectl get pods отрабатывает по несколько секунд. Создание объектов иногда падает по таймауту. При этом ноды почти не загружены, а рабочие нагрузки продолжают работать.

В логах API server — сообщения о медленных запросах к etcd.

Вопрос: что могло привести к такому состоянию и почему рабочие нагрузки при этом живы?

Что кажется очевидным

«Не хватает ресурсов control plane, надо добавить CPU мастерам».

Иногда помогает, но чаще причина в другом — в том, что и как пишут в etcd.

Как это работает на самом деле

etcd — распределённое key-value хранилище, единственный источник правды для всего кластера. В нём лежит каждый объект: поды, ConfigMap’ы, секреты, события, CRD.

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

Ключевые ограничения, о которые бьются:

1. Размер одного объекта — около 1.5 МиБ. Это лимит на запись в etcd. Попытка создать ConfigMap или Secret крупнее упрётся в ошибку. Соблазн «положить датасет/сертификаты/бинарник в ConfigMap» разбивается об это ограничение — и правильно.

2. Размер базы — по умолчанию 2 ГиБ (--quota-backend-bytes, максимум рекомендуемый — 8 ГиБ). При достижении квоты etcd переходит в режим только для чтения и весь кластер перестаёт принимать изменения. Это самый неприятный сценарий.

3. etcd хранит историю ревизий. Каждое изменение объекта создаёт новую ревизию, старые остаются до компакции. Объект, который обновляется в цикле, генерирует тысячи ревизий и раздувает базу — даже если сам объект маленький и его текущий размер не меняется.

4. Watch-и рассылают изменения. На каждое изменение объекта API server рассылает событие всем подписчикам (kubelet, контроллеры, операторы). Горячо обновляемый объект создаёт нагрузку не только на etcd, но и на всех наблюдателей.

5. etcd чувствителен к диску. Он делает fsync на каждую запись — медленный или «плавающий» по латентности диск напрямую превращается в тормоза всего кластера.

Типичные виновники

Ответ

Скорее всего, что-то интенсивно пишет в etcd: контроллер в цикле обновления, лавина событий или крупные часто обновляемые объекты. База растёт, история ревизий не успевает компактиться, латентность записи растёт — и все операции API замедляются. Нагрузки живы, потому что зависят от kubelet, а не от etcd.

Что с этим делать

Диагностика

BASH
# Размер базы и состояние узлов
etcdctl endpoint status --write-out=table --cluster

# Сколько объектов каждого типа (частый источник сюрпризов)
kubectl get events -A --no-headers | wc -l
kubectl get secrets -A --no-headers | wc -l

# Метрики API server: что пишется чаще всего
# etcd_object_counts / apiserver_storage_objects
kubectl get --raw /metrics | grep apiserver_storage_objects | sort -t' ' -k2 -rn | head -20
Нажмите, чтобы развернуть и увидеть больше

Последняя команда обычно и указывает на виновника: если объектов одного типа десятки тысяч, вопрос закрыт.

Лечение и профилактика


Дальше: Задача 10. HPA: почему автомасштабирование не срабатывает.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша