← До програми курсу

Модуль 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 або export
  • 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