OKE 플랫폼 엔지니어링 랩 2편 — ArgoCD App-in-Apps로 인프라 배포하기
이 포스트는 OKE 플랫폼 엔지니어링 랩 시리즈의 2편입니다.
- 1편 — Terraform + Terragrunt로 OKE 클러스터 프로비저닝하기
- 2편 — ArgoCD App-in-Apps로 인프라 배포하기 ← 현재
- 3편 — Vault + External Secrets로 Kubernetes 시크릿 관리하기
- 4편 — Istio + cert-manager로 TLS 인증서 자동화하기
1. 배경
1편에서 OKE 클러스터를 프로비저닝했습니다. 이제 그 위에 플랫폼 애플리케이션들(Istio, Vault, cert-manager 등)을 배포해야 합니다.
kubectl apply -f로 하나씩 적용하는 방식은 관리하기 어렵고, 상태를 추적할 방법도 없습니다. 이를 해결하기 위해 ArgoCD를 사용하고, 여러 애플리케이션을 선언적으로 한꺼번에 관리하는 App-in-Apps 패턴을 적용했습니다.
App-in-Apps 패턴이란?
일반적으로 ArgoCD Application 하나는 하나의 Helm 차트나 매니페스트를 배포합니다. App-in-Apps는 상위 Application이 하위 Application 매니페스트들을 담은 Git 경로를 바라보는 구조입니다. 상위 Application을 apply하면 그 안의 모든 하위 Application이 자동으로 등록되고 배포됩니다.
flowchart LR
apply["kubectl apply -f core.yaml\n상위 Application 하나만 적용"]
argo["ArgoCD\ninfra/core/ 경로 스캔"]
apply --> argo
argo --> cm[cert-manager 자동 배포]
argo --> eso[external-secrets 자동 배포]
argo --> istio[istio 자동 배포]
argo --> vault[vault 자동 배포]
2. 전체 구조
gitops/infra/
├── core.yaml # 상위 Application (core)
├── platform.yaml # 상위 Application (platform)
├── core/ # Wave 순 배포 그룹
│ ├── cert-manager-app.yaml
│ ├── external-secrets-app.yaml
│ ├── istio-base-app.yaml
│ ├── istiod-app.yaml
│ ├── istio-ingressgateway-app.yaml
│ ├── vault-app.yaml
│ ├── reflector-app.yaml
│ └── nfs-provisioner-app.yaml
├── platform/ # core 완료 후 배포 그룹
│ ├── cert-manager-config/
│ ├── cluster-secret-store/
│ └── istio-gateway/
└── cert-manager/ # Helm values
istio/ vault/ ...
core와 platform 두 그룹으로 분리한 이유는 배포 순서 때문입니다. platform 그룹의 앱들은 core 그룹의 앱이 먼저 설치되어 있어야 합니다. 예를 들어 ClusterSecretStore는 External Secrets CRD가 등록된 뒤에만 적용할 수 있고, cert-manager ClusterIssuer는 cert-manager가 먼저 떠 있어야 합니다.
3. ArgoCD 최초 부트스트랩
ArgoCD 자체는 Helm으로 직접 설치합니다. ArgoCD가 없으면 App-in-Apps를 등록할 수 없기 때문에, 이 단계만큼은 수동으로 진행합니다.
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
kubectl create namespace argocd
helm install argocd argo/argo-cd \
--namespace argocd \
--values argocd/values.yaml
# argocd/values.yaml
global:
domain: argocd.<your-domain>
configs:
params:
server.insecure: true # Istio에서 TLS 종료하므로 ArgoCD는 HTTP로
server:
metrics:
enabled: true
ArgoCD가 뜨면 core.yaml과 platform.yaml을 한 번만 적용합니다. 이후부터는 Git에 push하면 ArgoCD가 자동으로 동기화합니다.
kubectl apply -f infra/core.yaml
kubectl apply -f infra/platform.yaml
4. Core 그룹
상위 Application
core.yaml은 infra/core/ 경로를 바라봅니다. 이 경로 안의 모든 Application 매니페스트를 자동으로 등록합니다.
# infra/core.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: infra-core
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/<your-org>/gitops.git
targetRevision: main
path: infra/core
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Sync Wave — 배포 순서 제어
infra/core/ 안의 앱들은 서로 의존 관계가 있습니다. istiod는 istio-base의 CRD가 먼저 등록되어야 하고, istio-ingressgateway는 istiod가 먼저 떠야 합니다.
ArgoCD의 sync-wave 어노테이션으로 배포 순서를 제어합니다. 숫자가 낮을수록 먼저 배포되고, 같은 Wave 안에서는 병렬로 배포됩니다.
| Wave | 애플리케이션 | 이유 |
|---|---|---|
| -3 | cert-manager, external-secrets, nfs-provisioner | 다른 앱의 CRD 의존성 없음, 가장 먼저 CRD 등록 |
| -2 | istio-base, vault | istio-base CRD 등록 후 istiod 설치 필요 |
| -1 | istiod | istio-base CRD 필요 |
| 0 | istio-ingressgateway, metrics-server, reflector | istiod 필요 |
# infra/core/cert-manager-app.yaml
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-3"
Helm 멀티소스 패턴
Helm 차트는 공식 레포에서 받고, values 파일은 GitOps 레포에서 관리합니다. 이 두 소스를 함께 사용하는 것이 ArgoCD의 멀티소스 기능입니다.
# infra/core/cert-manager-app.yaml
spec:
sources:
- repoURL: https://charts.jetstack.io
chart: cert-manager
targetRevision: v1.20.0
helm:
valueFiles:
- $values/infra/cert-manager/values.yaml # $values 참조
- repoURL: https://github.com/<your-org>/gitops.git
targetRevision: main
ref: values # 이 소스를 $values 변수로 참조
두 번째 소스에 ref: values를 지정하면 첫 번째 소스의 valueFiles에서 $values로 참조할 수 있습니다. Helm 차트와 values를 완전히 분리해서 관리할 수 있는 방식입니다.
5. Platform 그룹
상위 Application
platform.yaml은 infra/platform/ 경로를 바라봅니다. Core 그룹과 구조는 동일하지만, Core 앱들이 모두 정상적으로 배포된 뒤에 적용되어야 합니다.
# infra/platform.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: infra-platform
namespace: argocd
spec:
source:
repoURL: https://github.com/<your-org>/gitops.git
targetRevision: main
path: infra/platform
# ...
Platform 앱 목록
Platform 그룹의 앱들은 Helm 차트가 아닌 직접 작성한 매니페스트를 Git 경로로 배포합니다.
# infra/platform/cert-manager-config-app.yaml
spec:
source:
repoURL: https://github.com/<your-org>/gitops.git
targetRevision: main
path: infra/cert-manager/config # ClusterIssuer, Certificate 매니페스트
destination:
namespace: cert-manager
# infra/platform/istio-gateway-app.yaml
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1" # cert-manager-config 이후 적용
spec:
source:
path: infra/istio/gateway # Istio Gateway 매니페스트
destination:
namespace: istio-system
| 애플리케이션 | 역할 |
|---|---|
| cert-manager-config | ClusterIssuer (Let’s Encrypt), 와일드카드 Certificate |
| cluster-secret-store | Vault 연동 ClusterSecretStore |
| istio-gateway | Istio Gateway (와일드카드 도메인, TLS) |
| vault-vs | Vault Istio VirtualService |
| argocd-vs | ArgoCD Istio VirtualService |
| keycloak-operator | Keycloak 배포 (PostgreSQL 포함) |
6. 배포 흐름 정리
flowchart TD
A["1. ArgoCD 수동 설치 (Helm)"]
B["2. kubectl apply -f core.yaml"]
C["3. ArgoCD → infra/core/ 경로 스캔"]
A --> B --> C
subgraph w3["Wave −3 (병렬)"]
cm[cert-manager]
eso[external-secrets]
nfs[nfs-provisioner]
end
C --> cm & eso & nfs
subgraph w2["Wave −2 (병렬)"]
ib[istio-base]
vault[vault]
end
cm & eso & nfs --> ib & vault
subgraph w1["Wave −1"]
isd[istiod]
end
ib & vault --> isd
subgraph w0["Wave 0 (병렬)"]
igw[istio-ingressgateway]
ms[metrics-server]
ref[reflector]
end
isd --> igw & ms & ref
이후부터는 Git에 변경사항을 push하면 ArgoCD가 자동으로 클러스터에 반영합니다(selfHeal: true). 클러스터 상태가 Git과 다르면 자동으로 원복됩니다.