이 글에서 다루는 것

Argo CD Notifications Controller로 Sync/Health 이벤트를 Slack에 실시간 전송하고, Webhook URL을 SealedSecret으로 안전하게 관리하는 GitOps 모니터링 자동화 구조를 다룹니다.

선수지식


이 단계에서 해결하려는 문제

GitOps는 자동으로 잘 돌아가더라도, 지금 무슨 일이 일어나는지 모르면 운영자는 항상 불안하다. Argo CD의 Sync/Health 변화를 즉시 Slack으로 받아보는 GitOps 모니터링 루프를 만들어서, 커밋 이후 어떤 일이 일어나는지 실시간으로 보이게 만든다.


🎯 핵심 요약

  • Argo CD Notifications ControllerSync/Health 이벤트를 Slack에 실시간 전송
  • Webhook URL → SealedSecret → 환경변수 참조로 안전 관리(레포 커밋 OK)
  • 템플릿/트리거/구독을 ConfigMap 한 곳에서 선언적으로 관리
  • Git 커밋 → Argo Sync → Slack 알림의 자동 루프 완성

1️⃣ 전체 흐름 요약

mermaid-07.png


2️⃣ 폴더/리소스 구조(레포 반영 상태)

mlops-infra/
├─ bootstrap/
│  └─ notifications/
│     ├─ cm.yaml               # 템플릿/트리거/구독 선언
│     ├─ secret-sealed.yaml    # Slack Webhook(SealedSecret)
│     └─ kustomization.yaml    # (선택) 동일 디렉터리 리소스 묶음
└─ apps/
   ├─ project-notifications.yaml
   └─ notifications.yaml

3️⃣ Slack Webhook(SealedSecret) — 안전 주입

# bootstrap/notifications/secret-sealed.yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: argocd-notifications-secret
  namespace: argocd
spec:
  encryptedData:
    slack-webhook: AgC...==   # kubeseal 결과(키: slack-webhook)
  template:
    metadata:
      name: argocd-notifications-secret
      namespace: argocd
    type: Opaque

생성 절차(로컬에서 1회)

# 원문 Secret (파일로 출력)
kubectl -n argocd create secret generic argocd-notifications-secret \
  --from-literal=slack-webhook='<YOUR_SLACK_WEBHOOK_URL>' \
  --dry-run=client -o yaml > /tmp/argocd-noti-secret.yaml

# seal (컨트롤러 이름/네임스페이스는 실제 설치값과 정확히 일치해야 함)
kubeseal --controller-name sealed-secrets \
         --controller-namespace kube-system \
         -o yaml < /tmp/argocd-noti-secret.yaml \
  > bootstrap/notifications/secret-sealed.yaml

기존 레포의 다른 SealedSecret들과 동일하게 controller-name/namespace를 맞춰야 복호화됩니다.


4️⃣ 템플릿/트리거/구독(ConfigMap) — 한 곳에서 일원화

# bootstrap/notifications/cm.yaml (핵심부)
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  context: |
    argocdUrl: https://argocd.local

  service.webhook.slack_webhook: |
    url: $slack-webhook
    headers:
    - name: Content-Type
      value: application/json

  # 템플릿: Sync 상태 변경
  template.send-slack-status: |
    webhook:
      slack_webhook:
        method: POST
        body: |
          {
            "text": "*[{{.app.metadata.name}}]* Sync *{{.app.status.sync.status}}* → Health *{{.app.status.health.status}}*\n· Rev: `{{.app.status.sync.revision}}`\n<{{.context.argocdUrl}}/applications/{{.app.metadata.name}}|Open in ArgoCD>"
          }

  # 트리거 + 구독 (동일 ConfigMap 내)
  trigger.on-sync-status-change: |
    - when: app.status.sync.status in ['Synced', 'OutOfSync']
      send: [send-slack-status]

  subscriptions: |
    - recipients:
        - slack_webhook
      triggers:
        - on-sync-status-change
        - on-sync-failed
        - on-health-degraded

핵심 포인트:

  • Webhook 키 이름은 slack-webhook (SealedSecret의 data 키와 일치)
  • 수신 대상은 채널명 대신 slack_webhook(service.webhook 식별자)으로 구독

5️⃣ Argo CD Project & Application (GitOps로 관리)

# apps/project-notifications.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: notifications
  namespace: argocd
spec:
  description: Project for Argo CD Notifications
  sourceRepos:
    - 'https://github.com/keonhoban/mlops-infra-gitops'
  destinations:
    - namespace: argocd
      server: https://kubernetes.default.svc
  clusterResourceWhitelist:
    - group: '*'
      kind: '*'
  orphanedResources:
    warn: true
# apps/notifications.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: notifications
  namespace: argocd
  annotations:
    argocd.argoproj.io/sync-wave: "2"
spec:
  project: notifications
  source:
    repoURL: https://github.com/keonhoban/mlops-infra-gitops
    targetRevision: main
    path: bootstrap/notifications
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

6️⃣ 적용 & 검증 시퀀스

# 1) 프로젝트/앱 적용
kubectl -n argocd apply -f apps/project-notifications.yaml
kubectl -n argocd apply -f apps/notifications.yaml

# 2) 동기화/상태
argocd app sync notifications --grpc-web
argocd app get  notifications

# 3) 컨트롤러 로그(이상 시)
kubectl -n argocd logs deploy/argocd-notifications-controller

정상 지표

  • notifications 앱이 Synced/Healthy
  • 템플릿 변경 → 커밋/푸시 시, Slack에 Sync/Health 메시지 수신

7️⃣ 운영 체크리스트

  • argocd-notifications-secret SealedSecretargocd 네임스페이스에 정상 복호화
  • ConfigMap의 service.webhook.slack_webhookSealedSecret 키(slack-webhook) 일치
  • Argo CD Notifications Controller가 실행 중(Argo 2.6+ 기본 포함)
  • context.argocdUrl이 실제 접속 URL과 일치
  • (옵션) 앱별로 별도 구독을 두고 싶으면 subscriptions를 다중 항목으로 분리

🧩 팁

  • Bot Token 모드로 전환하면 멘션/스레드/이모지 커스터마이징이 쉬워짐 (service.slack: 사용)
  • 앱별 다른 채널: service.webhook.slack_teamA, ..._teamB 추가 후 subscriptions 분기
  • 메시지에 커밋 SHA/링크 포함: {{.app.status.sync.revision}} 사용

설계 판단 (Why This Way?)

ArgoCD Notifications 설정을 ConfigMap 한 장에 모아 Git diff로 변경 이력을 추적하고, Slack Webhook URL은 SealedSecret으로 암호화하여 Git 노출로 인한 임의 메시지 전송을 방지합니다.


다음에 읽을 글

MLOps 운영 고도화 6단계: GitOps 고도화 — ArgoCD 동기화 전략 정교화