← К программе курса

Модуль 19 / 19

Финальный проект: production-like платформа

KUBERNETES

Содержание
01

1. Цели итогового модуля

Итоговый проект объединяет архитектуру, Kubernetes API, workloads, networking, storage/configuration, security, observability, CI/CD, GitOps и operations в один проверяемый результат.

  • репозиторий как source of truth
  • immutable delivery
  • надёжный и ограниченный workload
  • SLI/SLO и alerts
  • failure drills и evidence
  • эксплуатационная документация
02

2. Сценарий проекта

Вы отвечаете за сервис course-web в staging и production. Команда требует безопасный rollout без потери доступности, автоматическое восстановление экземпляров, ограниченный сетевой и API-доступ, наблюдаемость, supply-chain проверки и GitOps promotion одного image digest.

Локальный kind используется для функциональной приёмки. Ограничения single-host среды — отсутствие реальной zone failure, cloud load balancer и production storage — фиксируются явно, а не скрываются зелёными тестами.

03

3. Требуемая структура репозитория

  • app/ — исходный код, unit tests, Dockerfile и health endpoints
  • chart/ или deploy/base/ — базовые Kubernetes manifests
  • deploy/overlays/staging и deploy/overlays/production — только различия окружений
  • argocd/ — AppProject, Applications или ApplicationSet
  • .gitlab-ci.yml — validate, build, scan, sign, publish и promotion
  • docs/architecture.md — границы системы и зависимости
  • docs/runbooks/ — deploy, rollback, degraded service и disaster recovery
  • docs/evidence/ — отчёт лаборатории без credentials и secrets

Generated manifests, kubeconfig, private keys, tokens и local snapshots не коммитятся. README содержит prerequisites, bootstrap, verification, cleanup и известные ограничения.

04

4. Архитектурные требования

  • Deployment минимум с тремя replicas, RollingUpdate, readiness/liveness и progress deadline
  • requests/limits, non-root, dropped capabilities, read-only filesystem и RuntimeDefault seccomp
  • Service и проверяемые EndpointSlices
  • PDB и topology spread; объясните поведение при недостатке Nodes
  • HPA с Metrics Server и безопасным scale-down
  • ConfigMap/Secret separation; production secrets поступают из утверждённого secret system
  • NetworkPolicy с описанным CNI enforcement
  • отдельный ServiceAccount с automount=false, если Kubernetes API не нужен
05

5. Требования к delivery и GitOps

Pipeline выполняет tests, manifest validation, image build, SBOM, vulnerability policy и signature verification. Между staging и production продвигается один digest без rebuild. Production promotion выполняется merge request с approval.

Argo CD Application использует ограниченный AppProject, automated sync, selfHeal и осознанный prune. targetRevision и dependencies фиксируются. Rollback меняет desired state через Git; прямой kubectl write считается break-glass и документируется.

06

6. SLI, SLO и error budget

Для учебного проекта примите SLO: availability 99,9% за rolling 30 days, успешность HTTP не ниже 99%, p95 latency ниже 300 ms и успешный rollback до 10 минут. 99,9% availability соответствует примерно 43 минутам 12 секундам error budget за 30 дней.

Определите источник каждого SLI, PromQL, окно, исключения и владельца. Добавьте multi-window burn-rate alerts, dashboard и runbook. Эти числа — учебная гипотеза; production targets выводятся из пользовательских ожиданий и стоимости надёжности.

07

7. Методические указания

  • Сначала напишите acceptance criteria, затем реализацию
  • Каждое решение свяжите с конкретным риском или SLO
  • Не добавляйте инструмент без владельца и runbook
  • Используйте immutable versions и digests
  • Проверяйте позитивные и негативные security cases
  • Failure drill должен иметь hypothesis, steady state, action, evidence и recovery
  • Не удаляйте evidence до postmortem
  • Явно отделяйте проверенное от предположений и ограничений среды
08

8. Лабораторная работа: базовая платформа

Сохраните manifest как deploy/base/application.yaml. Он создаёт hardened учебный HTTP workload, Service, PDB, HPA и NetworkPolicy. NetworkPolicy реально применяется только CNI с поддержкой policy.

terminal
apiVersion: v1
kind: Namespace
metadata:
  name: final-project
  labels:
    course.example.com/access: allowed
---
apiVersion: v1
kind: ConfigMap
metadata: {name: web-content, namespace: final-project}
data:
  index.html: |
    <!doctype html>
    <html><body><h1>final-project: ok</h1></body></html>
