10. Управление конфигурацией: исходный YAML, Kustomize, Helm, GitOps
Незнакомый термин? Откройте словарь Kubernetes и терминов курса.
Назначение, предварительные знания и результаты обучения
Нужны главы 00–09 и базовые манифесты. После главы вы сможете:
- выбрать исходные манифесты, наложения Kustomize или chart Helm;
- объяснить наложение patches в сравнении с шаблонизацией;
- отделить успешный рендеринг от проверки API и среды исполнения;
- получить детерминированное сравнение
devиprod; - обнаружить и устранить расхождение;
- описать риски согласования,
pruneи секретов в GitOps; - не смешивать конфигурацию окружения со скопированным устаревшим YAML.
Ментальная модель: исходник → рендеринг → проверка → согласование
исходные файлы + входные данные среды
↓ рендеринг
полные объекты Kubernetes
↓ синтаксис/схема клиента
↓ схема/значения по умолчанию/admission/аутентификация сервера
сохранённые желаемые объекты
↓ контроллеры/среда исполнения
наблюдаемая нагрузка
Каждый этап отвечает на другой вопрос. helm template/kubectl kustomize
могут успешно вывести синтаксически корректный YAML с несуществующим API,
неправильным полем, отсутствующим Secret или невыполнимым планированием.
Шаблонизация не равна проверке API; серверный dry-run не доказывает здоровую среду
исполнения.
Три подхода
Исходные манифесты
Плюсы: Kubernetes API виден, меньше инструментов, удобно для обучения и небольшого сервиса. Минусы: дублирование окружений, ручные хеши rollout, распространение и версионирование. Исходный YAML уместен, пока повторение и API для потребителя не стали сложнее самого ресурса.
Kustomize
Kustomize выполняет структурные преобразования и patches без универсального
языка шаблонов. Базовый набор остаётся корректным Kubernetes YAML, наложения выражают
дельту. Встроен в kubectl -k.
Базовый набор:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- configmap.yaml
- serviceaccount.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
- networkpolicy.yaml
- pdb.yaml
- hpa.yaml
- rbac.yaml
Наложение:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: deployment-patch.yaml
- path: hpa-patch.yaml
- path: configmap-patch.yaml
Это конфигурация для рендерера, а не объект Kubernetes API; у Kustomization нет
metadata/spec. Его результат содержит полные объекты. Например, patch:
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-api
namespace: kube-course
spec:
replicas: 1
template:
spec:
containers:
- name: api
resources:
requests:
cpu: 50m
memory: 64Mi
ephemeral-storage: 32Mi
limits:
cpu: 250m
memory: 192Mi
ephemeral-storage: 128Mi
Стратегическое слияние сопоставляет ресурс по GVK, имени и namespace, а элементы списка — по ключу слияния, например имени контейнера. Проверяйте отрендеренный результат: неверный patch списка может заменить весь список.
Helm
Chart Helm — упакованный параметризованный шаблон с Chart.yaml, values.yaml,
шаблонами и состоянием выпуска. Он подходит для распространения ПО среди
многих потребителей, условных ресурсов и пакетов экосистемы. Цена — сложность
шаблонов Go, совместимость API значений, ошибки пробелов и типов и скрытый
итоговый YAML.
helm template рендерит локально; helm install/upgrade управляет выпуском.
Обработчики имеют отдельный жизненный цикл и могут сделать обновление неатомарным.
CRDs из crds/ требуют отдельного плана обновления. --atomic полезен, но не
откатывает внешние побочные эффекты и миграции БД. Всегда проверяйте:
helm lint ./chart
helm template python-api ./chart -f values-prod.yaml > /tmp/rendered.yaml
kubectl apply --dry-run=server -f /tmp/rendered.yaml
Курс не добавляет chart Helm ради дублирования работающих ресурсов Kustomize: задача — понять интерфейс и компромиссы. Для внутреннего приложения наложения проще. Для распространяемого компонента платформы chart может быть лучше.
Практическое упражнение: детерминированный рендеринг и сравнение
Рендеринг
kubectl kustomize manifests/overlays/dev > /tmp/python-api-dev.yaml
kubectl kustomize manifests/overlays/prod > /tmp/python-api-prod.yaml
kubectl kustomize manifests/overlays/dev > /tmp/python-api-dev-second.yaml
cmp /tmp/python-api-dev.yaml /tmp/python-api-dev-second.yaml
Ожидается код 0 от cmp: одинаковый исходник даёт побайтово идентичный
результат рендеринга.
Проверяйте без ненадёжного визуального просмотра:
kubectl kustomize manifests/overlays/dev |
kubectl apply --dry-run=client -f -
kubectl apply --dry-run=server -f /tmp/python-api-dev.yaml
kubectl diff -f /tmp/python-api-dev.yaml
Код 0 от kubectl diff означает отсутствие различий, 1 — наличие различий,
а код больше 1 — ошибку. Не оборачивайте команду так, чтобы любой ненулевой
код игнорировался.
Сравните значимые поля:
diff -u /tmp/python-api-dev.yaml /tmp/python-api-prod.yaml
rg -n 'replicas:|cpu:|memory:|APP_MESSAGE|FEATURE_COLOR' \
/tmp/python-api-dev.yaml /tmp/python-api-prod.yaml
Ожидается: в dev меньше реплик, ресурсов и границ HPA, а в prod больше ресурсов.
Сгенерированные порядок и детали могут зависеть от версии kubectl/Kustomize;
фиксируйте версию инструмента в CI.
Применить наложение dev и проверить владение
test "$(kubectl config current-context)" = "kind-kube-course"
kubectl apply -k manifests/overlays/dev
kubectl rollout status deployment/python-api -n kube-course --timeout=180s
kubectl get deployment python-api -n kube-course \
-o jsonpath='{.spec.replicas}{" replicas\n"}'
HPA может сразу изменить число реплик в разрешённом диапазоне, поэтому исходное
replicas: 1 не гарантирует фактическое значение после согласования HPA.
Это пример нескольких владельцев поля.
Упражнение по расхождениям
kubectl annotate service python-api -n kube-course \
course.example.com/manual-drift=true --overwrite
kubectl diff -k manifests/overlays/dev
kubectl apply -k manifests/overlays/dev
kubectl get service python-api -n kube-course \
-o jsonpath='{.metadata.annotations.course\.example\.com/manual-drift}{"\n"}'
Если аннотация не принадлежит менеджеру поля или источнику применения, применение может её не удалить. Определение расхождения зависит от владения. Удалите явно:
kubectl annotate service python-api -n kube-course \
course.example.com/manual-drift-
Используйте metadata.managedFields для расследования владения полями, но не
сохраняйте его в Git.
Секреты и сгенерированные имена
secret.example.yaml содержит только заглушку для лаборатории и схемы и
намеренно не включён в Kustomization. Эксплуатационный конвейер обязан отдельно
доставить Secret одобренным способом до rollout. Не помещайте настоящий секрет
в значения Helm, отрендеренный артефакт или журнал CI.
Kustomize configMapGenerator/secretGenerator добавляет хеш содержимого в
имя, а ссылки преобразуются; изменение меняет шаблон Pod и вызывает rollout.
Плюсы — неизменяемая версия и автоматический rollout, минусы — сборка мусора и
открытый текст Secret в локальном исходнике Kustomize, если генератор читает
литеральное значение. Используйте процесс с зашифрованным или внешним секретом.
Обзор GitOps
Контроллер GitOps, например дополнения экосистемы Flux или Argo CD, получает и согласует объявленный источник с кластером. Он даёт непрерывное исправление расхождений, инвентаризацию и след проверки и аудита. Плохой манифест от этого не становится хорошим.
Проектные решения:
- неизменяемые коммит, артефакт и digest как продвигаемая единица;
- один авторитетный владелец каждого поля;
- проверки здоровья и процедура rollback или возврата изменения;
pruneудаляет отсутствующие объекты — это мощная разрушающая операция;- волны синхронизации, обработчики, CRDs и порядок зависимостей с возможной задержкой;
- граница расшифрования секретов и ключи;
- экстренное изменение с последующим согласованием исходника.
Не включайте автоматический prune во всём кластере до проверки инвентаризации, области действия и резервной копии.
Самостоятельная задача
Добавьте наложение staging только как разницу: две реплики, HPA 2–4,
FEATURE_COLOR: amber, ресурсы и Pod Security, похожие на prod. Выполните
рендеринг дважды и серверный dry-run, покажите сравнение с dev и prod. Критерий
приёмки: базовый набор не скопирован, настоящих Secrets нет, все целевые patches
нашли ровно один ресурс.
Сломанное наложение
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-ap1
namespace: kube-course
spec:
replicas: 9
Добавьте patch с неверным именем во временное наложение. Современный Kustomize
должен завершиться ненулевым кодом с
no matches for Id ...; failed to find unique target. Если преобразователь
создаёт неожиданный вывод, проверьте число и имена ресурсов:
kubectl kustomize /tmp/broken-overlay
Исправьте точные GVK, имя и namespace. Не добавляйте второй Deployment, чтобы «patch нашёлся»: это меняет архитектуру.
Дерево диагностических решений
Доставленное состояние не совпадает с ожидаемым
├─ рендеринг завершается ошибкой → путь, цель patch, функция/тип YAML/шаблона
├─ рендеринг успешен, клиент завершается ошибкой → локальная схема/синтаксис/версия инструмента
├─ клиент успешен, сервер отклоняет → версия API/admission/RBAC/неизменяемое поле
├─ сервер принимает, rollout завершается ошибкой → ссылка на конфигурацию/образ/назначение/проверка
└─ живое состояние отличается
├─ полем владеет HPA/контроллер → ожидаемое совместное владение
├─ полем владеет ручной менеджер → managedFields/политика расхождений
├─ неверный источник/revision GitOps → status контроллера/артефакт
└─ мутация вебхуком/значения по умолчанию → сравнить объект сервера и результат рендеринга
Типичные ошибки: копирование каталогов окружений; шаблон заключает числа и
логические значения в кавычки; helm template считается проверкой; плавающая
зависимость chart; Secret из эксплуатационной среды попадает в значения или результат
рендеринга; patch Kustomize незаметно заменяет список контейнеров или окружения;
HPA и GitOps спорят; prune применяется без инвентаризации.
Эксплуатационные компромиссы, безопасность и стоимость
Более высокий уровень абстракции снижает повторение, но усложняет проверку и диагностику. Рендерер, дополнение и chart — код цепочки поставки; фиксируйте версии и digests, проверяйте происхождение. Отрендеренные манифесты могут содержать секреты и требуют политики срока хранения и доступа. Контроллер GitOps имеет широкие разрешения на запись и удаление: ограничивайте область namespace, где возможно, аудитируйте и защищайте ветку исходников. Сканирование расхождений и опрос API имеют стоимость для плоскости управления; выбирайте интервал по риску, а не секунды по умолчанию.
Самопроверка
- Проверяет ли
helm templateadmission? - Чем patch отличается от шаблона?
- Почему результат рендеринга нужно хранить и проверять в CI?
- Что означает код завершения 1 у
kubectl diff? - Почему фактическое число реплик может отличаться от исходника?
- Чем опасен GitOps prune?
- Должны ли настоящие секреты находиться в значениях Helm?
Ответы: 1) нет; 2) структурная разница для корректных ресурсов в сравнении с генерацией текста; 3) это фактическая полезная нагрузка API; 4) есть различия, это не ошибка выполнения; 5) HPA или другой владелец поля; 6) удаляет объекты, отсутствующие в инвентаризации; 7) нет.
Резюме и источники
Сохраняйте авторитетный источник, детерминированный рендеринг и явную цепочку проверок. Далее: промышленная эксплуатация.