Эффективные ресурсы подов
Эффективные ресурсы подов
Запросы и лимиты ресурсов для CPU и памяти можно задавать на уровне контейнера, на уровне init-контейнера, а начиная с Kubernetes 1.34 — на уровне пода. Поскольку разные типы контейнеров работают в разное время, вычисление эффективного лимита на уровне пода нелинейно: простое суммирование всех лимитов контейнеров даёт неверный результат во многих реальных подах.
Ключ-АСТРОМ вычисляет правильное эффективное значение во время приёма данных и корректирует метрику так, чтобы агрегированные представления по подам, рабочим нагрузкам, пространствам имён и кластерам всегда отражали то, что Kubernetes фактически применяет.
Применяется только к мониторингу Latest. Требуется мониторинг Kubernetes через АктивныйШлюз.
Если сервисная сетка, такая как Istio, настроена на использование нативных sidecar-контейнеров, эти sidecar-контейнеры принимаются и суммируются корректно в АктивныйШлюз версии 1.339+. Поды, использующие более ранние версии Istio (до 1.24 или с 1.24 по 1.26 без явной настройки), использовали app-контейнеры для прокси, которые уже учитывались. Обновление Istio до версии 1.27+ (где нативные sidecar-контейнеры используются по умолчанию) без одновременного обновления до АктивныйШлюз версии 1.339+ приведёт к тому, что ресурсы sidecar-контейнеров будут отсутствовать в метрике.
| Сценарий | АктивныйШлюз версии 1.339+ | АктивныйШлюз версии 1.343+ | АктивныйШлюз версии 1.345+ |
|---|---|---|---|
| App-контейнеры | ✓ | ✓ | ✓ |
| Нативные sidecar-контейнеры (restartPolicy: Always) | ✓ | ✓ | ✓ |
| Init-контейнеры (добавлена компенсирующая дельта) | — | ✓ | ✓ |
| Ресурсы уровня пода (spec.resources) — Kubernetes 1.34+ (добавлена компенсирующая дельта) | — | — | ✓ |
| Накладные расходы пода (overhead в RuntimeClass) (добавлена компенсирующая дельта) | — | — | ✓ |
Как Kubernetes вычисляет эффективные лимиты подов
Kubernetes определяет три типа контейнеров с различными окнами жизненного цикла. Поскольку они работают не одновременно, их вклад в ресурсы нельзя просто суммировать.
Следующий пример показывает под с двумя init-контейнерами и одним app-контейнером. kubectl describe pod сообщает лимиты каждого контейнера по отдельности; он не вычисляет эффективный лимит на уровне пода.
Init Containers:
init-step-1:
Limits: cpu: 50m memory: 32Mi
init-step-2:
Limits: cpu: 100m memory: 60Mi
Containers:
app:
Limits: cpu: 4m memory: 32Mi
Эффективный лимит необходимо вывести вручную:
- CPU: MAX(MAX(50m, 100m), 4m) = 100m
- Память: MAX(MAX(32Mi, 60Mi), 32Mi) = 60Mi
| Тип | Когда работает | Вклад в эффективный лимит пода |
|---|---|---|
| App-контейнер | Весь жизненный цикл пода | Добавляется к SUM фазы выполнения |
| Нативный sidecar-контейнер (restartPolicy: Always) | Запускается во время init-фазы, работает весь жизненный цикл пода | Добавляется к SUM фазы выполнения |
| Init-контейнер | Последовательно до запуска app-контейнеров, затем завершается | Вносит вклад в MAX init-фазы |
spec.resources уровня пода
|
Н/Д — бюджет, применяемый ко всему поду | Может ограничить эффективный лимит; может увеличить эффективный запрос |
Нативные sidecar-контейнеры — это init-контейнеры с restartPolicy: Always, доступные с Kubernetes 1.29. В отличие от классических init-контейнеров, они не завершаются до запуска приложения — они сохраняются на весь жизненный цикл пода и работают одновременно с app-контейнерами.
Эффективный лимит пода для ресурса:
effective limit = MAX(
SUM(app containers + sidecar containers), // running phase
MAX(each init container + sidecars running before it) // init phase
)
Если задан лимит на уровне пода и он ниже суммы фазы выполнения, Kubernetes применяет ограничение на уровне пода.
Спецификация ресурсов на уровне пода (spec.resources, feature gate PodLevelResources) — это бета-функция, включённая по умолчанию с версии Kubernetes 1.34. Некоторые веб-консоли и kubectl describe node пока не учитывают ресурсы уровня пода при отображении; значения там могут не отражать то, что применяет Kubernetes.
Как Ключ-АСТРОМ обеспечивает точность
Ключ-АСТРОМ хранит метрики ресурсов на уровне контейнера (dt.kubernetes.container.limits_cpu, dt.kubernetes.container.requests_memory и так далее), чтобы сохранить гранулярность по контейнерам. Для большинства подов агрегирование этих метрик по контейнерам даёт правильный итог по поду.
Когда простое агрегирование дало бы неверный эффективный лимит, во время приёма данных в ту же метрику добавляется компенсирующая дельта. Эта дельта делает агрегированный итог правильным, не изменяя отдельные точки данных контейнеров.
Используя тот же пример пода, запрос dt.kubernetes.container.limits_cpu по контейнеру показывает:
| k8s.container.name | k8s.container.type | cpu_millicore | mem_mib |
|---|---|---|---|
| app | app | 4 | 32 |
| (компенсирующая дельта) | — | 96 | 28 |
| Итого (сумма) | 100 | 60 |
Строка компенсирующей дельты не имеет имени или типа контейнера. Суммирование по всем строкам даёт правильный эффективный лимит пода, который применяет Kubernetes.
Значение дельты:
- Положительное, когда пик init-фазы (init-контейнеры + уже работающие sidecar-контейнеры) превышает сумму фазы выполнения, или когда запрос уровня пода выше суммы контейнеров.
- Отрицательное, когда лимит CPU или памяти уровня пода ограничивает итог ниже суммы контейнеров. Это применяется только к лимитам; Kubernetes не позволяет запросам уровня пода быть ниже суммы контейнеров.
Точка данных компенсирующей дельты не имеет размерности dt.smartscape.container. Её dt.smartscape_source.type — K8S_POD, даже когда дельта происходит из init-контейнера. Это позволяет при необходимости отличать её в запросах.
Нативные sidecar-контейнеры не требуют компенсирующей дельты. Поскольку они работают весь жизненный цикл пода, их вклад линеен и суммируется напрямую со значениями app-контейнеров.
Проверка расчёта
Чтобы проверить, сохраняются ли точки данных компенсирующей дельты, выполните запрос по размерностям, связанным с контейнером. k8s.cluster.name и подобные атрибуты — это свойства сущности, а не размерности метрики; используйте поля dt.smartscape.* для группировки и идентификации дельт. Строки, где dt.smartscape.container отсутствует, — это точки данных компенсирующей дельты.
timeseries sum(dt.kubernetes.container.limits_memory),
by: { dt.smartscape.k8s_pod, dt.smartscape.container, k8s.container.type }
Чтобы ограничить конкретной рабочей нагрузкой, начните с метрики и присоедините контекст сущности из Smartscape. Присвойте псевдонимы полям k8s.* внутри подзапроса lookup.
timeseries sum(dt.kubernetes.container.limits_memory), by: { dt.smartscape.k8s_pod, dt.smartscape.container, k8s.container.type } | lookup [
smartscapeNodes "*" | filter type == "K8S_POD" | fields id, cluster = k8s.cluster.name, ns = k8s.namespace.name, wl = k8s.workload.name ], sourceField: dt.smartscape.k8s_pod, lookupField: id| fieldsAdd cluster = lookup.cluster, ns = lookup.ns, wl = lookup.wl | filter cluster == "<cluster-name>" and ns == "<namespace>" and wl == "<workload>" | fields dt.smartscape.k8s_pod, dt.smartscape.container, k8s.container.type, cluster, ns, wl
Если компенсирующая дельта отсутствует, проверьте версию АктивныйШлюз и значения свойств.