Модуль 15 / 19
Helm, Kustomize та відтворювана доставка
Зміст
1. Цілі та результат модуля
Ви навчитеся відокремлювати source manifests від rendered output, обирати Kustomize чи Helm і проводити зміну через render, validation, diff, apply/upgrade та rollback.
- Kustomize перетворює Kubernetes resources без шаблонної мови
- Helm пакує templates, values і release lifecycle
- rendered YAML перевіряють до mutation
- version chart не дорівнює appVersion
- секрети не можна безпечно зберігати у values.yaml
2. Теорія: відтворювана доставка
Відтворюваність потребує зафіксованих версій tool/chart/image, reviewable inputs та однакового render. Команда, залежна від latest, локальних файлів або ручного --set без запису, погано відтворюється.
Package manager не замінює CI, policy, observability і backup. Він відповідає за формування та lifecycle набору Kubernetes objects.
3. Kustomize: base та overlays
Kustomize працює зі структурованими Kubernetes resources. Base містить спільне, overlay додає environment-specific namespace, patches, images, replicas і generators. Він вбудований у kubectl як apply -k та kustomize.
configMapGenerator додає content hash до імені й оновлює references, тому зміна конфігурації змінює Pod template та може викликати rollout.
4. Helm: chart, values і release
Chart містить Chart.yaml, defaults values.yaml, templates та optional schema. Helm render використовує release context і values; install/upgrade зберігають release revisions. appVersion — метадані застосунку, version — версія package chart.
Values — публічний configuration interface chart. Надто гнучкі templates стають неперевірною програмою; values.schema.json робить контракт явним.
5. Install, upgrade і rollback
upgrade --install ідемпотентно обирає створення чи зміну release. --wait чекає готовності resources до timeout. history показує revisions, rollback створює нову revision на основі старої.
Rollback manifests не відкочує зовнішні side effects, database migration чи вміст PV. Сумісність даних планують окремо.
6. CRD, hooks, secrets і ownership
CRDs у chart мають особливий lifecycle і зазвичай не видаляються автоматично. Hooks — Jobs/resources поза звичайним порядком, їх side effects мають бути ідемпотентними. Перед чужим chart вивчайте rendered RBAC, securityContext, images і cluster-scoped objects.
Helm values та rendered Secret — не secret storage. Використовуйте зовнішнє керування секретами й не передавайте їх у command history.
7. Методичні вказівки
- Фіксуйте tool, chart та image versions
- Спочатку lint/render, потім server dry-run і diff
- Зберігайте environment inputs у Git
- Не редагуйте rendered YAML вручну
- Не змішуйте ownership Helm і kubectl одного поля
- Перевіряйте cluster-scoped resources і hooks
- Тестуйте rollback разом із даними
- Не використовуйте --set для недокументованих production changes
8. Лабораторна робота: Kustomize overlay
Base задає один Deployment, overlay — namespace, prefix, дві replicas та APP_MODE=lab. Перевірте hash ConfigMap і автоматично переписану reference.
mkdir -p /tmp/k8s-m15/kustomize/base /tmp/k8s-m15/kustomize/overlays/lab
cat > /tmp/k8s-m15/kustomize/base/deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata: {name: app}
spec:
replicas: 1
selector: {matchLabels: {app: kustomize-web}}
template:
metadata: {labels: {app: kustomize-web}}
spec:
containers:
- name: nginx
image: nginx:1.29-alpine
envFrom: [{configMapRef: {name: app-config}}]
EOF
cat > /tmp/k8s-m15/kustomize/base/kustomization.yaml <<'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources: [deployment.yaml]
configMapGenerator:
- name: app-config
literals: [APP_MODE=base]
EOF
cat > /tmp/k8s-m15/kustomize/overlays/lab/kustomization.yaml <<'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: k8s-m15-kustomize
namePrefix: lab-
resources: [../../base]
replicas:
- {name: app, count: 2}
configMapGenerator:
- name: app-config
behavior: merge
literals: [APP_MODE=lab]
EOFkubectl create namespace k8s-m15-kustomize
kubectl kustomize /tmp/k8s-m15/kustomize/overlays/lab > /tmp/k8s-m15/rendered.yaml
sed -n '1,160p' /tmp/k8s-m15/rendered.yaml
kubectl apply --dry-run=server -f /tmp/k8s-m15/rendered.yaml
kubectl diff -k /tmp/k8s-m15/kustomize/overlays/lab || [ "$?" -eq 1 ]
kubectl apply --server-side --field-manager=kustomize-lab -k /tmp/k8s-m15/kustomize/overlays/lab
kubectl -n k8s-m15-kustomize rollout status deployment/lab-app --timeout=120s
kubectl -n k8s-m15-kustomize get deployment,configmap,pod
kubectl -n k8s-m15-kustomize get deployment lab-app -o jsonpath='{.spec.template.spec.containers[0].envFrom[0].configMapRef.name}{"\n"}'9. Лабораторна робота: власний Helm chart
Мінімальний chart має явний values contract. Виконайте lint, збережіть render, проведіть server dry-run і лише потім створіть release.
mkdir -p /tmp/k8s-m15/chart/templates
cat > /tmp/k8s-m15/chart/Chart.yaml <<'EOF'
apiVersion: v2
name: course-web
description: Minimal chart for Kubernetes Fundamentals module 15
type: application
version: 0.1.0
appVersion: "1.29"
EOF
cat > /tmp/k8s-m15/chart/values.yaml <<'EOF'
replicaCount: 2
image: {repository: nginx, tag: 1.29-alpine}
service: {port: 80}
EOF
cat > /tmp/k8s-m15/chart/values.schema.json <<'EOF'
{"$schema":"https://json-schema.org/draft-07/schema#","type":"object","required":["replicaCount","image","service"],"properties":{"replicaCount":{"type":"integer","minimum":1,"maximum":5},"image":{"type":"object","required":["repository","tag"]},"service":{"type":"object","required":["port"]}}}
EOF
cat > /tmp/k8s-m15/chart/templates/_helpers.tpl <<'EOF'
{{- define "course-web.name" -}}course-web{{- end -}}
EOF
cat > /tmp/k8s-m15/chart/templates/deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "course-web.name" . }}
labels: {app.kubernetes.io/name: {{ include "course-web.name" . }}, app.kubernetes.io/managed-by: {{ .Release.Service }}}
spec:
replicas: {{ .Values.replicaCount }}
selector: {matchLabels: {app.kubernetes.io/name: {{ include "course-web.name" . }}}}
template:
metadata: {labels: {app.kubernetes.io/name: {{ include "course-web.name" . }}}}
spec:
containers:
- name: nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports: [{name: http, containerPort: {{ .Values.service.port }}}]
EOF
cat > /tmp/k8s-m15/chart/templates/service.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata: {name: {{ include "course-web.name" . }}}
spec:
selector: {app.kubernetes.io/name: {{ include "course-web.name" . }}}
ports: [{name: http, port: {{ .Values.service.port }}, targetPort: http}]
EOFhelm version --short
helm lint /tmp/k8s-m15/chart
helm template course-web /tmp/k8s-m15/chart --namespace k8s-m15-helm > /tmp/k8s-m15/helm-rendered.yaml
kubectl apply --dry-run=server -f /tmp/k8s-m15/helm-rendered.yaml
helm upgrade --install course-web /tmp/k8s-m15/chart \
--namespace k8s-m15-helm --create-namespace --wait --timeout 3m
helm status course-web -n k8s-m15-helm
kubectl -n k8s-m15-helm get deployment,service,pod10. Лабораторна робота: upgrade і rollback
Змініть replicas через values, дослідіть effective values/history, потім поверніться до revision 1. Після rollback історія отримує нову revision.
helm upgrade course-web /tmp/k8s-m15/chart -n k8s-m15-helm \
--set replicaCount=3 --wait --timeout 3m
helm get values course-web -n k8s-m15-helm --all
helm history course-web -n k8s-m15-helm
kubectl -n k8s-m15-helm get deployment course-web
helm rollback course-web 1 -n k8s-m15-helm --wait --timeout 3m
helm history course-web -n k8s-m15-helm
kubectl -n k8s-m15-helm get deployment course-web11. Діагностика до mutation
Рядок zero порушує JSON Schema integer, і upgrade не створює revision. Зламаний Kustomize path також припиняє render; уже застосований Deployment не змінюється.
helm upgrade course-web /tmp/k8s-m15/chart -n k8s-m15-helm \
--set-string replicaCount=zero || true
helm history course-web -n k8s-m15-helm
kubectl -n k8s-m15-helm get deployment course-web -o jsonpath='replicas={.spec.replicas}{"\n"}'
cp -a /tmp/k8s-m15/kustomize/overlays/lab /tmp/k8s-m15/kustomize/overlays/broken
sed -i 's#../../base#../../missing-base#' /tmp/k8s-m15/kustomize/overlays/broken/kustomization.yaml
kubectl kustomize /tmp/k8s-m15/kustomize/overlays/broken || true
kubectl -n k8s-m15-kustomize get deployment lab-appПорядок: versions/dependencies → input values/overlay → lint/build → rendered YAML → schema/server dry-run → diff → release events/status → workload diagnostics.
12. Контроль, критерії засвоєння та cleanup
- Чим base відрізняється від overlay?
- Навіщо hash ConfigMap?
- version проти appVersion?
- Що зберігає Helm revision?
- Rollback видаляє database migration?
- Навіщо values schema?
- Чому rendered Secret небезпечний?
- Чим hook небезпечніший за resource?
- Чи можна змішувати Helm і kubectl ownership?
- Чому latest руйнує відтворюваність?
helm uninstall course-web -n k8s-m15-helm
kubectl delete namespace k8s-m15-helm k8s-m15-kustomize --ignore-not-found --wait=true
rm -rf /tmp/k8s-m15
helm list -A
kubectl get namespace k8s-m15-helm k8s-m15-kustomize 2>&1 || trueМодуль засвоєно, якщо ви отримуєте однаковий render із зафіксованих inputs, проводите Helm upgrade/rollback і блокуєте неправильне значення до mutation.