Как решить проблему нехватки ресурсов (CPU/Memory) в Kubernetes-кластере?

«Как решить проблему нехватки ресурсов (CPU/Memory) в Kubernetes-кластере?» — вопрос из категории Kubernetes, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В моей практике решение проблемы нехватки ресурсов — это итеративный процесс, а не разовое действие.

1. Оптимизация существующих рабочих нагрузок (самый быстрый эффект):

  • Анализ и настройка requests/limits: Часто limits завышены "на всякий случай", а requests не отражают реальное потребление. Используем kubectl top pods и метрики из Prometheus (например, через Grafana) для анализа.
    # Пример реалистичных requests/limits после анализа
    resources:
      requests:
        memory: "256Mi"
        cpu: "100m"
      limits:
        memory: "512Mi"  # Не ставлю в 2Gi, если пиковое потребление 450Mi
        cpu: "500m"
  • Вертикальное масштабирование (VPA): На проектах с динамичной нагрузкой настраивал Vertical Pod Autoscaler в режиме updateMode: "Off" (только рекомендации) или "Auto". VPA анализирует историю потребления и предлагает/применяет оптимальные requests.

2. Горизонтальное масштабирование:

  • HPA (Horizontal Pod Autoscaler): Настраивал на кастомные метрики (например, длину очереди сообщений в RabbitMQ) или на стандартные (CPU/Memory). Важно, чтобы приложение было stateless или имело механизм сессий.
    # HPA на основе CPU
    metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
  • Кластер-автоскейлер (Cluster Autoscaler): Интегрировал с облачным провайдером (AWS, GCP). Он автоматически добавляет ноды в пул, когда появляются pending pods из-за нехватки ресурсов, и удаляет пустые ноды для экономии.

3. Увеличение ёмкости кластера:

  • Вручную добавить ноду в пул (через Terraform/провайдера).
  • Оптимизировать планировщик: Использовал nodeSelector, taints/tolerations, podAntiAffinity чтобы равномерно распределять нагрузку и изолировать "прожорливые" приложения.

4. Архитектурные изменения (долгосрочные):

  • Оптимизация образов: Переход на alpine-based образы, многостадийные сборки в Dockerfile для уменьшения размера.
  • Вынос состояния: Перенос кэшей (Redis), баз данных, файловых хранилищ за пределы кластера (managed-сервисы) или в StatefulSets с выделенными PVC.
  • Ревизия: Регулярный аудит на наличие "зомби"-подов, неиспользуемых сервисов, дублирующих deployment'ов.

Ключевой инструмент — мониторинг. Без Grafana-дашбордов, отображающих kube_pod_container_resource_requests/limits, node_memory_MemAvailable_bytes и алертов на KubeCPUOvercommit, KubeMemoryOvercommit — работа вслепую.