[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,405 @@
|
||||
---
|
||||
id: devops-argocd-gitops
|
||||
title: ArgoCD / GitOps — Git = Source of Truth
|
||||
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 / K8s", applicable_to: ["DevOps"] }
|
||||
applied_in: []
|
||||
aliases: [ArgoCD, Flux, GitOps, declarative deploy, App of Apps, sync wave]
|
||||
---
|
||||
|
||||
# ArgoCD / GitOps
|
||||
|
||||
> "Git = production state". **ArgoCD / Flux 가 Git 의 manifest → cluster 자동 sync**. Push 대신 pull. Kubernetes 의 modern 배포 표준.
|
||||
|
||||
## 📖 핵심 개념
|
||||
- Git = single source of truth.
|
||||
- Pull-based: ArgoCD 가 git poll → apply.
|
||||
- Drift detection: cluster ≠ git → 자동 fix.
|
||||
- App of Apps: meta-app 가 다른 app 관리.
|
||||
|
||||
## 💻 코드 패턴
|
||||
|
||||
### ArgoCD 설치
|
||||
```bash
|
||||
kubectl create namespace argocd
|
||||
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
|
||||
|
||||
# CLI
|
||||
brew install argocd
|
||||
argocd login <argocd-server>
|
||||
|
||||
# UI
|
||||
kubectl port-forward svc/argocd-server -n argocd 8080:443
|
||||
```
|
||||
|
||||
### Application
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: my-app
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
|
||||
source:
|
||||
repoURL: https://github.com/myorg/k8s-manifests
|
||||
targetRevision: main
|
||||
path: apps/my-app/overlays/prod
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: prod
|
||||
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true # Git 에서 제거된 자원 cluster 에서도 제거
|
||||
selfHeal: true # Manual 변경 시 자동 revert
|
||||
allowEmpty: false
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
- PrunePropagationPolicy=foreground
|
||||
- PruneLast=true
|
||||
retry:
|
||||
limit: 5
|
||||
backoff:
|
||||
duration: 5s
|
||||
factor: 2
|
||||
maxDuration: 3m
|
||||
```
|
||||
|
||||
→ Git push → 1-3 min 안 cluster 자동 update.
|
||||
|
||||
### Helm + ArgoCD
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata: { name: my-app }
|
||||
spec:
|
||||
source:
|
||||
repoURL: https://github.com/myorg/charts
|
||||
targetRevision: HEAD
|
||||
path: charts/my-app
|
||||
helm:
|
||||
valueFiles:
|
||||
- values.yaml
|
||||
- values-prod.yaml
|
||||
parameters:
|
||||
- name: image.tag
|
||||
value: 1.5.0
|
||||
```
|
||||
|
||||
### Kustomize + ArgoCD
|
||||
```yaml
|
||||
spec:
|
||||
source:
|
||||
repoURL: https://github.com/myorg/manifests
|
||||
path: apps/my-app/overlays/prod
|
||||
kustomize:
|
||||
images:
|
||||
- my-app=ghcr.io/myorg/my-app:1.5.0
|
||||
namePrefix: prod-
|
||||
```
|
||||
|
||||
### App of Apps (meta)
|
||||
```yaml
|
||||
# argocd/applications.yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata: { name: bootstrap, namespace: argocd }
|
||||
spec:
|
||||
source:
|
||||
repoURL: https://github.com/myorg/argocd
|
||||
path: apps/
|
||||
targetRevision: HEAD
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: argocd
|
||||
syncPolicy:
|
||||
automated: { prune: true, selfHeal: true }
|
||||
```
|
||||
|
||||
```
|
||||
apps/
|
||||
├── application.yaml
|
||||
├── api.yaml # Application
|
||||
├── web.yaml # Application
|
||||
├── monitoring.yaml # Application
|
||||
└── ...
|
||||
```
|
||||
|
||||
→ 한 ArgoCD app 가 다른 app 들 관리.
|
||||
|
||||
### ApplicationSet (multi-cluster / multi-tenant)
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata: { name: my-app, namespace: argocd }
|
||||
spec:
|
||||
generators:
|
||||
- clusters: {} # 모든 등록된 cluster
|
||||
template:
|
||||
metadata:
|
||||
name: my-app-{{name}}
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: ...
|
||||
path: apps/my-app
|
||||
destination:
|
||||
server: '{{server}}'
|
||||
namespace: prod
|
||||
```
|
||||
|
||||
→ N cluster 에 자동 deploy.
|
||||
|
||||
### Sync waves (dependency order)
|
||||
```yaml
|
||||
# Wave 0 (CRDs)
|
||||
metadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "0"
|
||||
|
||||
# Wave 1 (DB)
|
||||
metadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "1"
|
||||
|
||||
# Wave 2 (App)
|
||||
metadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "2"
|
||||
```
|
||||
|
||||
→ ArgoCD 가 wave 별 순차 deploy.
|
||||
|
||||
### Hooks
|
||||
```yaml
|
||||
# DB migration before app deploy
|
||||
metadata:
|
||||
annotations:
|
||||
argocd.argoproj.io/hook: PreSync
|
||||
argocd.argoproj.io/hook-delete-policy: HookSucceeded
|
||||
```
|
||||
|
||||
### RBAC
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AppProject
|
||||
metadata: { name: prod, namespace: argocd }
|
||||
spec:
|
||||
description: Production
|
||||
sourceRepos:
|
||||
- 'https://github.com/myorg/*'
|
||||
destinations:
|
||||
- namespace: 'prod-*'
|
||||
server: '*'
|
||||
|
||||
roles:
|
||||
- name: deployer
|
||||
policies:
|
||||
- p, proj:prod:deployer, applications, sync, prod/*, allow
|
||||
groups:
|
||||
- acme:platform
|
||||
```
|
||||
|
||||
### Notifications
|
||||
```yaml
|
||||
# notifications.yaml
|
||||
service.slack:
|
||||
token: ...
|
||||
|
||||
template.app-sync-succeeded: |
|
||||
message: 'Application {{.app.metadata.name}} synced successfully'
|
||||
|
||||
trigger.on-sync-succeeded: |
|
||||
- when: app.status.operationState.phase in ['Succeeded']
|
||||
send: [app-sync-succeeded]
|
||||
|
||||
subscriptions:
|
||||
- recipients: [slack:engineering]
|
||||
triggers: [on-sync-succeeded, on-sync-failed]
|
||||
```
|
||||
|
||||
### CI workflow
|
||||
```yaml
|
||||
# .github/workflows/deploy.yml
|
||||
- name: Build + push image
|
||||
run: docker build -t $REGISTRY/my-app:$SHA . && docker push $REGISTRY/my-app:$SHA
|
||||
|
||||
- name: Update manifest
|
||||
run: |
|
||||
cd k8s-manifests
|
||||
yq -i '.image.tag = "${{ github.sha }}"' apps/my-app/values-prod.yaml
|
||||
git add . && git commit -m "Deploy my-app ${{ github.sha }}" && git push
|
||||
```
|
||||
|
||||
→ Git push = ArgoCD 자동 deploy. 직접 kubectl 안 함.
|
||||
|
||||
### Health check (ArgoCD 가 status 추정)
|
||||
```yaml
|
||||
# Custom health check (Lua)
|
||||
metadata:
|
||||
name: argocd-cm
|
||||
data:
|
||||
resource.customizations: |
|
||||
networking.k8s.io/Ingress:
|
||||
health.lua: |
|
||||
hs = {}
|
||||
if obj.status ~= nil and obj.status.loadBalancer ~= nil then
|
||||
...
|
||||
end
|
||||
return hs
|
||||
```
|
||||
|
||||
### Drift / self-heal
|
||||
```
|
||||
사용자가 cluster 에서 manual 변경:
|
||||
- ArgoCD detect drift
|
||||
- selfHeal: true → 자동 git state 로 revert
|
||||
- selfHeal: false → 알람 만
|
||||
```
|
||||
|
||||
### Rollback
|
||||
```bash
|
||||
# History
|
||||
argocd app history my-app
|
||||
|
||||
# Rollback to specific revision
|
||||
argocd app rollback my-app 5
|
||||
|
||||
# 또는 git revert
|
||||
git revert <commit>
|
||||
git push # ArgoCD 자동 sync
|
||||
```
|
||||
|
||||
### Image automation (Argo Image Updater)
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: my-app
|
||||
annotations:
|
||||
argocd-image-updater.argoproj.io/image-list: my-app=ghcr.io/myorg/my-app
|
||||
argocd-image-updater.argoproj.io/my-app.update-strategy: semver
|
||||
argocd-image-updater.argoproj.io/my-app.allow-tags: "regexp:^v[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
```
|
||||
|
||||
→ 새 image tag 자동 detect → manifest update + commit.
|
||||
|
||||
### Flux (alternative)
|
||||
```yaml
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata: { name: my-app, namespace: flux-system }
|
||||
spec:
|
||||
url: https://github.com/myorg/manifests
|
||||
ref: { branch: main }
|
||||
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata: { name: my-app, namespace: flux-system }
|
||||
spec:
|
||||
sourceRef: { kind: GitRepository, name: my-app }
|
||||
path: apps/my-app/overlays/prod
|
||||
prune: true
|
||||
interval: 1m
|
||||
```
|
||||
|
||||
→ ArgoCD 와 비슷. Git-friendly UX.
|
||||
|
||||
### Flux vs ArgoCD
|
||||
```
|
||||
ArgoCD:
|
||||
+ UI 강력
|
||||
+ 큰 ecosystem
|
||||
+ App-centric
|
||||
|
||||
Flux:
|
||||
+ Cloud-native (CNCF graduated)
|
||||
+ More automation features
|
||||
+ Lighter weight
|
||||
```
|
||||
|
||||
→ ArgoCD 가 더 인기 (2024+).
|
||||
|
||||
### Multi-cluster
|
||||
```
|
||||
1. ArgoCD 가 central cluster
|
||||
2. argocd cluster add — 다른 cluster
|
||||
3. Application destination 이 어느 cluster
|
||||
4. ApplicationSet 가 여러 cluster 동시 deploy
|
||||
```
|
||||
|
||||
### Progressive delivery (Argo Rollouts)
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata: { name: my-app }
|
||||
spec:
|
||||
replicas: 10
|
||||
strategy:
|
||||
canary:
|
||||
steps:
|
||||
- setWeight: 10
|
||||
- pause: { duration: 5m }
|
||||
- setWeight: 25
|
||||
- pause: { duration: 5m }
|
||||
- setWeight: 50
|
||||
- pause: { duration: 10m }
|
||||
- setWeight: 100
|
||||
analysis:
|
||||
templates:
|
||||
- templateName: success-rate
|
||||
startingStep: 1
|
||||
```
|
||||
|
||||
→ Auto canary + rollback if metric 깨짐.
|
||||
|
||||
### Sealed Secrets / External Secrets
|
||||
```yaml
|
||||
# Secret 가 git 안 안전 — encrypted
|
||||
apiVersion: bitnami.com/v1alpha1
|
||||
kind: SealedSecret
|
||||
spec:
|
||||
encryptedData:
|
||||
api-key: AgB7...
|
||||
```
|
||||
|
||||
→ ArgoCD 가 sealed secret apply → controller decrypt.
|
||||
|
||||
## 🤔 의사결정 기준
|
||||
| 상황 | 추천 |
|
||||
|---|---|
|
||||
| K8s + Git workflow | ArgoCD |
|
||||
| Cloud-native official | Flux |
|
||||
| Multi-cluster | ApplicationSet |
|
||||
| Progressive delivery | Argo Rollouts |
|
||||
| 작은 / 단순 | Manual kubectl + CI |
|
||||
| 매우 큰 organization | + Crossplane |
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **kubectl apply manual prod**: drift / no audit.
|
||||
- **Image tag latest**: hash 안 명시 — 추적 불가.
|
||||
- **Secret in git plain**: leak.
|
||||
- **Sync 너무 자주 (1s)**: API rate limit.
|
||||
- **Self-heal off**: drift 누적.
|
||||
- **App of Apps 없이 100 application**: 관리 불가.
|
||||
- **Sync wave 무시**: dependency 순서 깨짐.
|
||||
|
||||
## 🤖 LLM 활용 힌트
|
||||
- Git push = production update.
|
||||
- App of Apps 패턴 + ApplicationSet.
|
||||
- Argo Rollouts = canary / blue-green 자동.
|
||||
- Sealed / External Secrets.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[DevOps_Helm_Deep]]
|
||||
- [[DevOps_Kubernetes_Basics]]
|
||||
- [[Backend_Maintenance_Mode]]
|
||||
Reference in New Issue
Block a user