CI-CD

Argo CD - ApplicationSet

Operation CWAL 2022. 7. 2. 16:57

ApplicationSet이 왜 필요할까?

K8s를 사용하는 조직이라면, 클러스터를 목적에 따라 여러개로 구분하여 활용하는 곳이 대부분일 것이다. 환경별(Dev, Staging, Prod 등) 클러스터를 따로 구성하거나, 규모가 큰 기업은 프로젝트, 팀 또는 계열사마다 따로 클러스터를 사용하는 경우를 예로 들 수 있다.

이제 Argo CD와 연결된 여러 개의 클러스터에 동일한 Application을 배포하는 경우에 대해 생각해보자. 예를 들어, Dev, Staging, Prod 클러스터에 Prometheus를 배포한다면, Argo CD에 이름만 다르고 내용은 같은 Application 3개를 추가해야 한다.

클러스터와 애플리케이션이 많아질 수록 이런 단순 반복 작업(Toil)이 늘어나기 때문에, 자동화가 미덕인 DevOps의 철학과는 맞지 않는 느낌이 든다. Argo CD에서 이런 문제를 해결할 수 있도록 제공하는 Custom Resource가 바로 ApplicationSet이다. ApplicationSet은 비슷한 구성의 Application을 하나의 Template으로 만든 뒤, Parameter로부터 여러 개의 Application이생성되는 일종의 Factory라고 볼 수 있다.

Web UI에선 ApplicationSet을 조회하거나 생성할 수 없기 때문에 이런 기능이 있는지도 모르는 상태로 Argo CD를 사용하는 경우가 많다(필자도 그랬다).

ApplicationSet 기본 구성

다음은 ApplicationSet의 Manifest 예시이다. 크게 봤을 때, Generator와 Template 영역으로 구분되는 것을 알 수 있다. template은 기존 Application의 YAML 파일 양식과 동일한 대신, 일부 필드값을 렌더링 가능하게 Parameter로 표현하였다. 사실 ApplicationSet에서 집중해서 봐야할 부분은 generator 쪽이다.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
spec:
  generators:
  - list:
      elements:
      - cluster: engineering-dev
        url: https://1.2.3.4
      - cluster: engineering-prod
        url: https://2.4.6.8
      - cluster: finance-preprod
        url: https://9.8.7.6
  template:
    metadata:
      name: '{{cluster}}-guestbook'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: applicationset/examples/list-generator/guestbook/{{cluster}}
      destination:
        server: '{{url}}'
        namespace: guestbook

Generator

Generator는 Application 템플릿의 렌더링에 필요한 Parameter를 생성하는 역할을 담당한다. Argo CD v2.4.3 기준으로 8개 정도의 Generator를 지원하고 있지만, 여기선 가장 많이 쓰이는 List, Cluster, Git Generator를 소개하려고 한다.

List

미리 정의된 List로부터 Parameter를 생성하는 Generator이다. 일반적으로 클러스터 이름('{{cluster}}')과 API 서버 URL('{{url}}')을 포함하지만, 사용자가 정의한 Element도 추가할 수 있다.

spec:
  generators:
  - list:
      elements:
      - cluster: engineering-dev
        url: https://1.2.3.4
      - cluster: engineering-prod
        url: https://2.4.6.8
      - cluster: finance-preprod
        url: https://9.8.7.6
# (...)

Application을 배포할 클러스터를 직접 지정할 수 있고 정의도 비교적 간단하기 때문에 사용하기 쉽지만, API 서버 주소를 노출해야 하므로 Repo에 올릴 때 주의할 것.

 

Cluster

Argo CD에 등록된 Cluster 전체 또는 일부(Label Selector)로부터 {{name}} 및 {{server}} Parameter를 생성하는 Generator이다. values 필드에 별도의 key-value pair를 추가하여, Parameter로 사용할 수도 있다.

spec:
  generators:
  - clusters:
      selector:
        matchLabels:
          staging: true
  template:
  # (...)

다만 Cluster에 Label을 추가하기 위해선, K8s Secret을 직접 수정해야 하는 번거로움이 존재한다.

 

Git

Git Generator는 다시 Directory 타입과 File 타입의 Generator로 구분된다.

  • Directory 타입: 단일 클러스터에 여러개의 Application을 한번에 배포하기 좋다. 예를 들어 K8s 클러스터를 처음 구성하고 나서, 기본적으로 필요한 System Application(ex: Prometheus, Istio, EFK 등)을 개별 sub-directory에 kustomize나 Helm 차트로 구성하고 이를 하나로 묶어서 배포할 수 있다.
  • File 타입: 각 클러스터에 해당하는 sub-directory마다 Parameter의 이름과 값을 정의한 JSON 파일(ex: config.json)이 존재하고, 이로부터 Parameter를 생성하는 Generator이다. List 타입에 비해 ApplicationSet에 Cluster 정보를 넣지 않아도 된다는 장점이 있다.
