Matrix Generator

Matrix Generator

두 개의 자식 generator가 생성한 파라미터를 결합해, 각 generator의 생성 파라미터의 모든 조합을 반복하는 generator예요. 두 generator의 파라미터를 조합해 모든 가능한 조합을 만들면 두 generator 본연의 특성을 모두 얻을 수 있어요.

출처: 문서

본문

Matrix generator는 두 자식 generator가 생성한 파라미터를 결합해, 각 generator의 생성 파라미터의 모든 조합을 반복해요.

두 generator 파라미터를 결합해 모든 가능한 조합을 만들면 두 generator의 본질적 특성을 모두 얻을 수 있어요. 예를 들어 많은 가능한 사용 사례 중 작은 부분집합:

  • SCM Provider Generator + Cluster Generator: GitHub 조직의 리포지토리를 스캔해 애플리케이션 리소스를 찾고, 그 리소스를 사용 가능한 모든 클러스터에 타겟팅.
  • Git File Generator + List Generator: 구성 파일을 통해 선택적 구성 옵션과 함께 배포할 애플리케이션 목록을 제공하고, 고정된 클러스터 목록에 배포.
  • Git Directory Generator + Cluster Decision Resource Generator: Git 리포지토리의 폴더 안에 있는 애플리케이션 리소스를 찾고, 외부 커스텀 리소스로 제공된 클러스터 목록에 배포.
  • 기타 등등...

모든 generator 집합을 사용할 수 있으며, 그러한 generator들의 결합된 값은 평소처럼 template 파라미터에 삽입돼요.

참고: 두 자식 generator가 모두 Git generator라면, 자식 generator들의 항목을 병합할 때 충돌을 피하기 위해 둘 중 하나 또는 둘 다 pathParamPrefix 옵션을 사용해야 해요.

예시: Git Directory generator + Cluster generator

