Модуль 35. Анти-паттерны и частые ошибки
Цель — превратить «непонятно почему ломается» в системную профилактику: чек-листы, политики и алерты. На выходе у вас будут шаблоны для выявления и устранения ошибок в неймспейсах, ресурсах, хранилище, сетевой публикации и конфигурации.
Карта анти-паттернов (коротко)
|
Группа |
Анти-паттерн |
Чем опасно |
|---|---|---|
|
Организация |
Хаотичные namespaces |
Смешение команд/окружений, риски доступа, конфликт имён |
|
Ресурсы |
Нет requests/limits |
OOM, CPU-throttling, нестабильность HPA/CA |
|
Хранилище |
Данные в emptyDir/hostPath |
Потеря данных при перезапуске/эвакуации |
|
Сеть |
«Избыточный» Ingress / без единой точки |
Цепочки редиректов, ломкие TLS, сложный контроль доступа |
|
Конфиги |
Хардкод в образах/env |
Секреты в логах/репо, боль при ротации |
|
Доставки |
В обход GitOps / kubectl edit в проде |
Дрифт, непредсказуемые изменения |
|
Доступы |
Container привилегии, PSP-наследие |
Эскалация прав, несоответствие аудитам |
|
Нагрузка |
CronJob/Job «кладбище» |
Захламление API, перерасход ресурсов |
|
Высокая доступность |
Нет PDB/anti-affinity |
Даунтайм при drain/апгрейде |
|
Образы |
Тег :latest, неподписанные |
Неидемпотентность, supply-chain риски |
|
Сеть/безопасность |
Нет NetworkPolicy |
Плоская сеть, «все со всеми» |
|
Мониторинг |
Без SLI/SLO/алертов |
«Кажется тормозит», позднее обнаружение проблем |
|
Хранилище (BI/DWH) |
RWX/NFS под БД/Trino-локальные |
Блокировки, деградация I/O |
Далее — подробно: симптомы → как найти → как исправить, с нюансами для BI/DWH.
Хаотичные namespaces
Симптомы: «prod-сервис» живёт рядом с тестовыми; роли RBAC размыты; команды мешают друг другу.
Как найти:
- Инвентаризация kubectl get ns --show-labels; ищите ns без меток env/team/owner.
- Проверьте ResourceQuota/LimitRange/NetworkPolicy — часто их просто нет.
Как исправить (без даунтайма):
- Ввести конвенцию: env={dev,stage,prod}, team, owner, cost-center.
- Создать базовый пакет на ns: Quota + LimitRange + default deny NetworkPolicy + PodSecurity.
- Через GitOps мигрировать ресурсы по ns (пошагово: копия → трафик → удаление старого).
Риск-уровень: высокий (контроль доступа, расходы).
Отсутствие requests/limits
Симптомы: периодические OOM/eviction; HPA «пилит»; CA не скейлит, хотя «всё тормозит».
Как найти:
- kubectl get deploy -A -o json | jq '.items[] | select(.spec.template.spec.containers[]? | has("resources")|not) | .metadata.namespace + "/" + .metadata.name'
- Метрики container_cpu_cfs_throttled_seconds_total, OOMKilled события.
Как исправить:
- Снять фактическое потребление (неделя), выбрать requests≈p50–p70, limits для памяти с запасом, для CPU — под профиль.
- Задать LimitRange на ns (минимумы/максимумы).
- Включить VPA (RecommendOnly/Initial); применять рекомендации через GitOps.
Риск-уровень: очень высокий (нестабильность).
Данные в emptyDir / hostPath
Симптомы: теряете BI-экспорт/кеши при рестарте; stateful-сервисы «ломаются» после drain.
Как найти:
- kubectl get pod -A -o json | jq '.. | objects | select(has("emptyDir")) | .metadata.name'
- Обход чартов: поиск emptyDir:/hostPath:.
Как исправить:
- Для данных — PVC с RWO (StorageClass WaitForFirstConsumer), ReclaimPolicy=Retain.
- emptyDir — только для временных (scratch), аккуратнее с размером (ephemeral storage).
- Для «кешей» BI — либо emptyDir с лимитом, либо tiered storage (локально + S3).
Риск-уровень: критичный (потеря данных).
Избыточный Ingress и «запутанная» публикация
Симптомы: двойные редиректы, 4xx/5xx, истёкшие сертификаты; конфликты путей.
Как найти:
- Скан Ingress на пересекающиеся host/path; устаревшие аннотации; сертификаты без auto-renew.
- Ошибки в Ingress-контроллере, всплески tls handshake error.
Как исправить:
- Консолидация входной точки: один IngressClass/Gateway на домен, разделение путей/вирт-хостов.
- TLS через cert-manager, автоматическое продление; единые секреты через ESO/Vault.
- Чёткие правила NetworkPolicy: доступ к backend только от Ingress-ns.
Риск-уровень: средне/высокий (доступность).
Хардкод конфигов и секретов
Симптомы: ключи в Git/логах; боль при ротации; разный конфиг Dev/Prod.
Как найти:
- Греп по репо на password=, AKIA, BEGIN PRIVATE KEY; контейнеры без ConfigMap/Secret зависимостей.
- Секреты в env без источников ротации.
Как исправить:
- Конфиг — в ConfigMap, секреты — из Vault/External Secrets Operator/Secrets Store CSI.
- Разнести «статус окружения» на оверлеи Helm/Kustomize; GitOps-промо Dev→Stage→Prod.
- Включить политику «запрет env с ключевыми словами» (Kyverno/Gatekeeper).
Риск-уровень: критичный (безопасность).
В обход GitOps
Симптомы: «у меня локально применилось, а на стенде — нет»; diff между кластером и Git.
Как найти:
- Сравнение kubectl get … -o yaml vs Git; отчёты Argo/Flux о дрейфе.
- История ручных kubectl edit/apply в audit-логе.
Как исправить:
- Всё — через PR/Argo/Flux.
- Ввести SSA (kubectl apply --server-side), единый fieldManager.
- На время инцидента — «break-glass» процесс с немедленным PR-фиксацией.
Риск-уровень: высокий (предсказуемость, аудит).
Нет PDB/anti-affinity
Симптомы: drain ноды роняет сервис; HA-БД теряет кворум.
Как найти:
- Поиск контроллеров без PodDisruptionBudget; проверка podAntiAffinity/TopologySpread.
- Инциденты «во время апгрейда пропал сервис».
Как исправить:
- Ввести PDB на StatefulSet/Deployment (мин. доступные/макс. недоступные).
- Развести реплики по нодам/зонам: podAntiAffinity + TopologySpreadConstraints.
- Тест: «chaos-drain» и замер SLO.
Риск-уровень: высокий (доступность).
Тег :latest и неподписанные образы
Симптомы: «на стенде один код, в проде — другой»; атаки через подмену образа.
Как найти:
- Поиск image: .*:latest; отсутствие проверки подписи/cosign.
- Нет политики запрета :latest.
Как исправить:
- Фиксированные теги/дигесты; release-процесс.
- cosign-подписи, проверка в admission.
- Политика «запрет :latest», «запрет pull из неутверждённых реестров».
Риск-уровень: высокий (supply-chain).
Нет NetworkPolicy (плоская сеть)
Симптомы: любой Pod достаёт любой; трудно локализовать утечки.
Как найти:
- Нейспейсы без NP; отсутствие default-deny.
Как исправить:
- Ввести default-deny ingress+egress во всех prod-ns.
- Разрешить только DNS/Ingress/мониторинг и нужные сервис-to-сервис.
- Покрыть тестами «policy-probe».
Риск-уровень: высокий (безопасность).
CronJob/Job «кладбище»
Симптомы: тысячи завершённых job/подов; API медленнее; диски заняты логами.
Как найти:
- Высокий kube_job_* счетчик; CronJob без successful/failedJobsHistoryLimit, Job без ttlSecondsAfterFinished.
Как исправить:
- concurrencyPolicy (Forbid/Replace), startingDeadlineSeconds.
- ttlSecondsAfterFinished, history limits.
- podFailurePolicy — не ретраить «плохие данные».
Риск-уровень: средний (эксплуатация/стоимость).
Анти-паттерны хранилища для BI/DWH
Симптомы: БД/ClickHouse на RWX/NFS; Trino spill на медленных томах; PITR не делается.
Как найти:
- PV с ReadWriteMany для stateful; отсутствие бэкап-CronJob.
Как исправить:
- Для БД/CH — RWO-блок (Ceph RBD/облачные диски), XFS/ext4, SC WaitForFirstConsumer, Retain.
- Бэкапы: pgBackRest/WAL-G, clickhouse-backup → S3; регулярный restore-день.
- Trino — spill на быстрые локальные, лимиты и мониторинг.
Риск-уровень: критичный (целостность/производительность).
Как ставить «защитные бордюры» (превентивно)
Политики (идея, компактно):
- Запрет :latest и обязательные resources (Kyverno/Gatekeeper).
- Pod Security (baseline/restricted) вместо PSP.
- Admission-правила: запрет privileged, hostPID/hostNetwork — только по списку.
- OPA/Conftest в CI: схема/правила перед мёрджем.
Наблюдаемость:
- Дашборды: OOM/eviction, throttling, «HPA упёрся в max», Job backoff, DENY по NetworkPolicy, TLS expiry.
- Алерты burn-rate по бизнес-SLO (BI-дашборды/ETL окна).
Процессы:
- GitOps с промо Dev→Stage→Prod; --server-side + diff/dry-run=server.
- Ежемесячный review рекомендаций VPA; раз в квартал — storage/backup restore-drill.
Практика (лабораторка 1–2 дня)
- Скан кластера: найти объекты без resources, ns без Quota/LimitRange/NP, Ingress с конфликтами путей.
- Включить default-deny + разрешения DNS/Ingress/мониторинг в одном ns.
- Вынести данные из emptyDir в PVC, Reclaim=Retain; сделать пробный бэкап/restore.
- Политики: запрет :latest и отсутствие resources; baseline Pod Security.
- CronJob-гигиена: ttlSecondsAfterFinished, history-лимиты, concurrencyPolicy.
- Чек уровня производительности: завести алерты на throttling/OOM/HPA=max; снять неделю данных и подправить requests.
Чек-лист «чистим анти-паттерны»
- Ns размечены (env/team/owner), есть Quota/LimitRange/NetworkPolicy/PodSecurity.
- Везде есть requests/limits, VPA даёт рекомендации, процесс их применения есть.
- Нет данных в emptyDir; PV для stateful — RWO, Retain; бэкапы и restore проверены.
- Ingress консолидирован, TLS auto-renew, доступ к backend ограничен NP.
- Секреты через Vault/ESO/CSI; конфиги — ConfigMap/оверлеи; без хардкода.
- GitOps обязателен, SSA включён; ручные правки фиксируются PR.
- PDB/anti-affinity/TopologySpread настроены для критичных сервисов.
- Политики: запрет :latest, baseline/restricted, запрет privileged.
- CronJob/Job с TTL, policy на ретраи; нет «кладбища job».
- Дашборды и алерты по SLO, OOM, throttling, HPA=max, DENY.
Вопрос-ответ
В: У нас мало трафика — можно без requests/limits?
О: Нет. Без них планировщик и автоскейлер работают «вслепую». Минимальные requests+LimitRange обязательны.
В: Когда emptyDir допустим?
О: Для временных файлов/кешей, где потеря не критична. Для данных — только PVC.
В: Как бороться с «сиротскими» Ingress/Route правилами?
О: Введите единый IngressClass/Gateway и ревью новой публикации через PR; мониторьте 4xx/5xx и TLS expiry.
В: Тег :latest — это же просто «удобно»?
О: Удобно до первой разницы между стендами. Фиксируйте теги/дигесты и подписи — иначе отладка и безопасность страдают.
В: Можно ли хранить секреты в env?
О: Допустимо, если источник — Secret/ESO и есть ротация. Но избегайте логирования env и дампов.
В: Мы используем NFS для ClickHouse/БД — это критично?
О: Да, для stateful-нагрузок это частый источник деградаций/коррапта. Переезжайте на RWO-блок.
В: CronJob периодически «накладывается» друг на друга — что делать?
О: concurrencyPolicy: Forbid (или Replace), startingDeadlineSeconds, activeDeadlineSeconds, ttlSecondsAfterFinished.
В: Как убедиться, что ручные правки больше не просачиваются?
О: Включить аудит, запретить apply из-под «людских» токенов на prod-ns, использовать Argo/Flux-only; дежурный «break-glass» — только по процедуре и с последующим PR.
Анти-паттерны в Kubernetes почти всегда про дисциплину: разложить по namespace, фиксировать ресурсы, хранить данные там, где им место, публиковать сервисы предсказуемо и управлять конфигами через GitOps. Введите политики и алерты, закрепите процедуры — и большинство «странных падений» исчезнут, а платформа BI/DWH станет спокойнее, быстрее и дешевле в эксплуатации.



