---
id: devops-argocd-apps-deep
title: ArgoCD Applications — App-of-Apps / ApplicationSet
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [devops, argocd, gitops, vibe-coding]
tech_stack: { language: "YAML", applicable_to: ["DevOps"] }
applied_in: []
aliases: [ArgoCD, Application, ApplicationSet, App-of-Apps, GitOps, declarative deploy]
---

# ArgoCD Applications Deep

> K8s GitOps 의 표준. **Application + ApplicationSet + App-of-Apps**. Declarative, drift detect, rollback.

## 📖 핵심 개념
- Git = source of truth.
- ArgoCD 가 sync to cluster.
- Drift detect + reconcile.
- Multi-cluster + multi-tenant.

## 💻 코드 패턴

### Application
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/me/my-app
    targetRevision: HEAD
    path: kubernetes
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
```

→ Git path 의 manifest 가 cluster.

### Sync wave (order)
```yaml
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: '-1'   # 먼저
```

→ "Database 먼저, app 다음" 식.

### Hook (pre/post sync)
```yaml
metadata:
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
```

→ DB migration 가 sync 전.

### App-of-Apps
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root
spec:
  source:
    path: apps/   # 매 file 가 Application
  destination: { ... }
```

```yaml
# apps/users.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: users-service
spec: ...

# apps/orders.yaml
...
```

→ 1 root Application 가 모든 다른 Application 관리.

### ApplicationSet (generator)
```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: per-cluster
spec:
  generators:
    - clusters: {}     # 매 cluster 의 Application
  template:
    metadata:
      name: '{{name}}-app'
    spec:
      source:
        repoURL: ...
        path: 'manifests/{{name}}'
      destination:
        server: '{{server}}'
```

→ 매 cluster / branch / file 가 자동 Application.

### Generator types
```
- List: explicit list.
- Cluster: matrix (모든 cluster).
- Git directory: 매 dir = Application.
- Git file: 매 file.
- Pull request: 매 PR 가 preview env.
- Matrix: combine.
- Merge: combine + override.
```

### PR preview environment
```yaml
generators:
  - pullRequest:
      github:
        owner: me
        repo: my-app
        labels: ['preview']
template:
  metadata:
    name: 'preview-{{number}}'
  spec:
    source:
      targetRevision: '{{branch}}'
      path: kubernetes
    destination:
      namespace: 'preview-{{number}}'
```

→ 매 PR 의 own preview namespace.

### Multi-cluster
```yaml
generators:
  - clusters:
      selector:
        matchLabels:
          environment: production
template:
  spec:
    destination:
      server: '{{server}}'
```

→ 매 prod cluster 에 자동 deploy.

### Sync options
```yaml
syncPolicy:
  automated: { prune: true, selfHeal: true }
  syncOptions:
    - CreateNamespace=true
    - ServerSideApply=true
    - ApplyOutOfSyncOnly=true
    - RespectIgnoreDifferences=true
```

### Ignore differences
```yaml
ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
      - /spec/replicas    # HPA 가 manage
```

→ Replica drift 무시.

### Health check
```yaml
# Custom resource
metadata:
  annotations:
    argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
```

```yaml
# Or custom health Lua script
data:
  resource.customizations: |
    redis.io/Redis:
      health.lua: |
        if obj.status ~= nil then
          if obj.status.phase == 'Ready' then
            return { status = 'Healthy' }
          end
        end
```

### Helm + ArgoCD
```yaml
spec:
  source:
    repoURL: https://charts.example.com
    chart: my-chart
    targetRevision: 1.2.3
    helm:
      values: |
        replicaCount: 3
        image: ...
```

### Kustomize + ArgoCD
```yaml
spec:
  source:
    path: overlays/production
    kustomize:
      images:
        - my-app:v1.2.3
```

### Notification
```yaml
# argocd-notifications-cm
data:
  service.slack: |
    token: $slack-token
  
  template.app-deployed: |
    message: 'App {{.app.metadata.name}} deployed.'
  
  trigger.on-deployed: |
    when: app.status.operationState.phase == 'Succeeded'
    send: [app-deployed]
  
  subscriptions: |
    - recipients: [slack:deployments]
      triggers: [on-deployed]
```

### RBAC
```yaml
data:
  policy.csv: |
    p, role:dev, applications, sync, default/*, allow
    p, role:dev, applications, get, default/*, allow
    g, dev-team, role:dev
```

→ Team 별 access.

### Project (multi-tenant)
```yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: my-team
spec:
  sourceRepos:
    - https://github.com/me/team-repo
  destinations:
    - namespace: 'team-*'
      server: '*'
  clusterResourceWhitelist:
    - group: '*'
      kind: '*'
```

### vs Flux
```
ArgoCD: UI 친화, 큰 ecosystem.
Flux: simple, GitOps Toolkit.

→ ArgoCD 가 더 popular.
```

### vs Argo Rollouts (다름)
```
ArgoCD: app deploy.
Argo Rollouts: progressive delivery (canary, blue-green).

→ 둘 다 같이 사용.
```

→ [[DevOps_Argo_Rollouts]].

### Production patterns
```
1. Git monorepo 의 매 app folder.
2. ApplicationSet 가 자동 Application 생성.
3. PR preview 가 매 feature.
4. Notification 가 Slack.
5. Project 별 RBAC.
6. Argo Rollouts 가 progressive deploy.
```

### Disaster recovery
```
ArgoCD 자체 가 down:
- Cluster 의 manifest 유지 (기존 deploy).
- 새 deploy 안 됨.
- Restore from backup (etcd).

→ ArgoCD 가 second cluster 의 backup.
```

### Cost
```
ArgoCD: 무료 (open source).
Cluster compute: ArgoCD 가 작은 (작은 deployment).

→ Self-host 가 cheap.
```

### Real-world
- **Intuit** (creator).
- **Adobe**: 큰 user.
- **Red Hat OpenShift**: native integration.
- **Tetrate / SAP**: 큰 deployment.

### 함정
```
- Auto-sync 가 모든 변경 즉시: 위험.
- No project / RBAC: 매 user 가 모든.
- Manifest drift (manual kubectl): self-heal 가 fight.
- Big repo (10k+ Application): 느린.
- Helm value secret in git: 안 됨 (External Secrets).
```

### Best practice
```
1. App-of-Apps 또는 ApplicationSet (DRY).
2. Self-heal + auto-sync (production).
3. Pre-sync hook 의 migration.
4. Notification (Slack).
5. RBAC + Project.
6. Argo Rollouts 가 progressive.
7. Secret management (External Secrets / Sealed Secrets).
```

## 🤔 의사결정 기준
| 작업 | 추천 |
|---|---|
| K8s GitOps | ArgoCD |
| Simple GitOps | Flux |
| Multi-cluster | ApplicationSet |
| Preview env | PR generator |
| Helm | Helm + ArgoCD |
| Kustomize | Kustomize + ArgoCD |
| Progressive deploy | Argo Rollouts |

## ❌ 안티패턴
- **Manual kubectl**: drift.
- **No project**: shared cluster + 매 user.
- **Big mono Application**: slow sync.
- **Secret in git**: leak.
- **No notification**: silent failure.
- **No backup**: lost.

## 🤖 LLM 활용 힌트
- ArgoCD = K8s GitOps standard.
- ApplicationSet 가 multi-cluster / multi-app.
- App-of-Apps 가 hierarchy.
- Argo Rollouts 와 함께 progressive.

## 🔗 관련 문서
- [[DevOps_ArgoCD_GitOps]]
- [[DevOps_Argo_Rollouts]]
- [[DevOps_K8s_Operators]]
