10. Архитектура репозиториев GitOps
Очень важный, часто недооцененный блок: как организовать репозитории и вложить структуру так, чтобы управление несколькими приложениями оставалось управляемым, проверяемым и безопасным.
Термины и сущности
| Термин | Определение |
|---|---|
| Monorepo | Один репозиторий для множества приложений/компонентов. |
| Multirepo | Отдельные репозитории для разных приложений/команд. |
| App-of-apps | Паттерн, где существует “root” (корневое) приложение Argo CD, синхронизирующее манифесты “child”-приложений. |
| Root application | Приложение, которое применяет/обновляет набор child Applications (или манифесты, которые их создают). |
| Child application | Приложение Argo CD, которое управляет конкретным Kubernetes-набором ресурсов (Deployment/Service/CRDs и т.п.). |
| Repository contract | Согласованный “контракт” структуры репозитория: где лежат манифесты, как выбирается environment, какие переменные ожидаются. |
Monorepo vs multirepo: как выбрать
Monorepo — когда это выигрышно
Подходит, когда:
- команды готовы совместно поддерживать единый стандарт структуры (repository contract),
- важно простое атомарное изменение набора компонентов,
- релизы/зависимости между приложениями часто идут вместе,
- требуется единый pipeline контроля качества (lint/test/build) с понятной промо-логикой.
Риски:
- широкий blast radius (ошибка может затронуть больше приложений),
- сложнее разграничивать доступы по репозиториям (нужно делать это на уровне Argo/AppProject и RBAC).
Multirepo — когда это выигрышно
Подходит, когда:
- у команд разные циклы поставки и ownership,
- нужна сильная изоляция (и по CI/CD, и по доступам),
- критична независимость версий/релизов.
Риски:
- больше “интеграционной” работы (сборка env-оверлеев, консистентность стандартов),
- сложнее управлять межкомпонентными релизами и зависимостями.
Production best practice (независимо от формата)
- задайте и документируйте
repository contract, - используйте
AppProjectдля per-app периметра (что разрешено откуда/куда), - стремитесь к “маленьким” приложениями Argo CD (меньше ответственности на один child app).
App-of-apps pattern: идея и назначение
Если у вас 10, 50 или 200 child applications, то руками управлять каждым становится трудно. App-of-apps решает это так:
- root application держит “каталог” child applications,
- child applications продолжают отвечать за конкретный workload,
- изменения набора приложений делаются через Git так же, как и изменения самих workload.
Типовая схема в репозитории:
apps/— каталог child Applications (YAML),apps/<env>/— окружения (dev/stage/prod) или overlays,clusters/— опционально: конфигурации для разных кластеров.
Пример: root application (управляет child Applications)
Идея: root application синхронизирует директорию с манифестами child Application CR.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-applications
namespace: argocd
spec:
project: default
source:
repoURL: https://git.example.com/platform/gitops.git
targetRevision: main
path: apps
directory:
recurse: true # позволяет root находить много child Application манифестов в поддиректориях
destination:
server: https://kubernetes.default.svc
namespace: argocd # где создаются child Applications (обычно argocd)
syncPolicy:
automated:
prune: true # важно только если набор child apps управляется исключительно из этого каталога
selfHeal: true # если манифесты child apps “сломались” — root вернет их в желаемое состояние
syncOptions:
- CreateNamespace=true
- PruneLast=true # снижает риск “невалидного порядка” при удалении ресурсов
Production нюанс:
- если вы включаете
prune: trueна root, убедитесь, что каталогapps/является полной картиной для всех child applications, иначе можно случайно удалить “лишнее”.
Пример: child application (управляет конкретным workload)
Например, child application для orders-api:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: orders-api
namespace: argocd
spec:
project: prod-orders # AppProject ограничивает периметр
source:
repoURL: https://git.example.com/services/orders-api.git
targetRevision: v1.2.3
path: deploy/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # уборка “мертвых” ресурсов при изменениях манифестов
selfHeal: true
Комментарий по production:
- фиксируйте
targetRevisionна релизных тегах или git sha в production (неmain), чтобы избежать неожиданных обновлений.
Пример: AppProject как “периметр” (guardrails)
AppProject ограничивает, какие репозитории и destinations разрешены child applications.
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: prod-orders
namespace: argocd
spec:
sourceRepos:
- 'https://git.example.com/services/*' # разрешаем только нужные сервисы
destinations:
- namespace: production
server: https://kubernetes.default.svc
# Дополнительно можно ограничивать разрешенные cluster-scoped ресурсы через resourceWhitelist.
Практика: реализовать root application и child apps
Шаги (минимально необходимое):
1) Создайте в apps/ каталог манифестов child Application CR.
2) Разверните root application (он создаст/обновит child applications).
3) Проверьте, что child приложения получают желаемое состояние и у них health “green”.
Команды:
argocd app get root-applications
# убедиться, что child приложения создались/обновились
argocd app list | rg "orders-api|payments-api"
Production debug:
- если child application не появляется, сначала проверьте, что root application синхронизировал каталог
apps/(sync status + events), - затем проверьте RBAC: child Applications должны создаваться в namespace, куда у root есть доступ.
Best practices: production checklist
| Практика | Зачем |
|---|---|
Четкий repository contract |
Меньше “магии” и ручных правок. |
| Root app управляет только набором child apps из одного каталога | Безопаснее prune. |
AppProject как периметр |
Снижение риска “не туда применили”. |
| Production фиксирует версии через tags/sha | Предсказуемые релизы. |
| Минимизируйте “ответственность” на один child app | Быстрее расследования и изменения. |