---
apiVersion: apps/v1
kind: Deployment
metadata: {name: web, namespace: final-project}
spec:
  replicas: 3
  revisionHistoryLimit: 5
  progressDeadlineSeconds: 120
  strategy:
    rollingUpdate: {maxUnavailable: 0, maxSurge: 1}
  selector:
    matchLabels: {app: web}
  template:
    metadata:
      labels: {app: web}
    spec:
      automountServiceAccountToken: false
      securityContext:
        seccompProfile: {type: RuntimeDefault}
      containers:
        - name: web
          image: busybox:1.37.0
          command: ["httpd", "-f", "-p", "8080", "-h", "/www"]
          ports: [{name: http, containerPort: 8080}]
          readinessProbe:
            httpGet: {path: /, port: http}
            initialDelaySeconds: 2
            periodSeconds: 5
          livenessProbe:
            httpGet: {path: /, port: http}
            initialDelaySeconds: 10
            periodSeconds: 10
          resources:
            requests: {cpu: 20m, memory: 16Mi}
            limits: {memory: 32Mi}
          securityContext:
            runAsNonRoot: true
            runAsUser: 65534
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities: {drop: ["ALL"]}
          volumeMounts:
            - {name: content, mountPath: /www, readOnly: true}
      volumes:
        - name: content
          configMap: {name: web-content}
---
apiVersion: v1
kind: Service
metadata: {name: web, namespace: final-project}
spec:
  selector: {app: web}
  ports: [{name: http, port: 80, targetPort: http}]
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: {name: web, namespace: final-project}
spec:
  maxUnavailable: 1
  selector:
    matchLabels: {app: web}
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: {name: web, namespace: final-project}
spec:
  scaleTargetRef: {apiVersion: apps/v1, kind: Deployment, name: web}
  minReplicas: 3
  maxReplicas: 6
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
  metrics:
    - type: Resource
      resource:
        name: cpu
        target: {type: Utilization, averageUtilization: 60}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: {name: web-ingress, namespace: final-project}
