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.yaml | Namespace и метки PSA |
| Конфигурация | configmap.yaml | ConfigMap; Secret доставляется отдельно |
| Рабочая нагрузка | deployment.yaml | Deployment, проверки, ресурсы и безопасность |
| Стабильная сеть | service.yaml | Service/EndpointSlice |
| Внешняя точка входа | ingress.yaml | Ingress; требуется дополнение-контроллер |
| Политика внутреннего трафика | networkpolicy.yaml | NetworkPolicy; требуется совместимый CNI |
| Доступность | pdb.yaml | PDB |
| Масштабирование | hpa.yaml | HPA; требуется дополнение Metrics API |
| Идентичность и RBAC | serviceaccount.yaml, rbac.yaml | SA/Role/RoleBinding |
| Окружения | overlays/dev, overlays/prod | Клиентские инструменты Kustomize |
| Лабораторное хранилище | pvc.yaml, storage-pod.yaml | PVC/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— точки интеграции, а не установленный мониторинг.
Модель угроз
| Угроза или актив | Граница или путь | Меры защиты | Проверка | Остаточный риск |
|---|---|---|---|---|
| Раскрытие ключа API | CI → 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 и трафик хоста |
| Несанкционированное развёртывание | пользователь → API | OIDC, 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.
-
Остановите дополнительные изменения; запишите UTC, контекст, ревизию, образ и хеш конфигурации.
-
Подтвердите область: старый и новый ReplicaSet, пользовательский путь и зависимости.
-
Если изменение касается только приложения и совместимо:
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 -
Проверьте HTTP, EndpointSlices, ошибки, задержку, Pods и перезапуски.
-
Отмените коммит или наложение исходника, чтобы GitOps или следующее применение не вернули плохое состояние.
-
Ротируйте Secret, если он раскрыт; rollback образа не отзывает учётные данные.
-
Если миграция схемы или данных несовместима, используйте заранее написанный план расширения, сужения и восстановления данных; одного undo Kubernetes недостаточно.
-
Сохраните доказательства и назначьте владельца и срок послеинцидентного действия.
Эксплуатационный регламент
Сигнал тревоги: доступность и задержка
Подтвердить пользовательский 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 и отмена исходника | старый сервис остаётся доступным |
| Плохая проверка | применить сценарий 05 | Unhealthy, перезапуски, предыдущие журналы | правильный именованный порт | устойчивый Ready, перезапуски прекратились |
| Нет ключа конфигурации | неверный ключ | Event CreateContainerConfigError | вернуть ключ и выполнить rollout | процесс видит нужную конфигурацию |
| Несовпадение селектора | сценарий 04 | пустой EndpointSlice | исправить селектор | endpoints и запрос восстановлены |
| Запрещён исходящий DNS | сценарий 08 | тайм-аут запроса, если политика применяется | вернуть правило DNS | DNS и HTTP восстановлены |
| OOM | сценарий 06 | OOMKilled/137 | подобрать размер и исследовать память | нет слепого перезапуска |
| PVC не привязан | сценарий 07 | Events PVC Pending | правильный класс и безопасное пересоздание PVC | Bound и проверка данных |
| Плохой RBAC | неверный resourceName | Forbidden и результат no команды kubectl auth can-i | точное исправление Role | положительная и отрицательная проверки пройдены |
| Обслуживание узла | drain рабочего узла | PDB, eviction и SLI | замены и uncordon | нет нарушения SLO |
Каждая запись об инциденте содержит влияние, начало и конец, гипотезу,
доказательства, действие, проверку, очистку и предотвращение. Уровень
production-ready требует автоматизированного наблюдения пользовательского SLI,
а не только kubectl.
Самостоятельная задача
Расширьте итоговый проект без изменения основного приложения:
- Добавьте наложение
staging. - Выберите реализацию Gateway API и создайте Gateway/HTTPRoute с планом TLS.
- Опишите ADR для внешнего PostgreSQL: соединение, Secret, пул, миграции и резервное копирование.
- Добавьте ServiceMonitor/OpenTelemetry, только если установлены сборщик и CRDs; иначе оставьте переносимые аннотации.
- Создайте проверки 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.
| Аспект | 0 | 1 | 2 |
|---|---|---|---|
| Сборка и воспроизводимость | плавающая или ручная | версионный тег и рендеринг | 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.
Самопроверка
- Почему PVC не смонтирован в Deployment с тремя репликами?
- Что должна доказать проверка внешнего входа?
- Почему Role есть, но токен основного Pod отсутствует?
- Что rollback не исправит?
- Какие доказательства подтверждают работу HPA?
- Может ли итоговый проект только в kind быть
production-ready?
Ответы: 1) антипаттерн RWO, топологии и конкурентной записи, приложение не хранит состояние; 2) status контроллера и реальный внешний ответ на Host и путь; 3) приложению не нужен API, минимизируется раскрытие; 4) разрушающую миграцию БД, утечку секрета и внешний побочный эффект; 5) Metrics API, цель, изменение реплик, нагрузка и здоровье; 6) нет, он не доказывает реального провайдера, CNI/CSI, данные, SLO и восстановление.
Резюме и источники
Итоговый проект закончен только после учебного дня отказов, rollback и доказательств по критериям. Переведите результаты в ответы для собеседования и резюме и проверочный список навыков.