← все статьи
10 марта 2026· 12 мин чтения· #kubernetes · #ops

Kubernetes в проде: уроки эксплуатации

Поднять кластер легко. Сложности начинаются на втором году, когда нагрузка выросла, а кто-то забыл выставить лимиты. Собрал то, что чаще всего болит.

Kubernetes на демо и Kubernetes под реальной банковской нагрузкой — это два разных мира. В первом всё работает само. Во втором ты узнаёшь о проблемах в 3 часа ночи. За несколько лет эксплуатации production-кластеров я собрал список вещей, которые ломаются чаще всего — и почти все они про дисциплину, а не про экзотику.

1. Probes, которые врут

Самая частая боль — неправильно настроенные liveness и readiness probes. Классическая ошибка: liveness-проба ходит в эндпоинт, который зависит от БД. База тормозит → проба падает → Kubernetes перезапускает под → нагрузка на оставшиеся реплики растёт → каскадный отказ.

Liveness отвечает на вопрос «жив ли процесс». Readiness — «готов ли он принимать трафик». Путать их — значит превращать временную деградацию в полный отказ.
livenessProbe:        # только сам процесс, без внешних зависимостей
  httpGet: { path: /actuator/health/liveness, port: 8443 }
  initialDelaySeconds: 30
  periodSeconds: 10
readinessProbe:       # учитывает БД, очереди и т.п.
  httpGet: { path: /actuator/health/readiness, port: 8443 }
  periodSeconds: 5
  failureThreshold: 3

2. Ресурсы: requests и limits — не формальность

Под без requests планировщик ставит куда угодно; под без limits может съесть память соседей и спровоцировать OOM на ноде. Мы взяли за правило: у каждого пода заданы и requests, и limits, а значения берём не из головы, а из метрик реального потребления.

3. Stateful-приложения требуют уважения

Запускать базу данных в Kubernetes можно — но только понимая, во что ввязываешься. StatefulSet, правильные PersistentVolume с подходящим storage class, аккуратные стратегии обновления и, снова, проверенные бэкапы. Если данные критичны и команда небольшая — иногда честнее держать БД вне кластера. Это не поражение, а трезвая оценка рисков.

4. Сеть: deny by default

По умолчанию в Kubernetes любой под может ходить в любой другой — для банковской среды это неприемлемо. Мы внедрили NetworkPolicy с принципом deny-by-default: явно разрешён только нужный трафик, остальное закрыто.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: default-deny, namespace: prod }
spec:
  podSelector: {}
  policyTypes: [ Ingress, Egress ]   # дальше точечно открываем нужное

Поверх — Ingress с TLS-терминацией, rate limiting и нормальными таймаутами. Открытый наружу сервис без ограничений рано или поздно найдут.

5. Логи и метрики: пока не видишь — не управляешь

Дебажить kubectl logs по отдельным подам не масштабируется. Мы свели всё в централизованное логирование (ELK / OpenSearch) и метрики в Prometheus + Grafana. Алерты завязаны на симптомы, которые чувствует пользователь (рост latency, ошибки 5xx), а не на каждый чих инфраструктуры — иначе дежурный перестаёт реагировать на алерты вообще.

# симптом, а не причина: пользователь видит ошибки
- alert: HighErrorRate
  expr: sum(rate(http_requests_total{status=~"5.."}[5m]))
        / sum(rate(http_requests_total[5m])) > 0.02
  for: 5m
  labels: { severity: page }

6. Обновления кластера — это проект, а не команда

Апгрейд версии Kubernetes мы планируем как отдельную задачу: читаем changelog на предмет deprecated API, прогоняем на стейдже, обновляем ноды по одной с drain и контролем PodDisruptionBudget. Спешка здесь стоит дороже всего.

Итог: скучная эксплуатация — это успех

Kubernetes даёт огромную силу, но вместе с ней — много способов выстрелить себе в ногу. Почти все инциденты, что я разбирал, сводились к пропущенным базовым вещам: probes, ресурсы, сеть, наблюдаемость. Хорошая эксплуатация выглядит скучно — и именно в этом её ценность.

KubernetesprobesNetworkPolicy PrometheusOpenSearchStatefulSet