Добавление нового окружения в FluxCD hub-and-spoke кластер
Published: 2026-04-30
Полный чеклист для подключения нового окружения — от создания кластера до первого успешного reconcile Flux. На примере гипотетического окружения staging в Yandex Cloud (лёгкий стек, без Kafka/Mongo/Cassandra/ClickHouse).
Общая схема
В hub-and-spoke модели hub-кластер (infra) запускает Flux и управляет spoke-кластерами через kubeConfig в каждом объекте Kustomization. Добавление нового окружения включает:
- Создание Kubernetes-кластера
- Создание структуры директорий FluxCD-проекта
- Создание верхнеуровневого kustomization-файла
- Написание патчей для каждого чарта
- Запечатывание kubeconfig как SealedSecret
- Подключение namespaces и secrets
- Регистрация в корневом kustomization
Шаг 1: создать кластер
Для Yandex Cloud:
bash# Создать через Terraform (или вручную в консоли YC)
yc managed-kubernetes cluster get-credentials staging --external
kubectl config rename-context yc-staging staging-k8s
cp ~/.kube/config .kubeconfigs/staging.yaml
Для on-prem k3s:
bash# Добавить хосты в ansible/inventory/staging/hosts.yaml
# Добавить переменные в ansible/group_vars/staging.yaml
ansible-playbook ansible/install-k3s.yaml -i ansible/inventory/staging/
ansible-playbook ansible/get-kubeconfig.yaml -i ansible/inventory/staging/
ansible-playbook ansible/upgrade-cilium.yaml -i ansible/inventory/staging/
cp ~/.kube/config .kubeconfigs/staging.yaml
Шаг 2: создать структуру проекта
bashmkdir -p fluxcd/projects/staging/kustomization/{hub/patches,spoke/secrets,spoke/monitoring,routes}
За основу взять ближайшее по смыслу окружение. Для лёгкого стека YC лучший шаблон — sre или loadgds:
bashcp fluxcd/projects/sre/kustomization/hub/kustomization.yaml \
fluxcd/projects/staging/kustomization/hub/kustomization.yaml
cp -r fluxcd/projects/sre/kustomization/spoke/ \
fluxcd/projects/staging/kustomization/spoke/
cp fluxcd/projects/sre/kustomization/routes/kustomization.yaml \
fluxcd/projects/staging/kustomization/routes/kustomization.yaml
Шаг 3: создать staging-kustomization.yaml
Скопировать fluxcd/sre-kustomization.yaml → fluxcd/staging-kustomization.yaml и отредактировать:
yaml# Namespace для hub-объектов
apiVersion: v1
kind: Namespace
metadata:
name: staging
---
# SealedSecret placeholder — заполнить на шаге 5
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: staging-kubeconfig
namespace: staging
spec:
encryptedData:
value: PLACEHOLDER
---
# Hub: деплой приложений в staging-кластер
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: staging-apps
namespace: staging
spec:
interval: 10m
path: ./fluxcd/projects/staging/kustomization/hub/
prune: true
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
kubeConfig:
secretRef:
name: staging-kubeconfig
---
# Spoke: ресурсы уровня кластера
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: staging-spoke
namespace: staging
spec:
interval: 10m
path: ./fluxcd/projects/staging/kustomization/spoke/
prune: true
dependsOn:
- name: staging-apps
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
kubeConfig:
secretRef:
name: staging-kubeconfig
---
# Routes: ApisixRoutes и TLS-конфигурация
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: staging-routes
namespace: staging
spec:
interval: 10m
path: ./fluxcd/projects/staging/kustomization/routes/
prune: true
dependsOn:
- name: staging-spoke
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
kubeConfig:
secretRef:
name: staging-kubeconfig
Шаг 4: создать патчи
Один файл патча на каждый Helm chart, только дельта относительно base.
kube-prom-stack.yaml — storageClass, retention, external labels:
yamlspec:
values:
prometheus:
prometheusSpec:
retention: 7d
externalLabels:
cluster: staging # ОБЯЗАТЕЛЬНО уникально для каждого кластера
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: yc-network-ssd
resources:
requests:
storage: 20Gi
grafana:
ingress:
hosts:
- grafana.staging.test.example.com
elasticsearch.yaml — hostname и storage:
yamlspec:
values:
master:
persistence:
storageClass: yc-network-ssd
ingress:
hosts:
- host: elasticsearch.staging.test.example.com
apisix-int.yaml — external IP (YC назначит автоматически):
yamlspec:
values:
service:
type: LoadBalancer
# loadBalancerIP не указывать — YC назначит сам
Шаг 5: запечатать kubeconfig
bashkubectl create secret generic staging-kubeconfig \
--from-file=value=.kubeconfigs/staging.yaml \
--namespace staging \
--dry-run=client -o yaml | \
kubeseal \
--format yaml \
--controller-namespace flux-system \
--kubeconfig .kubeconfigs/infra.yaml \
> /tmp/staging-sealed.yaml
# Скопировать encryptedData.value из /tmp/staging-sealed.yaml
# в fluxcd/staging-kustomization.yaml
# Удалить временный файл
rm /tmp/staging-sealed.yaml
Kubeconfig запечатан ключом Sealed Secrets infra-кластера. При пересборке infra-кластера нужно перезапечатать все kubeconfig'и новым ключом.
Шаг 6: добавить в spoke overlays
Создать fluxcd/projects/staging/kustomization/spoke/namespaces.yaml со списком namespaces. Для лёгкого стека исключить kafka, mongodb, rabbitmq, cassandra, clickhouse.
Добавить docker-registry pull secrets в spoke/secrets/ — скопировать из существующего окружения и перезапечатать с namespace staging.
Для YC-кластеров: убрать cilium-lb-pool.yaml и cilium-l2-announcement.yaml — не нужны.
Шаг 7: создать ApisixTls маршрут
yaml# routes/apisix-tls-staging.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixTls
metadata:
name: staging-example-com
namespace: ingress-apisix
spec:
hosts:
- "*.staging.test.example.com"
secret:
name: staging-example-com-tls
namespace: ingress-apisix
TLS-сертификат и ключ добавить как SealedSecret в spoke/secrets/.
Шаг 8: зарегистрировать в корневом kustomization
yaml# fluxcd/kustomization.yaml
resources:
- flux-system/
- infra-kustomization.yaml
- dev-kustomization.yaml
- test-kustomization.yaml
- sre-kustomization.yaml
- loadgds-kustomization.yaml
- staging-kustomization.yaml # ← добавить
Шаг 9: commit, push, проверка
bashgit add fluxcd/
git commit -m "feat: add staging environment"
git push
# Ждём, пока Flux подберёт изменения (обычно 2-3 минуты), затем проверяем
flux get kustomizations -A --context=infra-k8s | grep staging
# Принудительный reconcile если нужно
flux reconcile ks staging-apps -n staging --context=infra-k8s --timeout=10m
# Проверить поды на новом кластере
kubectl get pods -A --context=staging-k8s
Типичные ошибки
- Забыть
externalLabels.clusterв kube-prom-stack — Grafana не сможет отличить метрики staging от dev. Значение должно быть уникальным для каждого кластера. - Нет поля
namespaceв патче — Kustomize не найдёт целевой HelmRelease. Целевой объект в патче должен включать namespace. dependsOnуказывает на несуществующий объект — проверить, что имена объектов Kustomization вspoke.yamlиmonitoring.yamlсовпадают точно.- Отсутствует TLS-сертификат — если APISIX стартует до расшифровки TLS SealedSecret, маршруты упадут. Цепочка
dependsOnобеспечивает порядок. - Неправильный контекст в kubeconfig — запечатанный kubeconfig должен содержать полный путь к серверу, а не alias, существующий только локально.
- Скопировать патчи с Cilium L2 на YC-кластер — убрать поле
loadBalancerIP; YC назначает автоматически.