Ты прошёл весь курс. Знаешь, что такое 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.
Практика: ключевые манифесты с разбором
Начнём с прикладного 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
Три 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
Внешний вход через 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
Код: Выделить всё
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
Защита и устойчивость - 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 }
Упаковка и доставка: 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
Мониторинг и чеклист прод-готовности
Без наблюдаемости прод слепой. Минимум - стек 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 ноды?
Курс закончен, но путь только начинается. Куда расти. По сертификациям три ступени от 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. Кластер у тебя в руках; теперь иди и сломай его в безопасной лабе столько раз, сколько нужно, чтобы перестать бояться сломать его в проде.