Skip to content

Argo CD (GitOps)

Argo CD는 GitOps 방식을 지원하는 Kubernetes native 지속적 배포(CD) 도구입니다. 코드당에서 대부분의 Kubernetes 리소스는 Argo CD를 통해 배포 및 관리되고 있습니다.

GitOps

GitOps는 인프라 관리를 선언적으로 수행하는 방법론입니다. 모든 인프라 설정은 Git에 저장되며, 변경 사항은 pull request를 통해 관리됩니다.

Argo CD는 Git 저장소를 모니터링하고, 변경 사항이 감지되면 자동으로 Kubernetes 클러스터에 적용합니다. 즉 Git을 single source of truth로 사용하여, 다음과 같은 장점이 있습니다.

  • 모든 변경사항이 Git에 기록되기 때문에 변경 이력을 쉽게 확인할 수 있습니다.
  • Pull Request를 통해 변경 사항을 review하고 승인할 수 있습니다.
  • Kubernetes 리소스의 상태를 Git과 동기화하여 일관성을 유지할 수 있습니다.
  • 문제가 발생했을 때, 이전 상태로 쉽게 롤백할 수 있습니다. (Git revert)

Application

Argo CD에서 배포는 Application 단위로 관리됩니다. 각 Application은 Git repository의 특정 경로를 모니터링하고, 해당 경로에 정의된 Kubernetes 리소스를 클러스터에 배포합니다.

⚠️ 주의사항

GitOps 방식을 따르기 위해, Argo CD의 Application resource도 Git에 YAML로 저장되어 있어야 합니다. Argo CD UI에서 직접 Application을 생성하거나 수정하는 것은 권장되지 않습니다.

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    path: path/to/manifests
    repoURL: https://github.com/skkuding/codedang
    targetRevision: main  # Git branch
  destination:
    name: stage  # Target cluster name
  syncPolicy:
    automated:
      prune: true  # Delete resources that are no longer defined
      selfHeal: true  # Automatically sync if out of sync
    syncOptions:
      - PrunePropagationPolicy=foreground
  • source: Git repository와 경로를 지정합니다.
  • destination: 배포할 Kubernetes 클러스터를 지정합니다. (클러스터 이름은 Argo CD에 미리 등록되어 있어야 합니다.)
  • syncPolicy.automated: 자동 동기화 설정입니다. 자세한 내용은 공식 문서를 참고하세요.
  • syncPolicy.syncOptions: 동기화 옵션입니다. 자세한 내용은 공식 문서를 참고하세요.

ApplicationSet

ApplicationSet은 Application의 묶음으로, 여러 Application을 한 번에 생성하고 관리할 수 있습니다. 여러 환경(production, stage)에 동일한 애플리케이션을 배포할 때 유용합니다.

yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-app-set
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  goTemplate: true
  goTemplateOptions: ['missingkey=error']
  generators:
    - list:
        elements:
          - env: stage
            branch: main
          - env: production
            branch: release
  template:
    metadata:
      name: 'my-app-{{.env}}'
      finalizers:
        - resources-finalizer.argocd.argoproj.io
    spec:
      project: default
      source:
        path: 'path/to/manifests/{{.env}}'
        repoURL: https://github.com/skkuding/codedang
        targetRevision: '{{.branch}}'
      destination:
        name: '{{.env}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - PrunePropagationPolicy=foreground

ApplicationSet은 generatorstemplate으로 구성됩니다.

  • generators: Application을 생성하는 방법을 정의합니다. 위 예시에서는 list generator를 사용하여 두 개의 환경(stage, production)을 정의했습니다.
  • template: 각 Application의 공통 설정을 정의합니다. {{.env}}{{.branch}}generators에서 정의한 값을 참조합니다.

더 많은 generator 유형과 설정 방법은 공식 문서를 참고하세요.

Argo CD Image Updater

Kubernetes의 imagePullPolicyAlways로 설정되어 있더라도, 클러스터에 배포된 Pod는 새로운 이미지가 나와도 자동으로 업데이트되지 않습니다. Argo CD는 YAML에 변경이 있을 때만 리소스를 업데이트하고, 이미지 태그가 변경되지 않으면 새로운 이미지를 가져오지 않습니다. 이를 해결하기 위해 Argo CD Image Updater를 사용합니다.

Argo CD Image Updater는 컨테이너 이미지의 새로운 버전을 감지하고, Argo CD Application의 YAML을 자동으로 업데이트하여 새로운 이미지를 배포합니다.

먼저, Argo CD Image Updater를 설치합니다.

bash
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml

그 다음, 아래와 같이 Application에 annotation을 추가합니다.

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
  annotations:
    argocd-image-updater.argoproj.io/image-list: <alias>=my-registry/my-image:tag
    argocd-image-updater.argoproj.io/<alias>.update-strategy: digest
spec:
  ...

위와 같이 annotation을 추가하면, Argo CD Image Updater가 my-registry/my-image:tag에 새로운 이미지가 있는지 주기적으로 확인합니다. 새로운 이미지가 감지되면, 해당 Application의 YAML을 업데이트하여 새로운 이미지로 변경합니다.

