160 lines
7.6 KiB
Markdown
160 lines
7.6 KiB
Markdown
# Argo CD architecture
|
|
|
|
## Control-plane ownership
|
|
|
|
Controller 설치 후 다음 두 bootstrap object를 순서대로 수동 seed합니다.
|
|
|
|
1. `bootstrap/argocd/control-plane-project.yaml`
|
|
2. `bootstrap/argocd/root-application.yaml`
|
|
|
|
`gitops-control-plane` AppProject는 canonical Gitea repository와 in-cluster
|
|
`argocd` namespace, AppProject/ApplicationSet kind만 허용합니다. 단일 root
|
|
Application은 이 Project를 사용하고 다음 control-plane 구성을 source로
|
|
사용합니다.
|
|
|
|
```text
|
|
platform/control-plane/argocd
|
|
├── projects
|
|
│ ├── platform-addons.yaml
|
|
│ ├── platform-services.yaml
|
|
│ ├── systems.yaml
|
|
│ └── workloads.yaml
|
|
└── application-sets
|
|
├── platform-addons.yaml
|
|
├── platform-services.yaml
|
|
├── systems.yaml
|
|
└── workloads.yaml
|
|
```
|
|
|
|
Root는 AppProject와 ApplicationSet까지만 직접 소유합니다. 각
|
|
ApplicationSet의 list inventory가 실제 child Application을 생성합니다.
|
|
Routine 변경에 category별 root나 직접 `kubectl apply`를 추가하지 않습니다.
|
|
|
|
## AppProject boundary
|
|
|
|
| AppProject | 소유 범위 | 허용 destination |
|
|
|---|---|---|
|
|
| `platform-addons` | Sealed Secrets, Vault Agent Injector 같은 외부 cluster addon | `kube-system`, `vault` |
|
|
| `platform-services` | 저장소가 소유하는 Vault shared service | `vault` |
|
|
| `systems` | Project Auth 전용 PostgreSQL, Keycloak, sync job | `auth-system-dev` |
|
|
| `workloads` | first-party `auth-server`, `api-server` | `auth-dev`, `api-dev` |
|
|
|
|
Project는 ApplicationSet 파일마다 고정하며 inventory 값으로 template하지
|
|
않습니다. 이렇게 해야 element 변경으로 권한 경계를 넘을 수 없습니다.
|
|
각 Project는 필요한 source repository, destination, resource kind만
|
|
allowlist합니다.
|
|
|
|
## ApplicationSet contract
|
|
|
|
ApplicationSet은 strict Go template와 list generator를 사용합니다.
|
|
|
|
- `goTemplate: true`
|
|
- `goTemplateOptions: ["missingkey=error"]`
|
|
- 공통 element: `component`, `cluster`, `server`, `namespace`, quoted string
|
|
`autoSync`
|
|
- Git source element: ownership grammar를 따르는 `path`; `targetRevision`은
|
|
template의 `main`으로 고정
|
|
- Helm addon element: allowlisted `repoURL`, `chart`, chart `revision`,
|
|
`helmValues`
|
|
- 파일별 고정 project
|
|
|
|
필수 key가 빠지면 빈 문자열로 잘못 배포하지 않고 render가 실패해야 합니다.
|
|
Application 이름, destination, source path는 같은 element에서 파생하되
|
|
project와 Git repository/revision trust boundary는 template하지 않습니다.
|
|
외부 addon의 Helm `repoURL`은 element에서 template되지만 고정 AppProject의
|
|
`sourceRepos` allowlist 밖 URL은 sync할 수 없습니다.
|
|
|
|
## `autoSync` stage gate
|
|
|
|
`autoSync`는 bootstrap 준비 상태와 routine reconciliation을 분리합니다.
|
|
Inventory schema는 Go template 비교를 위해 boolean이 아닌 quoted string
|
|
`"true"`/`"false"`를 사용합니다. Template patch는 값이 `"true"`인
|
|
element에만 다음 정책을 추가합니다.
|
|
|
|
```yaml
|
|
syncPolicy:
|
|
automated:
|
|
enabled: true
|
|
prune: true
|
|
selfHeal: true
|
|
```
|
|
|
|
초기 gate는 다음과 같습니다.
|
|
|
|
| Application | 초기 `autoSync` | 열기 전 확인 |
|
|
|---|---:|---|
|
|
| Sealed Secrets | `"true"` | Argo가 chart source를 읽을 수 있음 |
|
|
| Vault | `"true"` | dev PVC와 NetworkPolicy 변경 검토 |
|
|
| Vault Agent Injector | `"false"` | Vault init, `vault-foundation`, `vault-workloads`, runtime secret seed 완료 |
|
|
| `auth-system` | `"false"` | Injector Healthy와 Vault login/secret capability 확인 |
|
|
| `auth-server` | `"false"` | PostgreSQL Healthy, `vault-database`, Keycloak/sync 준비 완료 |
|
|
| `api-server` | `"false"` | `auth-server` Healthy와 호출 경로 확인 |
|
|
|
|
Gate는 단계별 PR로 하나씩 엽니다. `false`여도 Application 생성과 diff
|
|
표시는 계속되며 수동 Sync 자체를 기술적으로 막지는 않습니다. 따라서
|
|
Argo RBAC에서 sync 권한을 제한하고, 수동 Sync에는 명시적 change record를
|
|
요구합니다.
|
|
|
|
비활성 기간 동안 쌓인 모든 diff가 gate를 여는 순간 함께 반영됩니다.
|
|
`autoSync: "true"` PR은 현재 live-to-desired 전체 diff를 검토한 뒤
|
|
승인해야 합니다.
|
|
|
|
## Ordering과 failure handling
|
|
|
|
Control-plane sync wave는 AppProject(`-10`)를 ApplicationSet(`-5`)보다
|
|
먼저 생성합니다. 네 ApplicationSet은 모두 같은 wave이고 element별
|
|
stage/wave field는 없습니다. Generated Application의 실제 readiness
|
|
순서는 `autoSync` 전환과 health 확인이 담당합니다.
|
|
|
|
Vault Agent, workload와 hook은 선행 API가 늦게 준비될 때 retry할 수 있어야
|
|
합니다. `auth-system`의 Keycloak client sync와 `auth-server`의 database
|
|
migration은 idempotent Sync hook입니다. Hook을 사용하는 Application에는
|
|
`ApplyOutOfSyncOnly=true`를 설정하지 않습니다.
|
|
|
|
Generated Application은 automated 상태에서 `PruneLast=true`와
|
|
`FailOnSharedResource=true`를 사용합니다. ApplicationSet은
|
|
`applicationsSync: create-update`와 `preserveResourcesOnDeletion: true`를
|
|
사용합니다. Parent prune과 Application 삭제에는 확인을 요구합니다.
|
|
CRD와 cluster-wide RBAC를 포함할 수 있는 `platform-addons`는
|
|
Application-level `Prune=confirm`도 사용하므로 chart upgrade의 삭제는
|
|
별도 승인이 필요합니다.
|
|
Stateful path rename이나 ownership 이동은 별도 migration으로 수행하며
|
|
ApplicationSet element를 먼저 삭제하지 않습니다.
|
|
|
|
`create-update`에서는 generator element를 제거해도 기존 generated
|
|
Application이 자동 삭제되지 않고 stale 상태로 남습니다. Element 제거와
|
|
Application/resource decommission은
|
|
[application decommission runbook](../runbooks/application-decommission.md)의
|
|
inventory, gate, backup, 명시적 삭제 절차를 따릅니다.
|
|
|
|
## Generator 확장 기준
|
|
|
|
현재는 cluster가 `dev-k3s` 하나이므로 네 ApplicationSet의 explicit List
|
|
generator가 가장 쉽게 검토됩니다. 존재하지 않는 production이나 미래
|
|
cluster를 위해 Matrix abstraction을 미리 만들지 않습니다.
|
|
|
|
두 번째 실제 cluster가 생겨 `cluster`, `server`와 cluster별 gate를 여러
|
|
component에서 반복하게 될 때 `clusters/<cluster>/config.yaml`을 Git files
|
|
generator로 읽고 component inventory와 Matrix generator로 결합합니다.
|
|
그때도 AppProject는 ApplicationSet template에 고정하고, cluster별
|
|
`autoSync`는 quoted string과 승인 gate로 유지합니다.
|
|
|
|
## Further reading
|
|
|
|
- Argo CD: [cluster bootstrapping](https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-bootstrapping/),
|
|
[ApplicationSet modification policy](https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Controlling-Resource-Modification/),
|
|
[ApplicationSet deletion](https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Application-Deletion/),
|
|
[automated sync semantics](https://argo-cd.readthedocs.io/en/stable/user-guide/auto_sync/)
|
|
- Kubernetes:
|
|
[Kustomize](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/)
|
|
- Terraform: [state refactoring](https://developer.hashicorp.com/terraform/language/state/refactor),
|
|
[`terraform_remote_state` security warning](https://developer.hashicorp.com/terraform/language/state/remote-state-data),
|
|
[write-only arguments](https://developer.hashicorp.com/terraform/language/manage-sensitive-data/write-only)
|
|
- Vault:
|
|
[JWT/OIDC authentication](https://developer.hashicorp.com/vault/docs/auth/jwt)
|
|
|
|
## Repository-only change
|
|
|
|
이 구조와 gate 설계는 2026-07-26 현재 Git에서만 작성·검증했습니다. 실제
|
|
cluster migration이나 sync는 이 리팩터링 리뷰 범위에 포함되지 않습니다.
|