Сквозной проект и путь дальше: от манифеста до прода

Рейтинг: 61% · 6 голосов
Kubernetes для разработчиков: поды, деплойменты, сервисы, ingress, конфиги и отладка. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
anton_k8s
Сообщения: 55
Зарегистрирован: 12 май 2026, 03:23

Сквозной проект и путь дальше: от манифеста до прода

Сообщение anton_k8s »

Оглавление курса (48)
  1. Зачем нужен Kubernetes и из чего состоит кластер
  2. Поднимаем локальный кластер: minikube и kind
  3. Поды: базовая единица запуска
  4. Deployment и ReplicaSet: управляем репликами
  5. Service: сетевой доступ к подам
  6. ConfigMap и Secret: выносим конфигурацию
  7. Ingress: пускаем трафик снаружи
  8. Хранилище: Volumes и PersistentVolumeClaim
  9. Namespaces, requests и limits
  10. Health checks: liveness и readiness пробы
  11. Отладка: почему под не стартует
  12. Helm: пакетный менеджер для Kubernetes
  13. Базовая безопасность: RBAC и доступы
  14. Job и CronJob: разовые и периодические задачи
  15. StatefulSet и DaemonSet: stateful-нагрузки и системные агенты
  16. Стратегии обновления и планирование: rollout и rollback, graceful shutdown, nodeSelector, affinity, taints
  17. Автомасштабирование: HPA по метрикам, обзор VPA и Cluster Autoscaler
  18. Наблюдаемость: логи, метрики, events, обзор Prometheus и Grafana
  19. Безопасность глубже: securityContext, Pod Security Standards, NetworkPolicy, шифрование секретов
  20. Архитектура control plane: api-server, etcd, scheduler
  21. Узел кластера: kubelet, kube-proxy и container runtime
  22. Декларативная модель: reconciliation, контроллеры, CRD
  23. kubectl профессионально: get, describe, explain, jsonpath
  24. Под глубже: init, sidecar, lifecycle hooks и QoS
  25. Метки, селекторы и организация ресурсов
  26. Сервисы и kube-proxy глубже: типы, IPVS, EndpointSlices
  27. Ingress, ingress-контроллеры и Gateway API
  28. Секреты в кластере: шифрование, External Secrets, Vault
  29. Хранилище глубже: PV, StorageClass, CSI и StatefulSet
  30. Сеть кластера: CNI, NetworkPolicy и CoreDNS
  31. Планировщик: affinity, taints, topology spread
  32. Ресурсы, QoS и вытеснение: requests, limits, eviction
  33. Helm глубже: шаблоны, хуки, зависимости, OCI
  34. Kustomize и управление конфигурацией без шаблонов
  35. RBAC и аутентификация глубже
  36. Admission и Pod Security: контроль на входе
  37. Policy as code: Kyverno и OPA Gatekeeper
  38. GitOps: Argo CD и Flux
  39. Операторы и CRD: расширяем Kubernetes
  40. Сервис-меш: Istio, Linkerd и когда он нужен
  41. Эксплуатация кластера: апгрейд, узлы, бэкап etcd
  42. Где запускать кластер: managed, self-hosted, k3s, Deckhouse
  43. Траблшутинг кластера: Pending, CrashLoop, узлы NotReady
  44. Стоимость и эффективность кластера: FinOps
  45. CI/CD в Kubernetes: сборка, деплой, прогрессивные релизы
  46. Лучшие практики и антипаттерны Kubernetes
  47. Сквозной проект и путь дальше: от манифеста до прода (вы здесь)
  48. Деплой приложений через Argo CD: Application, sync и App-of-Apps
Зачем нам финальный kubernetes проект, а не ещё одна теория

Ты прошёл весь курс. Знаешь, что такое Pod, Service, Deployment, probe, HPA, NetworkPolicy. По отдельности каждый кирпич понятен. Но боль начинается, когда из кирпичей надо сложить дом, который не развалится в три часа ночи под нагрузкой. Реальный kubernetes проект - это не "запустил nginx и порадовался". Это десяток связанных ресурсов, которые должны корректно стартовать в нужном порядке, переживать выкатку, падение ноды, всплеск трафика и при этом не светить пароли в открытом виде.