digest strategy는 해당 이미지 태그의 최신 digest를 사용하여 업데이트합니다. 이외에 다른 update strategy를 확인하고 싶다면 공식 문서 'Update Strategies'를 참고하세요.

Using with ApplicationSet

ApplicationSet은 각 Application을 ApplicationSet의 템플릿에 정의된 값으로 관리합니다. 즉, Argo CD Image Updater가 Application의 YAML을 업데이트해도, ApplicationSet이 다시 기존 값으로 덮어씌우게 됩니다. 이를 해결하기 위해, ApplicationSet에 ignoreApplicationDifferences 설정을 추가하여 특정 필드를 무시하도록 할 수 있습니다.

yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: frontend
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  ignoreApplicationDifferences:
    - jsonPointers:
        - /spec/source/kustomize/images
  ...

Pull Request Preview

Argo CD의 ApplicationSet Generator 중 하나인 pullRequest를 사용하면, GitHub Pull Request마다 별도의 Application을 생성할 수 있습니다.

yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: frontend-preview
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  goTemplate: true
  goTemplateOptions: ['missingkey=error']
  generators:
    - pullRequest:
        github:
          owner: skkuding
          repo: codedang
          appSecretName: github-app-secret # Required for higher API rate limit
        requeueAfterSeconds: 10 # Check for new PRs every 10 seconds
  template:
    metadata:
      name: '{{.number}}-preview-frontend'
      finalizers:
        - resources-finalizer.argocd.argoproj.io
    spec:
      ...

Argo CD에서는 GitHub API를 일정 시간마다 호출하여 Pull Request 목록을 가져오고, 각 Pull Request에 대해 별도의 Application을 생성합니다. GitHub API 공식 문서에 따르면, 인증되지 않은 요청은 시간당 60회, 인증된 요청은 시간당 5,000회로 제한됩니다. 따라서 appSecretName에 GitHub Personal Access Token이 저장된 Kubernetes Secret을 지정하는 것이 좋습니다. 코드당은 'skkuding-bot' GitHub App을 사용하여 API 호출 제한을 늘리고 있습니다.

자세한 내용은 공식 문서 'Pull Request Generator'를 참고하세요.

Notifications

Argo CD Notifications는 Argo CD의 이벤트(동기화 상태 변경, 오류 등)를 다양한 채널(Slack, Email 등)로 알림을 보내는 기능입니다. 현재 코드당에서는 Pull Request Preview의 상태를 GitHub PR comment와 commit status로 알림을 보내고 있습니다.

Argo CD Notifications를 사용하려면, 먼저 Argo CD Notifications Controller를 설치해야 합니다.

bash
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/notifications_catalog/install.yaml

그 다음, 필요한 secret 값을 Secret(argocd-notifications-secret)로 생성합니다.

yaml
apiVersion: v1
kind: Secret
metadata:
  name: argocd-notifications-secret
  namespace: argocd
type: Opaque
stringData:
  github-app-id: ...
  github-installation-id: ...
  github-private-key: ...

ConfigMap(argocd-notifications-cm)을 생성하여 알림 설정을 구성합니다.

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  service.github: |
    appID: $github-app-id
    installationID: $github-installation-id
    privateKey: $github-private-key

  trigger.on-sync-succeeded: |
    - when: app.status.sync.status == 'Synced' and app.status.health.status == 'Healthy'
      oncePer: app.status.operationState.syncResult.revision
      send: [github-succeed]

  template.github-succeed: |
    message: 'Successfully synced {{ .app.metadata.name }}'
    github:
      status:
        state: success
        label: "Argo CD / {{ .app.metadata.annotations.appName }}"
        targetURL: "{{ .context.argocdUrl }}/applications/{{ .app.metadata.name }}?operation=true"
      pullRequestComment:
        content: |
          ✅ **Syncing Preview App Succeeded**

          **Application:** `{{ .app.metadata.annotations.appName }}`
          **Revision:** `{{ .app.status.sync.revision }}`
          **Health Status:** {{ .app.status.health.status }}

Service

알림 설정에 필요한 서비스 정보를 지정합니다. 위 예시에서는 GitHub 알림 설정을 위해 GitHub App 정보를 service.github에 지정했습니다.

Trigger

알림을 트리거하는 조건을 정의합니다. 위 예시에서는 Application이 성공적으로 동기화되고, 상태가 Healthy일 때 github-succeed 알림을 보냅니다. oncePer 필드를 사용하여 동일한 revision에 대해 한 번만 알림을 보내도록 설정했습니다.

더 많은 트리거 조건 목록은 공식 문서 'Triggers and Templates Catalog'를 참고하세요.

Template

실제로 전송되는 알림 메시지의 형식을 정의합니다. 위 예시에서는 GitHub commit status와 Pull Request comment를 설정했습니다.

GitHub 알림 설정에 대한 자세한 내용은 공식 문서 'GitHub Notifications'를 참고하세요.