{ "index": 127, "slug": "editorial-2024-06-field-container-orchestration", "title": "Kubernetes без ложных сигналов: как связать ресурсы, readiness и HPA", "excerpt": "После релиза Pod может быть Unready, CPU — высоким, а HPA — не менять число реплик. Разбираем, какой контур породил симптом, чем его проверить и когда изменение манифеста действительно готово.", "contentHtml": "

После обновления образа часть Pod-ов долго остаётся Unready. В графике растёт CPU. Команда предлагает увеличить maxReplicas и CPU limit. Это может не изменить ни одного симптома. Readiness управляет допуском Pod к трафику Service. HPA рассчитывает реплики по метрике. Scheduler размещает Pod по requests. Runtime применяет limits. Один Pod, четыре контура.

\n

Цена ошибки — не только лишние ресурсы. Новый Pod может не пройти readiness из-за зависимости. HPA может не считать CPU, если у контейнера нет request. Увеличенный limit может скрыть рост памяти до следующего отказа. Если изменить все поля сразу, команда потеряет причинную связь. Она не узнает, что именно сработало и какой риск остался.

\n

Тезис. Сначала нужно назвать контракт сигнала, затем проверить его источником того же типа. Не называйте Ready доказательством capacity. Не называйте CPU percentage самостоятельным числом. Не называйте значение из учебной модели показанием кластера.

\n

Механизм: четыре контура вместо одной «нагрузки»

\n

Request задаёт reservation contract. Scheduler учитывает requests контейнеров при выборе Node. Для одного ресурса request Pod складывается из requests его контейнеров. Это не прогноз постоянного потребления. Это условие размещения.

\n

Limit задаёт границу ресурса для контейнера. CPU и memory ведут себя по-разному. CPU limit может ограничивать выполнение. Memory limit не превращается в прогноз пикового потребления и не объясняет lifetime cache или batch buffer. Нельзя вывести безопасные значения из одного универсального коэффициента.

\n

Readiness отвечает на другой вопрос: можно ли отправлять трафик этому Pod сейчас. Когда Pod не готов, Service не должен использовать его как backend. Readiness probe не обязана объяснять причину. Readiness gate добавляет named condition, но не задаёт ей смысл. Владелец приложения должен определить producer, переход в True и путь восстановления.

\n

HPA формирует предложение по числу реплик из метрики и target. CPU utilization — процент относительно CPU request контейнеров, которые попали в выборку. Если relevant request отсутствует, controller не может получить такой utilization для контейнера. Значит, строка target: 65 без request не является рабочим scaling contract.

\n
apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: api\nspec:\n  replicas: 2\n  template:\n    spec:\n      containers:\n        - name: api\n          image: registry.example/api@sha256:...\n          resources:\n            requests:\n              cpu: 500m\n              memory: 256Mi\n            limits:\n              cpu: \"1\"\n              memory: 512Mi\n          startupProbe:\n            httpGet:\n              path: /startup\n              port: 8080\n          readinessProbe:\n            httpGet:\n              path: /ready\n              port: 8080\n          readinessGates:\n            - conditionType: example.com/SchemaReady\n---\napiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n  name: api\nspec:\n  scaleTargetRef:\n    apiVersion: apps/v1\n    kind: Deployment\n    name: api\n  minReplicas: 2\n  maxReplicas: 10\n  metrics:\n    - type: Resource\n      resource:\n        name: cpu\n        target:\n          type: Utilization\n          averageUtilization: 70
\n

Фрагмент учебный. Образ, пути probes, custom condition и значения ресурсов нельзя переносить в production без profile приложения и проверки среды. В манифесте видно главное: HPA percentage имеет denominator requests.cpu: 500m. Readiness gate не становится HPA metric. Limit 1 не меняет denominator HPA.

\n

Симптом → причина → проверка → действие

\n
Диагностическая матрица для одного workload
СимптомВозможная причинаПроверкаДействие
Pod Unready после релизаProbe или gate не выполняет контракт; зависимость ещё не готоваСопоставить condition, probe event и смысл ReadyИсправить owner и recovery path; не увеличивать replicas автоматически
CPU высокий, HPA не меняет репликиНет CPU request, нет metrics API или выбран другой target typeПроверить effective request, HPA status и источник метрикиСначала восстановить denominator или метрику; не рисовать scale policy по одному графику
Memory близка к limitРост cache, batch, retained object или неверный limitОпределить lifetime памяти и проверить runtime evidenceОграничить владельца роста; отделить memory action от CPU HPA
Новые Pod запускаются, но трафик не растётReadiness false, gate не становится True или Service не видит endpointПроверить Pod condition и endpoints разрешённым способомПроверить traffic contract; не считать создание Pod доказательством capacity
Процент выглядит убедительно только в fixtureСинтетическое число приняли за telemetryПроверить источник и marker данныхОграничить вывод учебной моделью и запросить реальное evidence отдельно
\n

Конкретный пример: почему request меняет смысл процента

\n

Пусть CPU request равен 500m, а HPA target — 70%. В модели controller это означает usage около 350m на Pod для целевой точки. Это 70% request, а не 70% Node и не 70% CPU limit. Если request изменить на 1000m, тот же target будет означать другую рабочую точку. Одновременно Scheduler начнёт резервировать больше CPU. Одно изменение затронет placement и interpretation метрики.

\n

Теперь уберём request. Значение synthetic CPU 600m всё ещё выглядит конкретно, но процент больше не имеет объявленного denominator. Корректный verdict — «нельзя интерпретировать utilization», а не «нужно больше Pod». В этом отрицательном пути отсутствие действия HPA — ожидаемый результат проверки контракта. Сначала нужно определить serving unit, для которой request имеет смысл, и подтвердить состояние metrics API в разрешённой среде.

\n

Другой пример — memory. Если synthetic observation показывает 470Mi при limit 512Mi, это не доказывает OOM, eviction, restart или throttling. Без runtime event это только учебное значение рядом с границей. Следующий вопрос относится к владельцу памяти: cache, batch buffer, response aggregation или connection pool. Readiness false при этом остаётся отдельным сигналом traffic, а не именем причины memory pressure.

\n
\"Схема
Учебная схема показывает две границы. Readiness определяет traffic eligibility. HPA использует свою метрику и свой denominator. Asset не описывает состояние реального кластера.
\n

Как проверять безопасно

\n

Проверка должна отвечать на один вопрос и использовать один тип evidence. Условие Pod, HPA status, metrics API, controlled request и runtime event не взаимозаменяемы. Если источник не разрешён, его отсутствие фиксируют как blocker. Не подменяйте его значением из fixture, screenshot или случайным графиком.

\n
  1. Ограничьте scope. Выберите один Deployment, owner, среду, период и разрешённые источники. Не начинайте с массового изменения Pod.
  2. Снимите декларацию. Выпишите requests и limits для каждого контейнера. Отдельно зафиксируйте startup, readiness, gates, HPA metric, target и min/max.
  3. Опишите profile. Назовите serving unit, startup work, concurrency, dominant resource, dependency policy и точный смысл Ready.
  4. Проверьте denominator. Для utilization найдите relevant request и effective values после admission. Если request отсутствует, остановите процентный вывод.
  5. Разделите сигналы. Сопоставьте readiness с traffic, metric с replica proposal, limit с runtime boundary, request с placement. Запишите, чего каждый сигнал не доказывает.
  6. Выберите одну гипотезу. Назначьте один evidence source, ожидаемый результат и stop condition. Не меняйте request, probe и HPA в одном эксперименте.
  7. Проверьте отрицательный путь. Зафиксируйте, что произойдёт при missing request, false gate, stale metric или memory growth. Отсутствие решения иногда и есть корректный результат.
  8. Закройте изменение. Сохраните observed result, owner, ограничение и rollback snapshot. Повторите исходный вопрос тем же типом evidence.
\n

Что не должна делать учебная fixture

\n

Учебный код может держать три фиксированные карточки в памяти: steady serving с request, memory growth с false readiness и warmup без request. Он может проверять, что synthetic value не получила ярлык telemetry и что внешний field отклоняется. Он не должен читать kubeconfig, namespace, файл манифеста, CI, HTTP, trace или production. Комментарий syntheticObservedPodBehavior должен прямо говорить, что это не kubectl и не metrics API.

\n
const card = {\n  id: 'fixed-warmup-request-missing-v1',\n  declared: { cpuRequest: null, cpuTarget: 65 },\n  observed: {\n    kind: 'embedded-fixed-js-object-not-telemetry',\n    ready: false,\n    cpu: '600m'\n  }\n};\n\nconst verdict = card.declared.cpuRequest === null\n  ? 'block-utilization-conclusion'\n  : 'compare-with-request';\n\nconsole.log(verdict);\n// Учебная модель. Нет cluster, file, CI, HTTP или production data.
\n

Для этой карточки корректен verdict block-utilization-conclusion. Код не говорит, сколько реплик нужно реальному сервису. Он проверяет только отрицательную ветку: процент без request нельзя честно объяснить. Production-инструмент требует отдельной авторизации, источника данных и правил изменения. Учебный пример эти полномочия не получает.

\n

Ограничения и rollback

\n

Материал не выбирает размер Node, ratio CPU и memory, значения probes, тип custom metric или безопасный maxReplicas. Он не видит admission webhooks, quotas, EndpointSlice, runtime cgroups, Metrics Server, custom adapter, logs, traces и downstream dependencies. Официальная семантика Kubernetes не заменяет проверку конкретного кластера.

\n

Rollback должен возвращать snapshot декларации и проверять side effects. Откат HPA не исправляет неверный readiness contract. Возврат limit не объясняет рост памяти. Изменение probe не восстанавливает потерянные evidence. Для каждого изменения укажите owner, условие остановки, временную границу и наблюдаемый критерий отката.

\n

Критерий готовности. Изменение готово, если profile назван, у каждого сигнала есть источник и owner, CPU utilization имеет declared request, Ready имеет отдельный traffic contract, synthetic данные не выданы за production, а отрицательная ветка приводит к остановке или явному blocker. Кроме того, команда может повторить исходную проверку тем же типом evidence и получить объяснимый результат. Если хотя бы одна строка отвечает «кажется», манифест не готов.

\n

Проверяемые источники

\n" }