В этом уроке мы соберём сквозной пример: API-сервис на Go или Python, база данных PostgreSQL под управлением оператора, кэш Redis. Поверх - доставка, секреты, автоскейлинг, защита сети, мониторинг. И главное - упакуем всё так, чтобы деплой приложения kubernetes делался одной командой через Git, а не руками из консоли в пятницу вечером. Это и есть переход от учебного манифеста к kubernetes production. Параллельно я дам чеклист прод-готовности и карту роста: куда двигаться после курса, нужен ли тебе cka и что делать с FinOps и eBPF.

Аналогия для новичка: представь стройку. Манифест - это чертёж одной стены. Сквозной проект - это собранный дом с фундаментом, проводкой, сигнализацией и счётчиком воды. А GitOps - это когда любые изменения в доме вносятся через утверждённый проект в архиве, а не "сосед прибил полку, никто не знает зачем".

Изображение

Архитектура: что из чего состоит и кто за что отвечает

Разложим наш kubernetes проект на слои. Каждый ресурс решает ровно одну задачу - это не случайность, а принцип. Когда что-то сломается, ты должен точно знать, в каком слое копать.
  • Stateless API - это Deployment. Поды одинаковые, взаимозаменяемые, можно убить любой и поднять заново. Трафик к ним - через Service типа ClusterIP.
  • База PostgreSQL - это НЕ голый StatefulSet, который ты пишешь руками. В 2026 базы в кластере поднимают через оператор: CloudNativePG, Zalando Postgres Operator или Percona. Оператор сам создаёт StatefulSet, headless Service, настраивает репликацию, failover, бэкапы и ротацию паролей. Ты описываешь желаемое состояние ("хочу кластер из 3 реплик PG 16"), а контроллер оператора крутит реальность к этому состоянию. Это паттерн "оператор" - расширение API кластера через CRD.
  • Кэш Redis - тоже через оператор (например, Spotahome redis-operator) или, для простого кэша без персистентности, обычный Deployment с одной репликой. Кэш по определению можно потерять - это сильно упрощает жизнь.
  • Внешний вход - раньше был Ingress, сейчас правильнее Gateway API (apiVersion gateway.networking.k8s.io/v1, GA). Gateway описывает точку входа и слушатели, HTTPRoute - правила маршрутизации. Это преемник Ingress с нормальным разделением ролей: платформенная команда владеет Gateway, разработчики - своими HTTPRoute.
  • Конфигурация - ConfigMap для несекретного (URL, таймауты, фичефлаги) и Secret для паролей. Но Secret в Git коммитить нельзя, поэтому секреты тянем через External Secrets Operator из Vault или облачного KMS.
Под капотом порядок такой: оператор PG поднимает базу и кладёт сгенерированный пароль в Secret внутри кластера. External Secrets синхронизирует прикладные секреты из внешнего хранилища. API стартует, читает ConfigMap и Secret как переменные окружения, ходит в Service базы по DNS-имени и в Service Redis. Трафик снаружи приходит на Gateway, тот по HTTPRoute раскидывает на Service API. Сверху HPA смотрит на метрики и крутит число реплик, PDB не даёт убить слишком много подов разом, NetworkPolicy запрещает лишние сетевые разговоры.

Практика: ключевые манифесты с разбором

Начнём с прикладного API. Deployment с probes, requests/limits и нативным ожиданием готовности.

Код: Выделить всё

apiVersion: apps/v1
kind: Deployment
metadata:
  name: shop-api
  namespace: shop
spec:
  replicas: 3
  selector:
    matchLabels: { app: shop-api }
  template:
    metadata:
      labels: { app: shop-api }
    spec:
      containers:
        - name: api
          image: registry.cyberlake.ru/shop-api:1.8.2
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef: { name: shop-api-config }
            - secretRef: { name: shop-api-secrets }
          resources:
            requests: { cpu: "100m", memory: "128Mi" }
            limits:   { cpu: "500m", memory: "256Mi" }
          startupProbe:
            httpGet: { path: /healthz, port: 8080 }
            failureThreshold: 30
            periodSeconds: 2
          readinessProbe:
            httpGet: { path: /ready, port: 8080 }
            periodSeconds: 5
          livenessProbe:
            httpGet: { path: /healthz, port: 8080 }
            periodSeconds: 10
