Kube/Pythonproduction course
Курс · RU91-capstone.md

91. Итоговый проект: эксплуатационный Python-сервис

Незнакомый термин? Откройте словарь Kubernetes и терминов курса.

Назначение, предварительные знания и результаты обучения

Итоговый проект собирает все главы в один проверяемый результат. Нужны выполненные лабораторные 00–12, воспроизводимо собираемый образ и диагностика на основе доказательств.

После итогового проекта вы сможете:

  • защитить архитектуру и явно сформулированные нецели;
  • безопасно развернуть эксплуатационное наложение Kustomize;
  • проверить сеть, конфигурацию, безопасность, RBAC, ресурсы, проверки, HPA и PDB;
  • объяснить решение по хранению и границы восстановления;
  • выполнить rollback, пройти эксплуатационный регламент и учебный день отказов;
  • получить объективный уровень minimum, job-ready или production-ready.

Постановка задачи и SLO

Развернуть HTTP-сервис python-api с взаимозаменяемыми репликами. Service отвечает на /, /config, /health/*, /metrics; локальная точка состояния только демонстрационная. Эксплуатационный контракт:

  • предлагаемое SLO доступности: 99,9% успешных учитываемых HTTP-запросов за 30 дней;
  • предлагаемое SLO задержки: 99% запросов к / быстрее 300 мс при заявленной нагрузке;
  • RTO rollout приложения: 15 минут; RPO приложения без состояния: 0, внешних данных — согласно контракту резервного копирования БД;
  • rollout не уменьшает число готовых реплик ниже желаемого;
  • среда исполнения без root, токен API по умолчанию отсутствует, Role имеет минимальные привилегии;
  • нет плавающего тега образа и настоящего секрета в Git или результате рендеринга.

Эти числа — гипотеза до проверки нагрузки и бизнес-требований; уровень production-ready требует измеренной базовой линии и согласованного с заинтересованными сторонами состава запросов SLI.

Архитектура

flowchart TB
    Client[HTTP-клиент] --> Edge[контроллер Ingress/Gateway\nдополнение]
    Edge --> Svc[Service python-api :80]
    Svc --> ES[EndpointSlice\nготовые IP Pod :8000]
    ES --> P1[FastAPI Pod A]
    ES --> P2[FastAPI Pod B]
    ES --> P3[FastAPI Pod C]
    CM[ConfigMap] --> P1
    CM --> P2
    CM --> P3
    Secret[доставка Secret\nвне Kustomize] --> P1
    Metrics[Metrics Server / adapter\nдополнение] --> HPA[HPA 3..6]
    HPA --> Deploy[Deployment]
    Deploy --> P1
    Deploy --> P2
    Deploy --> P3
    PDB[PDB maxUnavailable 1] --> Evict[Eviction / drain]
    Scheduler[Scheduler + топологическое распределение] --> P1
    Scheduler --> P2
    Scheduler --> P3
    P1 --> Ext[(Внешняя БД/объектное хранилище\nэксплуатационное состояние)]
    P2 --> Ext
    P3 --> Ext

Путь запроса

Клиент → внешняя точка входа или LB → контроллер Ingress/Gateway → виртуальный IP Service → готовый адрес EndpointSlice → IP Pod:8000 → uvicorn → FastAPI. Для каждого перехода есть независимые status, журнал и метрика. Port-forward проверяет приложение, но обходит внешнюю точку входа и часть плоскости данных.

Решение по хранению данных

Базовый Deployment монтирует ограниченный emptyDir для /data; сервис не хранит состояние и безопасен для HPA. Бизнес-состояние эксплуатационной среды должно находиться во внешней реплицируемой БД или объектном хранилище с TLS, аутентификацией, пулом, тайм-аутами, резервным копированием, восстановлением, RPO и RTO. Один RWO PVC на три реплики намеренно отвергнут как антипаттерн гонок, топологии и доступности. manifests/base/pvc.yaml и manifests/labs/storage-pod.yaml покрывают жизненный цикл PVC отдельно. Критерии production-ready требуют реального ADR по системе данных и доказательств восстановления, а не обязательно PVC в Deployment веб-приложения.

Состав манифестов

АспектФайлПримитив Kubernetes или зависимость
Идентичность и изоляцияnamespace.yamlNamespace и метки PSA
Конфигурацияconfigmap.yamlConfigMap; Secret доставляется отдельно
Рабочая нагрузкаdeployment.yamlDeployment, проверки, ресурсы и безопасность
Стабильная сетьservice.yamlService/EndpointSlice
Внешняя точка входаingress.yamlIngress; требуется дополнение-контроллер
Политика внутреннего трафикаnetworkpolicy.yamlNetworkPolicy; требуется совместимый CNI
Доступностьpdb.yamlPDB
Масштабированиеhpa.yamlHPA; требуется дополнение Metrics API
Идентичность и RBACserviceaccount.yaml, rbac.yamlSA/Role/RoleBinding
Окруженияoverlays/dev, overlays/prodКлиентские инструменты Kustomize
Лабораторное хранилищеpvc.yaml, storage-pod.yamlPVC/PV/StorageClass/CSI

Канонический полный Deployment: manifests/base/deployment.yaml. Полный манифест доступности:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: python-api
  namespace: kube-course
  labels:
    app.kubernetes.io/name: python-api
    app.kubernetes.io/part-of: kube-python-course
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: python-api
      app.kubernetes.io/instance: course

Важные решения Deployment:

  • 3 реплики, maxUnavailable: 0, maxSurge: 1, minReadySeconds: 5;
  • startup/readiness/liveness имеют разную семантику;
  • preStop отключает readiness до SIGTERM в пределах 30-секундного льготного периода;
  • запросы и лимиты CPU, памяти и временного хранилища; наложение prod повышает измеренный начальный бюджет;
  • UID/GID 10001 без root, seccomp RuntimeDefault, удаление всех capabilities (ALL), корневая файловая система только для чтения;
  • токен API не монтируется; указаны точные ключи ConfigMap и Secret;
  • топологическое распределение по hostname; ScheduleAnyway сохраняет работоспособность маленького кластера;
  • аннотации Prometheus и /metrics — точки интеграции, а не установленный мониторинг.

Модель угроз

Угроза или активГраница или путьМеры защитыПроверкаОстаточный риск
Раскрытие ключа APICI → Secret → Podвнешняя доставка, RBAC, запрет журналирования, KMS для хранимых данных в prodотрицательный auth can-i, проверка журналовпамять процесса и диагностический доступ
Компрометация приложенияPod → узел/API/сетьбез root, корень только для чтения, seccomp, удаление capabilities, без токена, NetworkPolicyсерверный dry-run PSS, UID во время исполнения, контрольная политикаобщее ядро и пробелы CNI
Вредоносный образ или смена тегареестр → узелверсионный тег; политика digest и подписей в prodдоказательства imageID, digest и admissionуязвимый подписанный артефакт
Боковое перемещениесеть Podполитика в стиле default-deny, списки DNS и внешнего входа, аутентификация приложения и TLSразрешённая и запрещённая контрольные проверкиприменение CNI и трафик хоста
Несанкционированное развёртываниепользователь → APIOIDC, RBAC, admission и аудитauth can-i, запрос аудитакомпрометация учётных данных и аварийный доступ
Атака на доступность или нагрузкаклиент → приложение и зависимостиHPA, лимиты, PDB, тайм-ауты и ограничения частоты на входенагрузочная проверка, SLO и доказательства масштабаузкое место зависимости и стоимость
Потеря данныхприложение → внешнее состояниеPods без состояния, репликация, резервное копирование и восстановление БДтренировка восстановления, RPO/RTOкоррелированный отказ провайдера или KMS
Отказ политики или контроллераadmission, вход, метрикиHA, ограниченная область failurePolicy и регламентконтрольные проверки, хаос и сигналы тревогиобщий радиус поражения дополнения

Поэтапное развёртывание

1. Предварительная проверка и сборка

test "$(kubectl config current-context)" = "kind-kube-course"
kubectl version
kubectl wait --for=condition=Ready nodes --all --timeout=180s
docker build --file app/Containerfile --tag kube-python-course:1.0.0 app
kind load docker-image kube-python-course:1.0.0 --name kube-course
kubectl kustomize manifests/overlays/prod > /tmp/python-api-prod.yaml
kubectl apply --dry-run=client -f /tmp/python-api-prod.yaml
kubectl apply --dry-run=server -f /tmp/python-api-prod.yaml

Ожидается код завершения 0 у всех команд. Серверный dry-run не требует существования указанного Secret, но фактический запуск требует.

2. Доставка Secret и применение

Namespace должен существовать до создания Secret в нём:

kubectl apply -f manifests/base/namespace.yaml
read -r -s -p 'Capstone lab API key: ' CAPSTONE_API_KEY
printf '\n'
kubectl create secret generic python-api-secret \
  -n kube-course \
  --from-literal=API_KEY="$CAPSTONE_API_KEY" \
  --dry-run=client -o yaml |
  kubectl apply -f -
unset CAPSTONE_API_KEY
kubectl diff -k manifests/overlays/prod
kubectl apply -k manifests/overlays/prod

Код 1 у kubectl diff означает ожидаемые различия. Не сохраняйте Secret из /tmp в Git и не выводите его. Kustomization не содержит Secret, поэтому последующее применение его не перезаписывает.

3. Проверка рабочей нагрузки

kubectl rollout status deployment/python-api -n kube-course --timeout=180s
kubectl get deployment,replicaset,pod,service,endpointslice,hpa,pdb \
  -n kube-course -o wide
kubectl get pods -n kube-course -l app.kubernetes.io/instance=course \
  -o custom-columns='NAME:.metadata.name,READY:.status.containerStatuses[0].ready,UID:.metadata.uid,NODE:.spec.nodeName,QOS:.status.qosClass,RESTARTS:.status.containerStatuses[0].restartCount'
kubectl port-forward -n kube-course service/python-api 8080:80

В другом терминале:

curl --fail --silent http://127.0.0.1:8080/ | python3 -m json.tool
curl --fail --silent http://127.0.0.1:8080/config | python3 -m json.tool
curl --fail --silent http://127.0.0.1:8080/health/ready
curl --fail --silent http://127.0.0.1:8080/metrics

Ожидаются три готовых Pod, три endpoints, HTTP 200, конфигурация prod и только логический признак наличия секрета.

4. Проверка безопасности и RBAC

kubectl get namespace kube-course --show-labels
kubectl auth can-i get configmap/python-api-config -n kube-course \
  --as=system:serviceaccount:kube-course:python-api
kubectl auth can-i get secrets -n kube-course \
  --as=system:serviceaccount:kube-course:python-api
kubectl apply -f manifests/labs/rbac-check.yaml
kubectl wait pod/rbac-check -n kube-course \
  --for=jsonpath='{.status.phase}'=Succeeded --timeout=120s
kubectl logs rbac-check -n kube-course
kubectl delete pod rbac-check -n kube-course

Ожидаются разрешение конкретного ConfigMap и запрет Secrets. Pods основного Pods Deployment не имеют тома с токеном ServiceAccount:

kubectl get pod -n kube-course -l app.kubernetes.io/instance=course \
  -o jsonpath='{range .items[*]}{.metadata.name}{": "}{range .spec.volumes[*]}{.name}{" "}{end}{"\n"}{end}'

5. Проверка доступности и масштабирования

До сбора доказательств HPA Metrics Server должен быть установлен и здоров. Если он недоступен, зафиксируйте пробел зависимости; HPA TARGETS <unknown> не является успехом.

kubectl get hpa python-api -n kube-course
kubectl get pdb python-api -n kube-course \
  -o custom-columns='MIN:.status.desiredHealthy,CURRENT:.status.currentHealthy,ALLOWED:.status.disruptionsAllowed'
kubectl apply -f manifests/labs/hpa-load.yaml
kubectl get hpa python-api -n kube-course -w

Остановите нагрузку и проверьте ограниченное уменьшение масштаба. Затем выполните drain одного рабочего узла по лабораторной 9 и обязательно uncordon.

6. Проверка сети и внешнего входа

Service и DNS нужно проверить клиентом внутри кластера; для NetworkPolicy нужны разрешённая и запрещённая контрольные проверки на совместимом CNI. Для внешней точки входа либо запустите закреплённый cloud-provider-kind v0.9.0+ и примените Ingress, либо установите выбранную реализацию Gateway. Доказательства требуют адреса в status и реального запроса с Host и путём. Один лишь принятый Ingress баллов не даёт.

Регламент отката

Условия запуска: расход бюджета SLO по ошибкам или задержке, тайм-аут rollout, все новые Pods неготовы, регрессия безопасности. Не выполняйте rollback только из-за одного шумного Event.

  1. Остановите дополнительные изменения; запишите UTC, контекст, ревизию, образ и хеш конфигурации.

  2. Подтвердите область: старый и новый ReplicaSet, пользовательский путь и зависимости.

  3. Если изменение касается только приложения и совместимо:

    kubectl rollout history deployment/python-api -n kube-course
    kubectl rollout undo deployment/python-api -n kube-course --to-revision=<known-good>
    kubectl rollout status deployment/python-api -n kube-course --timeout=180s
    
  4. Проверьте HTTP, EndpointSlices, ошибки, задержку, Pods и перезапуски.

  5. Отмените коммит или наложение исходника, чтобы GitOps или следующее применение не вернули плохое состояние.

  6. Ротируйте Secret, если он раскрыт; rollback образа не отзывает учётные данные.

  7. Если миграция схемы или данных несовместима, используйте заранее написанный план расширения, сужения и восстановления данных; одного undo Kubernetes недостаточно.

  8. Сохраните доказательства и назначьте владельца и срок послеинцидентного действия.

Эксплуатационный регламент

Сигнал тревоги: доступность и задержка

Подтвердить пользовательский SLI → status границы → EndpointSlices Service → готовые Pods
→ новая revision? → журналы/traces/зависимость → ослабить влияние (rollback/масштабирование/сброс нагрузки)
→ проверить SLI → записать результат

Сигнал тревоги: исчерпание ресурсов

Проверьте kubectl top или мониторинг, ограничение CPU и OOM, цель и максимум HPA, Pending и ёмкость, пул последующей зависимости. Масштабирование Pods может перегрузить БД; ограничивайте частоту, используйте очередь и сброс нагрузки.

Обслуживание

Проверьте disruptionsAllowed PDB, запас ёмкости, хранилище и emptyDir, владельцев; выполните drain одного узла, проверьте SLO, выполните uncordon и только затем переходите к следующему. Не выполняйте параллельный drain сверх бюджета отказа.

Ротация Secret

Запишите новое значение через одобренную систему, запустите управляемый rollout, если используется окружение, проверьте новые реплики, отзовите старое значение и аудитируйте доступ. Одно обновление смонтированного файла ConfigMap/Secret не обновляет окружение.

Учебный день отказов

Выполняйте по одному, возвращаясь в устойчивое состояние между упражнениями.

УпражнениеВнесённая ошибкаОбнаружение и доказательстваИсправлениеКритерий успеха
Плохой образзадать недействительный образтайм-аут rollout, Events загрузкиrollout undo и отмена исходникастарый сервис остаётся доступным
Плохая проверкаприменить сценарий 05Unhealthy, перезапуски, предыдущие журналыправильный именованный портустойчивый Ready, перезапуски прекратились
Нет ключа конфигурацииневерный ключEvent CreateContainerConfigErrorвернуть ключ и выполнить rolloutпроцесс видит нужную конфигурацию
Несовпадение селекторасценарий 04пустой EndpointSliceисправить селекторendpoints и запрос восстановлены
Запрещён исходящий DNSсценарий 08тайм-аут запроса, если политика применяетсявернуть правило DNSDNS и HTTP восстановлены
OOMсценарий 06OOMKilled/137подобрать размер и исследовать памятьнет слепого перезапуска
PVC не привязансценарий 07Events PVC Pendingправильный класс и безопасное пересоздание PVCBound и проверка данных
Плохой RBACневерный resourceNameForbidden и результат no команды kubectl auth can-iточное исправление Roleположительная и отрицательная проверки пройдены
Обслуживание узлаdrain рабочего узлаPDB, eviction и SLIзамены и uncordonнет нарушения SLO

Каждая запись об инциденте содержит влияние, начало и конец, гипотезу, доказательства, действие, проверку, очистку и предотвращение. Уровень production-ready требует автоматизированного наблюдения пользовательского SLI, а не только kubectl.

Самостоятельная задача

Расширьте итоговый проект без изменения основного приложения:

  1. Добавьте наложение staging.
  2. Выберите реализацию Gateway API и создайте Gateway/HTTPRoute с планом TLS.
  3. Опишите ADR для внешнего PostgreSQL: соединение, Secret, пул, миграции и резервное копирование.
  4. Добавьте ServiceMonitor/OpenTelemetry, только если установлены сборщик и CRDs; иначе оставьте переносимые аннотации.
  5. Создайте проверки CI: детерминизм рендеринга, проверка схемы и сервера, политики, сканирование и подпись образа, контрольный rollout.

Критерий приёмки: каждое дополнение явно названо зависимостью; манифесты не используют неподдерживаемые CRD; нет latest и настоящих секретов; rollback и отмена исходника проверены.

Сломанный сценарий: конфликтующие средства управления доступностью

Установите одну реплику, PDB minAvailable: 1 и попробуйте выполнить drain узла с Pod. Ожидается блокировка eviction (Cannot evict pod as it would violate the pod's disruption budget). Это правильное поведение контроллера, но плохой проект обслуживания.

Восстановление: выполните uncordon, масштабируйте минимум до двух реплик на разных узлах, дождитесь Ready и только затем выполните drain; либо используйте одобренное исключение обслуживания с принятым простоем. Не --disable-eviction автоматически.

Дерево диагностических решений

Проверка итогового проекта не пройдена
├─ рендеринг/клиент → источник/Kustomize/инструмент
├─ серверный dry-run → API/RBAC/admission
├─ rollout → RS/Pod: назначение/образ/конфигурация/проверки
├─ Service/DNS → селектор/EndpointSlice/CoreDNS/политика
├─ граница → контроллер/class/маршрут/TLS/status
├─ HPA/PDB → метрики/запросы ресурсов/поле `behavior` или readiness/бюджет
├─ безопасность → PSA/RBAC/токен/среда исполнения/политика образов
└─ данные → внешняя БД/PVC/резервная копия/восстановление; не скрывать проблему перезапуском Pod

Критерии оценки

Оценка каждого аспекта: 0 — отсутствует или только заявлен, 1 — есть манифест или объяснение, 2 — есть фактические доказательства и восстановление. Максимум 24.

Аспект012
Сборка и воспроизводимостьплавающая или ручнаяверсионный тег и рендерингdigest, происхождение и детерминированный CI
Рабочая нагрузка и здоровьеодин Pod без проверокDeployment и проверкиизмеренные startup и drain без цикла обратной связи
Сетьтолько port-forwardманифест Service/Ingressконтрольные проверки endpoint, DNS, входа и политики
Конфигурация и секретыжёстко заданы или раскрытыссылки ConfigMap/Secretвнешняя ротация и отрицательная проверка доступа
Хранилище и данныеигнорируютсяявный ADR без состояния или с PVCрезервная копия, успешное восстановление, RPO/RTO
Ресурсы и планированиенет или скопированызапросы, лимиты и распределениедоказательства нагрузки, ёмкости и областей отказа
Доступность и масштабтолько репликиrollout, PDB и HPAнагрузка, drain, rollback и SLO
Безопасность и RBACзначения по умолчанию, root или широкие праваrestricted и минимальная Roleдоказательства admission, образов, аудита и угроз
Наблюдаемостьтолько журналыточки метрик и регламентпроверены панели SLI, сигналы тревоги и трассировки
Доставка и расхожденияслучайное применениеналожения и diffпроверены владение CI/GitOps и отмена
Работа с отказамисначала перезапускшесть упражненийвсе упражнения с доказательствами и действиями MTTR
Эксплуатациянет владельцазаметки об обновлении, резервной копии и стоимостиконтрольная группа, совместимость, восстановление, SLO и день отказов

Уровни:

  • minimum: 10–14, нет нулей по рабочей нагрузке, сети, конфигурации и безопасности; локальный сервис запускается и очищается.
  • job-ready: 15–19, не менее шести упражнений с отказами, rollback, RBAC и PVC объяснены и подтверждены.
  • production-ready: 20–24, ни один аспект не ниже 1; реальное целевое окружение, сеть с поддержкой политик, восстановление данных, SLO и сигналы тревоги, цепочка поставки и контрольные доказательства обновления. Работа только в kind не может доказать все аспекты промышленной эксплуатации.

Эксплуатационные компромиссы, безопасность и стоимость

Три реплики, PDB и HPA расходуют ёмкость, но снижают риск обслуживания и нагрузки. Контроллеры внешнего входа, метрик, политик, телеметрии и секретов добавляют общие зависимости. Внешняя управляемая БД упрощает эксплуатацию состояния, но стоит денег и связывает с провайдером. Digest и подпись уменьшают неопределённость, но не уязвимости. Строгая политика может заблокировать экстренное развёртывание; используйте аудируемый аварийный доступ с ограниченным сроком. Проверяйте неиспользуемые LB, тома и снимки, кардинальность журналов и трассировок и стоимость максимума HPA.

Самопроверка

  1. Почему PVC не смонтирован в Deployment с тремя репликами?
  2. Что должна доказать проверка внешнего входа?
  3. Почему Role есть, но токен основного Pod отсутствует?
  4. Что rollback не исправит?
  5. Какие доказательства подтверждают работу HPA?
  6. Может ли итоговый проект только в kind быть production-ready?

Ответы: 1) антипаттерн RWO, топологии и конкурентной записи, приложение не хранит состояние; 2) status контроллера и реальный внешний ответ на Host и путь; 3) приложению не нужен API, минимизируется раскрытие; 4) разрушающую миграцию БД, утечку секрета и внешний побочный эффект; 5) Metrics API, цель, изменение реплик, нагрузка и здоровье; 6) нет, он не доказывает реального провайдера, CNI/CSI, данные, SLO и восстановление.

Резюме и источники

Итоговый проект закончен только после учебного дня отказов, rollback и доказательств по критериям. Переведите результаты в ответы для собеседования и резюме и проверочный список навыков.