├── apps
│   └── guestbook
│       ├── guestbook-ui-deployment.yaml
│       ├── guestbook-ui-svc.yaml
│       └── kustomization.yaml
├── cluster-config
│   └── engineering
│       ├── dev
│       │   └── config.json
│       └── prod
│           └── config.json
└── git-generator-files.yaml
aws_account: 123456
asset_id: 11223344
cluster.owner: cluster-admin@company.com
cluster.name: engineering-dev
cluster.address: https://1.2.3.4
spec:
  generators:
  - git:
      repoURL: https://github.com/argoproj/applicationset.git
      revision: HEAD
      files:
      - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
  template:
    metadata:
      name: '{{cluster.name}}-guestbook'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/applicationset.git
        targetRevision: HEAD
        path: "examples/git-generator-files-discovery/apps/guestbook"
      destination:
        server: '{{cluster.address}}'
        namespace: guestbook

 

Git Generator는 상당히 강력한 기능을 제공하지만 다른 Generator에 비해 사용법이나 구성이 비교적 까다롭기 때문에, 제대로 사용하기 위해선 공식 문서를 참고하는 편이 좋다.

 

Demo

1. 데모용 K8s 클러스터 2개를 준비하였다. 참고로 in-cluster는 현재 Argo CD가 배포된 관리용 클러스터이며, 여기엔 배포하진 않고 'tfdemo-k8stest', 'tfdemo-k8stest2' 클러스터에 Application을 배포할 계획이다(URL은 보안상 모자이크 처리).

2. 디렉토리 계층을 아래와 같이 구성하였다. dev, prod로 구분된 것을 알 수 있다.

두 nginx-deployment.yaml 파일의 내용은 동일하며, 각각 Deployment 1개, Service 1개가 정의된 간단한 Manifest이다. 여기선 기본 K8s Manifest를 사용하지만, Argo CD가 지원하는 kustomize 또는 Helm 차트 역시 구성 가능하다.

 

3. Argo CD에서 위 파일을 가져올 수 있게, Repo를 추가한다. 참고로 위 파일들은 GitHub에 올려두었으니 참고할 것.

 

4. ApplicationSet을 정의한다. List Generator를 사용하였으며, 각 element로 cluster, url을 포함한다. Cluster는 여기서 dev/prod로 구분되며, url은 각 Cluster URL을 의미한다(간단한 예시일 뿐 환경에 맞게 정의해서 사용하길 바란다).

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: demo-applicationset
  namespace: argocd
spec:
  generators:
  - list:
      elements:
      - cluster: dev
        url: <<Target Cluster 1 URL>>
      - cluster: prod
        url: <<Target Cluster 2 URL>>
  template:
    metadata:
      name: '{{cluster}}-nginx'
    spec:
      project: default
      source:
        repoURL: https://github.com/cure4itches/argocd-demo.git
        targetRevision: main
        path: applicationset/list/{{cluster}}
      destination:
        server: '{{url}}'
        namespace: default

template 필드에는 기존 Argo CD Application 구성과 동일하되, generator에서 정의한 Parameter를 적용할 수 있다. 예를 들어 cluster=dev, url=(Target Cluster 1)인 경우, 이로부터 생성되는 Application은 다음과 같다.

  • .metadata.name: dev-nginx
  • .spec.source.path: applicationset/list/dev
  • .spec.destination.server: (Target Cluster 1)

참고로 namespace는 반드시 argocd로 지정해야 한다. 필자는 처음에 무심코 default에 ApplicationSet을 생성하였는데, Argo CD에서 아무런 변화가 없어서 당황한 경험이 있다.

 

5. kubectl 명령어로 ApplicationSet 리소스를 추가한다.

kubectl apply -f demo-applicationset.yaml

 

6. Argo CD 웹 콘솔에 접속해서, Application 2개가 추가되었는지 확인해보자.

예상했던 것과 같이 dev-nginx, prod-nginx 2개 Application이 생성되었다. Sync를 수행해서 정상적으로 배포되는지도 확인할 차례다.

Manifest가 단순하며, Image 역시 Public Registry에 위치하므로, 두 Application 모두 문제없이 배포에 성공한 것을 볼 수 있다.

 

참고

Introduction to ApplicationSet controller

Argo CD - Declarative GitOps CD for Kubernetes Generating Applications with ApplicationSet

Getting Started with ApplicationSets

토스ㅣSLASH 21 - 실수 없이 안전하게 쿠버네티스 운영하기