예시로 두 클러스터가 있다고 상상해 봐요:

  • staging 클러스터 (https://1.2.3.4)
  • production 클러스터 (https://2.4.6.8)

그리고 애플리케이션 YAML이 Git 리포지토리에 정의돼 있어요:

목표는 두 애플리케이션을 두 클러스터에 모두 배포하고, 더 일반적으로는 향후 Git 리포지토리의 새 애플리케이션과 Argo CD에 정의된 새 클러스터에도 자동으로 배포하는 것이에요.

이를 위해 Git과 Cluster를 자식 generator로 하는 Matrix generator를 사용할 거예요:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-git
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    # matrix 'parent' generator
    - matrix:
        generators:
          # git generator, 'child' #1
          - git:
              repoURL: https://github.com/argoproj/argo-cd.git
              revision: HEAD
              directories:
                - path: applicationset/examples/matrix/cluster-addons/*
          # cluster generator, 'child' #2
          - clusters:
              selector:
                matchLabels:
                  argocd.argoproj.io/secret-type: cluster
  template:
    metadata:
      name: '{{.path.basename}}-{{.name}}'
    spec:
      project: '{{index .metadata.labels "environment"}}'
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: '{{.server}}'
        namespace: '{{.path.basename}}'

먼저 Git directory generator가 Git 리포지토리를 스캔하며 지정된 경로 아래 디렉토리를 발견해요. argo-workflows와 prometheus-operator 애플리케이션을 발견하고, 두 개의 대응하는 파라미터 집합을 생성해요:

- path: /examples/git-generator-directory/cluster-addons/argo-workflows
  path.basename: argo-workflows

- path: /examples/git-generator-directory/cluster-addons/prometheus-operator
  path.basename: prometheus-operator

다음으로 Cluster generator가 Argo CD에 정의된 클러스터 집합을 스캔해 staging과 production 클러스터 시크릿을 찾고 두 개의 대응하는 파라미터 집합을 생성해요:

- name: staging
  server: https://1.2.3.4

- name: production
  server: https://2.4.6.8

마지막으로 Matrix generator가 두 출력 집합을 결합해 다음을 생성해요:

- name: staging
  server: https://1.2.3.4
  path: /examples/git-generator-directory/cluster-addons/argo-workflows
  path.basename: argo-workflows

- name: staging
  server: https://1.2.3.4
  path: /examples/git-generator-directory/cluster-addons/prometheus-operator
  path.basename: prometheus-operator

- name: production
  server: https://2.4.6.8
  path: /examples/git-generator-directory/cluster-addons/argo-workflows
  path.basename: argo-workflows

- name: production
  server: https://2.4.6.8
  path: /examples/git-generator-directory/cluster-addons/prometheus-operator
  path.basename: prometheus-operator

(전체 예시.)

한 자식 generator의 파라미터를 다른 자식 generator에서 사용 (Using Parameters from one child generator in another child generator)

Matrix generator는 한 자식 generator가 생성한 파라미터를 다른 자식 generator 안에서 사용할 수 있게 해줘요. 아래는 git-files generator와 cluster generator를 함께 사용하는 예시예요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-git
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    # matrix 'parent' generator
    - matrix:
        generators:
          # git generator, 'child' #1
          - git:
              repoURL: https://github.com/argoproj/applicationset.git
              revision: HEAD
              files:
                - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
          # cluster generator, 'child' #2
          - clusters:
              selector:
                matchLabels:
                  argocd.argoproj.io/secret-type: cluster
                  kubernetes.io/environment: '{{.path.basename}}'
  template:
    metadata:
      name: '{{.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: '{{.server}}'
        namespace: guestbook

다음은 git-files generator가 사용하는 git 리포지토리의 대응하는 폴더 구조예요:

├── 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

위 예시에서 git-files generator가 생성한 {{.path.basename}} 파라미터는 devprod로 해석돼요. 두 번째 자식 generator에서 라벨 kubernetes.io/environment: {{.path.basename}}이 있는 라벨 셀렉터는 첫 번째 자식 generator 파라미터가 생성한 값(kubernetes.io/environment: prodkubernetes.io/environment: dev)으로 해석돼요.

따라서 위 예시에서 라벨 kubernetes.io/environment: prod가 있는 클러스터에는 prod 전용 구성(즉 prod/config.json)만 적용되고, 라벨 kubernetes.io/environment: dev가 있는 클러스터에는 dev 전용 구성(즉 dev/config.json)만 적용돼요.

한 자식 generator의 파라미터를 다른 자식 generator에서 오버라이드 (Overriding parameters from one child generator in another child generator)

Matrix Generator는 같은 이름의 파라미터를 여러 자식 generator에서 정의할 수 있게 해줘요. 이는 예를 들어 한 generator에서 모든 스테이지의 기본값을 정의하고 다른 generator에서 스테이지별 값으로 오버라이드하는 데 유용해요. 아래 예시는 두 개의 git generator를 가진 matrix generator로 Helm 기반 애플리케이션을 생성해요: 첫 번째는 스테이지별 값(스테이지당 디렉토리 하나)을 제공하고, 두 번째는 모든 스테이지에 대한 전역 값을 제공해요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: parameter-override-example
spec:
  generators:
    - matrix:
        generators:
          - git:
              repoURL: https://github.com/example/values.git
              revision: HEAD
              files:
                - path: "**/stage.values.yaml"
          - git:
               repoURL: https://github.com/example/values.git
               revision: HEAD
               files:
                  - path: "global.values.yaml"
  goTemplate: true
  template:
    metadata:
      name: example
    spec:
      project: default
      source:
        repoURL: https://github.com/example/example-app.git
        targetRevision: HEAD
        path: .
        helm:
          values: |
            {{ `{{ . | mustToPrettyJson }}` }}
      destination:
        server: in-cluster
        namespace: default

다음 example/values 리포지토리의 구조/내용이 주어지면:

├── test
│   └── stage.values.yaml
│         stageName: test
│         cpuRequest: 100m
│         debugEnabled: true
├── staging
│   └── stage.values.yaml
│         stageName: staging
├── production
│   └── stage.values.yaml
│         stageName: production
│         memoryLimit: 512Mi
│         debugEnabled: false
└── global.values.yaml
      cpuRequest: 200m
      memoryLimit: 256Mi
      debugEnabled: true

위 matrix generator는 다음 결과를 산출해요:

- stageName: test
  cpuRequest: 100m
  memoryLimit: 256Mi
  debugEnabled: true

- stageName: staging
  cpuRequest: 200m
  memoryLimit: 256Mi
  debugEnabled: true

- stageName: production
  cpuRequest: 200m
  memoryLimit: 512Mi
  debugEnabled: false

예시: pathParamPrefix를 사용하는 두 개의 Git Generator

matrix generator는 자식이 서로 다른 값의 동일한 키를 포함하는 결과를 생성하면 실패해요. 두 자식이 모두 Git generator인 경우 출력에서 path 관련 파라미터를 자동으로 채우므로 이는 문제가 돼요. 이 문제를 피하려면 출력의 파라미터 키 충돌을 피하기 위해 자식 generator 중 하나 또는 둘 다에 pathParamPrefix를 지정하세요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: two-gits-with-path-param-prefix
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - matrix:
        generators:
          # git file generator referencing files containing details about each
          # app to be deployed (e.g., `appName`).
          - git:
              repoURL: https://github.com/some-org/some-repo.git
              revision: HEAD
              files:
                - path: "apps/*.json"
              pathParamPrefix: app
          # git file generator referencing files containing details about
          # locations to which each app should deploy (e.g., `region` and
          # `clusterName`).
          - git:
              repoURL: https://github.com/some-org/some-repo.git
              revision: HEAD
              files:
                - path: "targets/{{.appName}}/*.json"
              pathParamPrefix: target
  template: {} # ...

그런 다음 다음 파일 구조/내용이 주어지면:

├── apps
│   ├── app-one.json
│   │   { "appName": "app-one" }
│   └── app-two.json
│       { "appName": "app-two" }
└── targets
    ├── app-one
    │   ├── east-cluster-one.json
    │   │   { "region": "east", "clusterName": "cluster-one" }
    │   └── east-cluster-two.json
    │       { "region": "east", "clusterName": "cluster-two" }
    └── app-two
        ├── east-cluster-one.json
        │   { "region": "east", "clusterName": "cluster-one" }
        └── west-cluster-three.json
            { "region": "west", "clusterName": "cluster-three" }

…위 matrix generator는 다음 결과를 산출해요:

- appName: app-one
  app.path: /apps
  app.path.filename: app-one.json
  # plus additional path-related parameters from the first child generator, all
  # prefixed with "app".
  region: east
  clusterName: cluster-one
  target.path: /targets/app-one
  target.path.filename: east-cluster-one.json
  # plus additional path-related parameters from the second child generator, all
  # prefixed with "target".

- appName: app-one
  app.path: /apps
  app.path.filename: app-one.json
  region: east
  clusterName: cluster-two
  target.path: /targets/app-one
  target.path.filename: east-cluster-two.json

- appName: app-two
  app.path: /apps
  app.path.filename: app-two.json
  region: east
  clusterName: cluster-one
  target.path: /targets/app-two
  target.path.filename: east-cluster-one.json

- appName: app-two
  app.path: /apps
  app.path.filename: app-two.json
  region: west
  clusterName: cluster-three
  target.path: /targets/app-two
  target.path.filename: west-cluster-three.json

제한사항 (Restrictions)

  1. Matrix generator는 현재 두 자식 generator의 출력만 결합하는 것을 지원해요(예: 3개 이상의 조합 생성은 지원하지 않음).
  2. 배열 항목당 단일 generator만 지정해야 해요. 예를 들어 이것은 유효하지 않아요:
    - matrix:
        generators:
        - list: # (...)
          git: # (...)
    
    Kubernetes API 검증은 이를 받아들이지만, 컨트롤러는 생성 시 오류를 보고해요. 각 generator는 위 예시처럼 별도의 배열 요소로 지정해야 해요.
  3. Matrix generator는 자식 generator에 지정된 template 오버라이드를 현재 지원하지 않아요. 예를 들어 이 template은 처리되지 않아요:
    - matrix:
        generators:
          - list:
              elements:
                - # (...)
              template: { } # Not processed
    
  4. 조합형 generator(matrix 또는 merge)는 한 번만 중첩할 수 있어요. 예를 들어 이것은 동작하지 않아요:
    - matrix:
        generators:
          - matrix:
              generators:
                - matrix:  # This third level is invalid.
                    generators:
                      - list:
                          elements:
                            - # (...)
    
  5. 한 자식 generator의 파라미터를 다른 자식 generator에서 사용할 때, 파라미터를 소비하는 자식 generator는 파라미터를 생성하는 자식 generator 뒤에 와야 해요. 예를 들어 아래 예시는 유효하지 않아요(cluster-generator는 git-files generator 뒤에 와야 함):
    - matrix:
        generators:
          # cluster generator, 'child' #1
          - clusters:
              selector:
                matchLabels:
                  argocd.argoproj.io/secret-type: cluster
                  kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator
          # git generator, 'child' #2
          - git:
              repoURL: https://github.com/argoproj/applicationset.git
              revision: HEAD
              files:
                - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
    
  6. 두 자식 generator가 서로의 파라미터를 소비할 수는 없어요. 아래 예시에서 cluster generator는 git-files generator가 생성한 {{.path.basename}} 파라미터를 소비하고, git-files generator는 cluster generator가 생성한 {{.name}} 파라미터를 소비해요. 이는 순환 의존성이 되어 유효하지 않아요.
    - matrix:
        generators:
          # cluster generator, 'child' #1
          - clusters:
              selector:
                matchLabels:
                  argocd.argoproj.io/secret-type: cluster
                  kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator
          # git generator, 'child' #2
          - git:
              repoURL: https://github.com/argoproj/applicationset.git
              revision: HEAD
              files:
                - path: "examples/git-generator-files-discovery/cluster-config/engineering/{{.name}}**/config.json" # {{.name}} is produced by cluster generator
    

더 알아보기 (Learn more)