Практическое руководство по аудиту ресурсов кластера Kubernetes
В этой статье мы разберем практические методы анализа ресурсного профиля кластера Kubernetes. Я покажу вам, как использовать встроенные инструменты для получения реальной картины потребления CPU и памяти вашими подами, и сравнить эти данные с заданными ограничениями. Эти знания критически важны для оптимизации производительности и затрат на инфраструктуру.
Зачем нужен аудит ресурсов?
Представьте ситуацию: ваши поды "падают" с ошибками OutOfMemory (OOM), планировщик не может разместить новые поды из-за нехватки ресурсов, или, наоборот, кластер простаивает с низкой утилизацией. Все эти проблемы связаны с неправильной настройкой ресурсных лимитов и запросов (requests/limits).
КогдаРегулярный выаудит указываетересурсов Pod,помогает:
Устранить сколькопроблемы каждогопроизводительности
Сократить Когда вы указываете запрос ресурса для контейнеров в Pod, kube-scheduler использует эту информацию для решения,затраты на какойинфраструктуру
Обеспечить Когдастабильность выработы указываетеприложений
Подготовка к аудиту
Перед началом работы убедитесь, что в вашем кластере установлен и функционирует Metrics Server. Metrics API предлагает базовый набор метрик для поддержки автоматического масштабирования и похожих случаев использования. Этот API делает доступной информацию об использовании ресурсов для узлов и подов, включая метрики CPU и памяти.
Проверить наличие Metrics Server можно командой:
kubectl get apiservice v1beta1.metrics.k8s.io
Если статус показывает True, можно приступать к работе. Если Metrics Server отсутствует, не переживайте — я покажу альтернативные способы получения метрик. Вы можете использовать Prometheus для долгосрочного анализа, если он пресутсвуют внутри вашей инфраструктуры .
Метод 1: kubectl top pods — быстрый обзор нагрузки
Команда kubectl top — это ваш первый инструмент для получения мгновенного снимка потребления ресурсов. Она работает через Metrics API и обращается к данным, собираемым kubelet'ами на каждом узле.
Базовое использование
# Показать использование ресурсов всех подов во всех namespace'ах
kubectl top pods --all-namespaces
# Показать детализацию по контейнерам
kubectl top pods --all-namespaces --containers
# Показать использование ресурсов узлов
kubectl top nodes
Практические примеры
Давайте разберем несколько полезных сценариев:
# Найти топ-10 подов по потреблению памяти в конкретном namespace
kubectl top pods -n production | sort -k3 -hr | head -10
# Показать только поды, потребляющие больше 500m CPU (милликор)
kubectl top pods --all-namespaces | awk 'NR==1 || $3 > 500'
# Показать поды с высоким потреблением памяти (больше 1Gi)
kubectl top pods --all-namespaces | awk 'NR==1 || $4~/[0-9]+Gi/ && $4+0 > 1'
Что показывают эти метрики:
- CPU — текущее потребление в ядрах (1000m = 1 ядро)
- Memory — рабочий набор памяти (working set) в мебибайтах
Важно понимать: kubectl top показывает моментальный снимок, а не среднее значение за период. Для получения более репрезентативных данных запускайте команду несколько раз в разное время.
Метод 2: Прямое обращение к kubelet Summary API
Если Metrics Server недоступен или вы хотите получить более детальную информацию, можно обратиться напрямую к Summary API kubelet'а.
Получение данных
Так как приведённая ниже команда может выполнить сбор summary статистики только с одного узла, то провести процедуру необходимо будет на всех узлах кластера с вашими pods.
# На узле кластера
curl -ks https:http://127.0.0.1:10250/8001/api/v1/nodes/$(hostname)/proxy/stats/summary > /tmp/summary.json
# Или с удаленного хоста (при наличии доступа)
curl -k https://<node-ip>:10250/stats/summary > /tmp/summary.json
Парсинг JSON-ответа
Summary API возвращает подробную статистику в JSON формате. Вот простой Python-скрипт для извлечения ключевых метрик:
#!/usr/bin/env python3
import json
import sys
def parse_kubelet_stats(filename):
with open(filename, 'r') as f:
data = json.load(f)
print(f'{"POD NAME":40} {"CPU (cores)":>12} {"Memory (MiB)":>15}')
print("-" * 70)
for pod in data.get("pods", []):
pod_name = pod["podRef"]["name"]
# Суммируем метрики по всем контейнерам пода
total_cpu = 0.0
total_memory = 0.0
for container in pod.get("containers", []):
cpu_usage = container.get("cpu", {}).get("usageNanoCores", 0)
memory_usage = container.get("memory", {}).get("workingSetBytes", 0)
total_cpu += cpu_usage / 1e9 # nanocores to→ cores
total_memory += memory_usage / (1024 * 1024) # bytes to→ MiB
print(f'{pod_name:40} {total_cpu:12.3f} {total_memory:15.0f}')
if __name__ == "__main__":
# ИспользованиеЕсли parse_kubelet_stats(имя файла передано аргументом — используем его, иначе — /tmp/summary.json
filename = sys.argv[1] if len(sys.argv) > 1 else "/tmp/summary.json")
parse_kubelet_stats(filename)
Преимущества метода
- Работает даже без Metrics Server
- Предоставляет более детальную статистику
- Включает метрики файловой системы и сети
- Не требует дополнительных компонентов в кластере
Ограничения
- Показывает данные только с одного узла
- Требует сетевого доступа к kubelet API
- Нужны соответствующие права доступа (RBAC)
Метод 3: Анализ requests и limits через kubectl describe
Теперь перейдем к анализу того, что было заявлено в спецификациях подов. Это критически важно для понимания разрыва между фактическим и планируемым потреблением ресурсов.
Получение информации о конкретном поде
# Детальная информация о поде
kubectl describe pod <pod-name> -n <namespace>
# Извлечение только секции Resources
kubectl describe pod <pod-name> -n <namespace> | grep -A 10 "Limits:\|Requests:"
Массовое извлечение данных с помощью JSONPath
Для анализа всех подов в namespace используйте JSONPath запросы:
# СозданиеЛибо CSVвыполните файлапоиск ссразу даннымипо о ресурсах
kubectl get pods -n <namespace> -o jsonpath='
NAME,CONTAINER,CPU_REQ,MEM_REQ,CPU_LIM,MEM_LIM
{range .items[*]}
{range .spec.containers[*]}
{$.metadata.name},{.name},{.resources.requests.cpu},{.resources.requests.memory},{.resources.limits.cpu},{.resources.limits.memory}
{"\n"}
{end}
{end}' > resources.csv
Более читаемый вариант вывода
# Скрипт для форматированного вывода
kubectl get pods -n default -o json | jq -r '
.items[] |
{
pod: .metadata.name,
containers: [
.spec.containers[] | {
name: .name,
requests: .resources.requests // {},
limits: .resources.limits // {}
}
]
} |
"\(.pod):\n" +
(.containers[] | " \(.name): req(\(.requests.cpu // "none")/\(.requests.memory // "none")) lim(\(.limits.cpu // "none")/\(.limits.memory // "none"))\n")
'
Проверка LimitRange
Не забывайте про объекты LimitRange, которые могут автоматически назначать дефолтные значения:
# Проверка LimitRange в namespaceвсем
kubectl describe limitrange -n <namespace>
# Просмотр всех LimitRange в кластере
kubectl get limitrangepods --all-namespaces \
| grep -E -A2 -B2 "Namespace:|Name:|Container:|Limits:|Requests:"
Метод 4: Использование docker stats для детальной диагностики
Если на узлах кластера используется Docker runtime, команда docker stats предоставляет детальную статистику контейнеров в реальном времени.
Основные команды
# Показать статистику всех запущенных контейнеров
docker stats
# Получить единичный снимок (без постоянного обновления)
docker stats --no-stream
# Показать статистику конкретных контейнеров
docker stats --no-stream $(docker ps --format "table {{.Names}}" | grep k8s)
Интерпретация вывода
Docker stats показывает следующие метрики:
- CPU % — процент использования CPU
- MEM USAGE/LIMIT — текущее использование памяти и лимит
- MEM % — процент от доступной памяти системы
- NET I/O — сетевой трафик
- BLOCK I/O — дисковые операции
Для containerd runtime
Если используется containerd, аналогичную информацию можно получить командой:
# Список всех задач
ctr -n k8s.io tasks list
# Метрики конкретной задачи
ctr -n k8s.io tasks metrics <task-id>
Практический пример: комплексный аудит
Давайте проведем пошаговый аудит реального namespace:
Шаг 1: СборПростой скрипт для сбора фактических метрик при наличии Metric Server
#!/bin/bash
# ПолучаемОдноразовый текущееснимок потребление«сейчас» в current_usage.txt
echo "TIMESTAMP NAME CONTAINER CPU(cores) MEMORY(bytes)" > current_usage.txt
kubectl top pods -n production-all-namespaces --containers --no-headers \
| awk -v D="$(date -Iseconds)" \
'{ printf "%-24s %-28s %-20s %12s %12s\n", D, $1, $2, $3, $4 }' \
>> current_usage.txt
# Собираем данныеСбор в течение часа длякаждые получения5 среднихминут значенийв usage_log.txt
echo "TIMESTAMP NAME CONTAINER CPU(cores) MEMORY(bytes)" > usage_log.txt
for i in {1..12}; do
echo "$(date): " >> usage_log.txt
kubectl top pods -n-all-namespaces production--containers --no-headers \
| awk -v D="$(date -Iseconds)" \
'{ printf "%-24s %-28s %-20s %12s %12s\n", D, $1, $2, $3, $4 }' \
>> usage_log.txt
sleep 300 # 5 минут
done
Шаг 2: Извлечение requests/limits
# Создаем подробный отчет
kubectl getdescribe pods -n-all-namespaces production -o json\
| jqgrep -rE '-A2 .items[] |
{
name: .metadata.name,
containers: [.spec.containers[] | {
name: .name,
cpu_req: .resources.requests.cpu //-B2 "none",
mem_req: .resources.requests.memory // Namespace:|Name:|Container:|Limits:|Requests:"none",
cpu_lim: .resources.limits.cpu // "none",
mem_lim: .resources.limits.memory // "none"
}]
} |
[.name, (.containers[0].cpu_req), (.containers[0].mem_req), (.containers[0].cpu_lim), (.containers[0].mem_lim)] |
@csv
' > pod_resources.csv
Шаг 3: Анализ расхождений
Создайте простую таблицу сравнения в Excel или используйте awk для базового анализа:
# Найти поды без установленных requests
kubectl get pods -n production -o json | jq -r '
.items[] |
select(.spec.containers[].resources.requests == null or .spec.containers[].resources.requests == {}) |
.metadata.name
'
# Найти поды с потреблением выше requests
# (требует комбинирования данных из kubectl top и describe)
Интерпретация результатов и рекомендации
Типичные проблемы и их решения
-
Завышенные requests
- Симптомы: низкая утилизация узлов, проблемы с планированием
- Решение: уменьшить requests на основе фактического потребления
-
Заниженные limits
- Симптомы: частые OOM kills, нестабильная работа приложений
- Решение: увеличить limits с учетом пиковых нагрузок
-
Отсутствие requests/limits
- Симптомы: непредсказуемое поведение кластера
- Решение: установить базовые значения, использовать LimitRange
Рекомендуемые практики
- Установите requests на уровне 75-80% от среднего потребления
- Установите limits на уровне 150-200% от requests для CPU
- Для памяти: limits должны быть близки к максимальному наблюдаемому потреблению
- Используйте Vertical Pod Autoscaler для автоматической оптимизации
Автоматизация процесса
Для регулярного мониторинга создайте простой скрипт:
#!/bin/bash
# audit_resources.sh
NAMESPACE=${1:-default}
OUTPUT_DIR="./audit_results_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$OUTPUT_DIR"
echo "Collecting metrics for namespace: $NAMESPACE"
# Сбор текущих метрик
kubectl top pods -n "$NAMESPACE" --containers > "$OUTPUT_DIR/current_usage.txt"
# Сбор информации о requests/limits
kubectl get pods -n "$NAMESPACE" -o json | jq -r '
.items[] | [
.metadata.name,
(.spec.containers[0].resources.requests.cpu // "none"),
(.spec.containers[0].resources.requests.memory // "none"),
(.spec.containers[0].resources.limits.cpu // "none"),
(.spec.containers[0].resources.limits.memory // "none")
] | @csv
' > "$OUTPUT_DIR/pod_resources.csv"
# Проверка LimitRange
kubectl describe limitrange -n "$NAMESPACE" > "$OUTPUT_DIR/limitranges.txt" 2>/dev/null
echo "Audit completed. Results saved in: $OUTPUT_DIR"
Заключение
Регулярный аудит ресурсов кластера Kubernetes — это не разовая задача, а постоянный процесс оптимизации. Используя описанные методы, вы сможете:
- Выявить неэффективное использование ресурсов
- Предотвратить проблемы с производительностью
- Оптимизировать затраты на инфраструктуру
- Обеспечить стабильную работу приложений
Помните: мониторинг ресурсов должен сочетаться с пониманием специфики ваших приложений. Не всегда математически оптимальные значения являются лучшими с точки зрения надежности системы.
Начните с базового аудита раз в неделю, постепенно автоматизируя процесс и внедряя более сложные инструменты мониторинга по мере роста вашего кластера.