spec:
  podSelector:
    matchLabels: {app: web}
  policyTypes: [Ingress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels: {course.example.com/access: allowed}
      ports:
        - {protocol: TCP, port: 8080}
09

9. Лабораторная работа: развёртывание и приёмка

Metrics Server должен работать по модулю 9. Примените точный manifest через Server-Side Apply и проверьте workload, traffic, autoscaling signal и effective permissions.

terminal
kubectl config current-context
kubectl apply --dry-run=server -f deploy/base/application.yaml
kubectl apply --server-side --field-manager=final-project -f deploy/base/application.yaml
kubectl rollout status deployment/web -n final-project --timeout=180s
kubectl wait pod -n final-project -l app=web --for=condition=Ready --timeout=120s
kubectl get deployment,pod,service,endpointslice,poddisruptionbudget,horizontalpodautoscaler -n final-project -o wide
kubectl run smoke -n final-project --rm -i --restart=Never --image=busybox:1.37.0 -- wget -qO- http://web
kubectl top pod -n final-project --containers
kubectl auth can-i --list -n final-project

Критерий: три Ready Pod, три ready endpoint, smoke test возвращает final-project: ok, PDB допускает максимум один voluntary disruption, HPA получает CPU metrics.

10

10. Failure drill №1: потеря Pod

Гипотеза: удаление одного Pod не нарушает доступность и Deployment создаёт экземпляр с новым UID. Сохраните timeline и Events.

terminal
POD="$(kubectl get pod -n final-project -l app=web -o jsonpath='{.items[0].metadata.name}')"
UID_BEFORE="$(kubectl get pod "$POD" -n final-project -o jsonpath='{.metadata.uid}')"
kubectl delete pod "$POD" -n final-project --wait=false
kubectl rollout status deployment/web -n final-project --timeout=120s
kubectl get pod -n final-project -l app=web -o custom-columns='NAME:.metadata.name,UID:.metadata.uid,READY:.status.containerStatuses[0].ready'
kubectl get event -n final-project --sort-by=.metadata.creationTimestamp
test -n "$UID_BEFORE"

Успех: desired replicas восстановлены за 120 секунд, новый UID отличается, smoke/SLI не нарушают выбранный threshold.

11

11. Failure drill №2: ошибочная readiness

Гипотеза: плохая revision не входит в ready endpoints, rollout останавливается, а rollback восстанавливает трафик. Timeout первой команды ожидаем.

terminal
kubectl patch deployment web -n final-project --type=json -p='[{"op":"replace","path":"/spec/template/spec/containers/0/readinessProbe/httpGet/path","value":"/missing"}]'
kubectl rollout status deployment/web -n final-project --timeout=45s
kubectl get pod,endpointslice -n final-project -o wide
kubectl events -n final-project --types=Warning
kubectl rollout undo deployment/web -n final-project
kubectl rollout status deployment/web -n final-project --timeout=180s
kubectl run smoke-after-rollback -n final-project --rm -i --restart=Never --image=busybox:1.37.0 -- wget -qO- http://web

Успех: доказан NotReady нового ReplicaSet, старые endpoints сохраняли обслуживание, rollback завершён менее чем за 10 минут, финальный smoke успешен.

12

12. Failure drill №3: неверный Service selector

Гипотеза: Pods останутся Ready, но Service потеряет endpoints и пользовательский запрос завершится ошибкой. Диагностика должна найти несоответствие labels без restart Pods.

terminal
kubectl patch service web -n final-project --type=merge -p='{"spec":{"selector":{"app":"wrong"}}}'
kubectl get endpointslice -n final-project -l kubernetes.io/service-name=web -o yaml
kubectl run failed-smoke -n final-project --rm -i --restart=Never --image=busybox:1.37.0 -- wget -T 5 -qO- http://web
kubectl get service web -n final-project -o jsonpath='{.spec.selector}{"\n"}'
kubectl get pod -n final-project -l app=web --show-labels
kubectl patch service web -n final-project --type=merge -p='{"spec":{"selector":{"app":"web"}}}'
kubectl run recovered-smoke -n final-project --rm -i --restart=Never --image=busybox:1.37.0 -- wget -qO- http://web

Успех: пустой EndpointSlice объясняет отказ, selector восстановлен минимальным patch, smoke снова успешен. После успешного smoke сохраните evidence и только затем удалите лабораторный namespace.

13

13. Пакет доказательств

До cleanup соберите evidence и сохраните очищенный от чувствительных данных вывод в docs/evidence. Добавьте UTC timestamps, commit SHA, image digest, версии инструментов, ожидаемый и фактический результат.

terminal
git rev-parse HEAD
git status --short
kubectl version
kubectl get deployment web -n final-project -o yaml
kubectl get pod -n final-project -l app=web -o yaml
kubectl get event -n final-project --sort-by=.metadata.creationTimestamp
kubectl get endpointslice -n final-project -l kubernetes.io/service-name=web -o yaml
kubectl top pod -n final-project --containers
kubectl auth can-i --list -n final-project
kubectl delete namespace final-project
  • pipeline URL и security reports
  • Argo CD revision, sync/health и diff
  • rollout history и smoke results
  • SLI dashboard/alert screenshots или экспорт
  • timeline трёх drills
  • найденные ограничения и follow-up actions
14

14. Приёмка и оценивание

  • 20 баллов — воспроизводимый repository и документация
  • 20 — корректные Kubernetes manifests и security context
  • 15 — tests, SBOM, scan, signature и immutable digest
  • 15 — ограниченный Argo CD project и GitOps promotion
  • 15 — metrics/logs, SLI/SLO, alerts и runbook
  • 15 — три воспроизводимых failure drills с evidence

Обязательные стоп-факторы: committed secret/kubeconfig, cluster-admin для приложения или CI, mutable latest в deploy, отсутствующий rollback, неработающий smoke test. Проект принят при 80/100 и отсутствии стоп-факторов.

15

15. Защита проекта

  • Покажите путь commit → digest → Git promotion → Argo revision → Pod imageID
  • Объясните каждое permission и NetworkPolicy rule
  • Докажите, что readiness защищает traffic, а liveness не маскирует dependency failure
  • Рассчитайте error budget и реакцию на быстрый burn
  • Проведите случайно выбранный failure drill без подсказки
  • Назовите три ограничения kind и production mitigation

Курс завершён, если другой инженер по README воспроизводит систему, проверяет её безопасность и наблюдаемость, выполняет drill и восстанавливает steady state без устных инструкций автора.

PDF для работы офлайн

Скачайте оформленную версию модуля для чтения без подключения к сети.

Скачать PDFPDF