Разбор того, что тут реально важно и что новички ставят неправильно. requests - это бронь под планировщик: по ним scheduler решает, влезет ли под на ноду, и по ним же считается база для HPA. limits - потолок: превышение CPU дросселируется (throttling), превышение памяти - это OOMKill, под убивают мгновенно. Поэтому memory request и limit часто делают равными - чтобы под не подсадили на ноду, где он потом задохнётся. CPU limit нередко вообще не ставят, чтобы не душить всплески, но это спорно и зависит от соседей по ноде.

Три probe делают три разные вещи, и путать их - классическая грабля. startupProbe закрывает медленный старт: пока она не прошла, остальные две не работают, и тяжёлое приложение с прогревом JIT не убьют по liveness раньше времени. readinessProbe управляет тем, шлёт ли Service трафик на под: упала - под выкинут из эндпоинтов, но не перезапущен. livenessProbe - если упала, kubelet перезапускает контейнер. Если повесить тяжёлую проверку (например, пинг базы) на liveness, то при недоступности базы кластер начнёт бесконечно перезапускать здоровые поды API - и ты сам себе устроишь каскадный отказ.

Теперь Service и автоскейлинг.

Код: Выделить всё

apiVersion: v1
kind: Service
metadata:
  name: shop-api
  namespace: shop
spec:
  selector: { app: shop-api }
  ports:
    - port: 80
      targetPort: 8080
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: shop-api
  namespace: shop
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: shop-api
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target: { type: Utilization, averageUtilization: 70 }
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
Обрати внимание: apiVersion autoscaling/v2 (старые v2beta1 и v2beta2 уже не обслуживаются), и averageUtilization считается от requests, а не от limits. Если у тебя cpu request 100m и под жрёт 70m - это 70 процентов, HPA доволен. Поэтому requests должны быть честными: занизишь - HPA будет дёргать реплики на ровном месте. stabilizationWindowSeconds на scaleDown в 300 секунд гасит "флаппинг" - резкое схлопывание реплик после короткого всплеска. Без этого окна сервис будет пилообразно скейлиться и ронять latency на каждом откате.

Внешний вход через Gateway API:

Код: Выделить всё

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: shop-api
  namespace: shop
spec:
  parentRefs:
    - name: public-gateway
      namespace: gateway-system
  hostnames: ["api.shop.cyberlake.ru"]
  rules:
    - matches:
        - path: { type: PathPrefix, value: / }
      backendRefs:
        - name: shop-api
          port: 80
Секреты без коммита паролей в Git - через External Secrets Operator (apiVersion external-secrets.io/v1, стабильный):

Код: Выделить всё

apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: shop-api-secrets
  namespace: shop
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: shop-api-secrets
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: shop/db
        property: password
Тут механика такая: оператор раз в час идёт в Vault, читает ключ shop/db, поле password, и материализует обычный k8s Secret shop-api-secrets. Приложение про Vault ничего не знает - оно просто читает Secret через envFrom. Ротация пароля в Vault сама доедет до пода в течение refreshInterval. В Git лежит только ссылка на ключ, сам пароль - никогда.

Защита и устойчивость - NetworkPolicy и PDB:

Код: Выделить всё

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: shop-api
  namespace: shop
spec:
  minAvailable: 2
  selector:
    matchLabels: { app: shop-api }
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: shop-api-allow
  namespace: shop
spec:
  podSelector:
    matchLabels: { app: shop-api }
  policyTypes: [Ingress, Egress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels: { kubernetes.io/metadata.name: gateway-system }
  egress:
    - to:
        - podSelector:
            matchLabels: { app: postgres }
PDB страхует от добровольных нарушений (drain ноды, выкатка): minAvailable 2 значит "при любом плановом выселении держи минимум 2 живых пода". Грабля: если поставить minAvailable равным replicas, drain ноды зависнет навсегда - его нечем удовлетворить. NetworkPolicy по умолчанию в Kubernetes разрешает всё; как только ты применил хотя бы одну policy на под, для него включается deny-by-default по указанным policyTypes. То есть после этого манифеста API сможет принимать трафик только из gateway-system и ходить только в postgres - всё остальное обрублено. Это базовая микросегментация. Учти: NetworkPolicy реализует CNI, и не всякий CNI её поддерживает - Cilium и Calico да, а совсем простой плагин может молча игнорировать.

Упаковка и доставка: Helm, Kustomize и GitOps через Argo CD

Десяток YAML руками через kubectl apply - это ад для kubernetes production. Нужна упаковка и единый источник правды.

Helm - шаблонизатор и менеджер релизов. Манифесты становятся шаблонами с values.yaml, на выходе - версионированный релиз, который можно откатить одной командой. Kustomize - наложение оверлеев без шаблонов: одна base, поверх неё overlays для dev/stage/prod, которые патчат только различия (число реплик, имя образа, домен). Часто их сочетают: Helm для сторонних чартов (PG-оператор, Prometheus), Kustomize для своих манифестов.

Дальше - GitOps. Идея простая и мощная: желаемое состояние кластера лежит в Git, а контроллер постоянно сравнивает Git с реальностью и подтягивает кластер к описанному. Никаких ручных kubectl apply в прод. Хочешь изменить - делаешь Pull Request, ревью, merge, и Argo CD сам выкатывает. Это даёт аудит (вся история в git log), откат (git revert) и защиту от дрейфа (кто-то поправил руками - Argo вернёт как в Git).

Код: Выделить всё

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: shop
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://git.cyberlake.ru/infra/shop.git
    targetRevision: main
    path: overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: shop
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
Тут selfHeal: true - тот самый страж от дрейфа: правка руками будет затёрта обратно к Git. prune: true - удаление из Git означает удаление из кластера. Для десятков сервисов на нескольких кластерах вместо ручного клонирования Application используют ApplicationSet (тоже argoproj.io/v1alpha1) - один генератор плодит сотню Application из матрицы "сервис на кластер".

Мониторинг и чеклист прод-готовности

Без наблюдаемости прод слепой. Минимум - стек kube-prometheus-stack (Prometheus собирает метрики, Grafana рисует, Alertmanager шлёт алерты). Приложение отдаёт метрики на /metrics, ты вешаешь ServiceMonitor (CRD от Prometheus Operator), и метрики сами подхватываются. Целься на четыре золотых сигнала: latency, трафик, ошибки, насыщение (saturation).

Сводный чеклист, прежде чем назвать кластер и приложение готовыми к продакшену:
  • У каждого пода выставлены requests/limits, нет подов в QoS BestEffort на критичном пути.
  • Три probe настроены осмысленно, liveness не зависит от внешних сервисов.
  • HPA с честными requests и stabilization window; PDB у всех stateful и важных stateless.
  • Секреты не в Git - только External Secrets или sealed-secrets; ConfigMap отдельно от Secret.
  • NetworkPolicy с deny-by-default, открыто только нужное.
  • Pod Security Admission в режиме enforce на уровне baseline или restricted для прикладных namespace (PSP давно мертвы).
  • Ресурсы под GitOps, ручной доступ в прод закрыт, всё через PR.
  • Метрики, логи, алерты на четыре золотых сигнала; есть дашборд и runbook на инцидент.
  • Бэкапы базы проверены восстановлением (бэкап без проверенного restore - это не бэкап).
  • Заданы requests на уровне namespace через ResourceQuota и LimitRange, чтобы один сервис не съел кластер.
Типичные грабли и антипаттерны
  • База как голый StatefulSet своими руками - failover, бэкапы и репликацию ты будешь чинить вечно. Бери оператор.
  • latronics liveness на проверку БД - падение базы превращается в перезапуск всех API. Liveness проверяет только сам процесс.
  • Один namespace на всё - нет границ ни по сети, ни по квотам, ни по доступу. Режь по командам и окружениям.
  • Секреты в ConfigMap или прямо в Git - рано или поздно утекут. Это не "потом поправим", это сразу.
  • kubectl apply в прод руками поверх GitOps - дрейф и неповторяемость. Либо GitOps, либо нет, серединка хуже обоих.
  • minReplicas: 1 на проде - любая выкатка или drain роняет сервис в ноль. Минимум 2-3 и PDB.
Мини-лаба: собери проект руками

Подними локальный кластер (k3d, kind или minikube) и пройди путь целиком:
  • Поставь CloudNativePG чартом и создай Cluster из 2 реплик PG.
  • Деплой API-Deployment с тремя probe и requests/limits, проверь kubectl describe pod - в Events не должно быть OOMKilled и Unhealthy.
  • Заверни манифесты в Kustomize base + overlays/dev и overlays/prod, в prod подними replicas до 3.
  • Поставь Argo CD, заведи Application на свой git-репозиторий, включи selfHeal, поправь Deployment руками через kubectl edit и посмотри, как Argo вернёт его обратно.
  • Добавь HPA, нагрузи API через hey или ab и в kubectl get hpa -w посмотри, как растут реплики, а потом схлопываются через stabilization window.
  • Примени NetworkPolicy deny-by-default и убедись, что лишний трафик обрублен (kubectl exec в чужой под и curl, который должен повиснуть).
Контрольные вопросы
  • Чем отличаются readinessProbe и livenessProbe по последствиям срабатывания и почему нельзя вешать проверку БД на liveness?
  • От какой величины HPA на autoscaling/v2 считает averageUtilization и как заниженный CPU request ломает автоскейлинг?
  • Что делают selfHeal и prune в Argo CD Application и как они защищают от дрейфа конфигурации?
  • Почему minAvailable в PDB нельзя ставить равным числу реплик и что тогда произойдёт при drain ноды?
Карта роста: cka, платформенная инженерия и куда дальше

Курс закончен, но путь только начинается. Куда расти. По сертификациям три ступени от CNCF: CKAD - для разработчиков, фокус на манифестах и деплое приложения kubernetes; CKA (самый ходовой в найме) - администрирование кластера, etcd, сеть, апгрейды; CKS - безопасность поверх CKA, для тех, кто хочет в защиту прода. Все три - практические экзамены в живом терминале, зубрёжка не спасает, нужны руки.

Дальше по специализациям: платформенная инженерия - строить internal developer platform поверх Kubernetes (Backstage, Crossplane, golden paths), чтобы разработчики катили сервисы без знания кишок кластера. FinOps - управление стоимостью: Kubecost, right-sizing requests, спот-ноды, Karpenter для умного провижининга. eBPF и Cilium - сеть, observability и безопасность нового поколения без iptables, с Hubble для видимости трафика. Любое из направлений - это годы глубины. Главное, что у тебя теперь есть фундамент, на котором всё это держится.

Итог

Мы собрали полноценный kubernetes проект из реальных слоёв: stateless API на Deployment, база через оператор, кэш, Gateway API на входе, External Secrets для паролей, requests/limits и три probe для устойчивости, HPA и PDB для масштаба и доступности, NetworkPolicy для сети. Упаковали в Helm и Kustomize, доставили через Argo CD по GitOps, накрыли Prometheus и Grafana и прогнали чеклист прод-готовности. Это и есть дорога от учебного манифеста до kubernetes production. Дальше - cka, платформа, FinOps, eBPF. Кластер у тебя в руках; теперь иди и сломай его в безопасной лабе столько раз, сколько нужно, чтобы перестать бояться сломать его в проде.
👍2 ❤️3 🔥2 😄 🤔1
Аватара пользователя
pyro6626
Сообщения: 1
Зарегистрирован: 18 май 2026, 10:06

Re: Сквозной проект и путь дальше: от манифеста до прода

Сообщение pyro6626 »

Вот этот момент про liveness на проверку базы прям про нас - год назад так и поймали каскад, пока не разнесли liveness и readiness. Спасибо что разжевали
👍 ❤️1 🔥1 😄 🤔
Аватара пользователя
chan_alex
Сообщения: 1
Зарегистрирован: 13 май 2026, 06:39

Re: Сквозной проект и путь дальше: от манифеста до прода

Сообщение chan_alex »

Подскажите, для прода лучше сразу Gateway API брать или Ingress ещё ок, если кластер на Yandex Managed? Боюсь что не все контроллеры Gateway уже тянут
👍 ❤️1 🔥 😄 🤔2
Ответить
← Предыдущая глава
Лучшие практики и антипаттерны Kubernetes
Следующая глава →
Деплой приложений через Argo CD: Application, sync и App-of-Apps

Все главы курса «Kubernetes: оркестрация контейнеров от основ до продакшена»

Поделиться темой: ✈ Telegram VK

Вернуться в «Kubernetes на практике»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя