Go 템플릿

Go 템플릿 (Go Template)

ApplicationSet에서 Go Text Template을 사용할 수 있게 해주는 기능이에요. 복잡한 템플릿 로직이 필요한 경우 기본 fasttemplate보다 강력해서, 조건·반복·함수 활용이 가능해져요.

출처: 문서

본문

소개 (Introduction)

ApplicationSet은 Go Text Template을 사용할 수 있어요. 이 기능을 활성화하려면 ApplicationSet 매니페스트에 goTemplate: true를 추가하세요.

기본 Go Text Template 함수에 더해 Sprig 함수 라이브러리(env, expandenv, getHostByName 제외)도 사용할 수 있어요.

추가 normalize 함수는 모든 문자열 파라미터를 유효한 DNS 이름으로 사용할 수 있게 만들어 줘요 — 유효하지 않은 문자를 하이픈으로 바꾸고 253자에서 자르는 방식이에요. Application 이름 같은 것에 파라미터를 안전하게 만들 때 유용해요.

또 다른 slugify 함수가 추가됐는데, 기본적으로 정리(sanitize)하고 스마트하게 자르며(단어를 2개로 자르지 않음) 몇 가지 인자를 받아요:

  • 첫 번째 인자(제공되면)는 슬러그의 최대 길이를 지정하는 정수예요.
  • 두 번째 인자(제공되면)는 스마트 절단이 활성화되었는지 나타내는 boolean이에요.
  • 마지막 인자(제공되면)는 slugify할 입력 이름이에요.

사용 예시 (Usage example)

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: test-appset
spec:
  ...
  template:
    metadata:
      name: 'hellos3-{{.name}}-{{ cat .branch | slugify 23 }}'
      annotations:
        label-1: '{{ cat .branch | slugify }}'
        label-2: '{{ cat .branch | slugify 23 }}'
        label-3: '{{ cat .branch | slugify 50 false }}'

text/template에서 정의된 옵션을 커스터마이즈하려면 ApplicationSet에 goTemplate: true 옆에 goTemplateOptions: ["opt1", "opt2", ...] 키를 추가하면 돼요. 글을 쓰는 시점에 유용한 옵션은 missingkey=error 하나뿐임에 유의하세요.

goTemplateOptions의 권장 설정은 ["missingkey=error"]인데, 이렇게 하면 템플릿이 정의되지 않은 값을 조회할 때 조용히 무시되는 대신 오류가 보고돼요. 현재는 하위 호환성 때문에 이것이 기본 동작이 아니에요.

동기 (Motivation)

Go Template은 Go 표준 문자열 템플릿이에요. 또한 복잡한 템플릿 로직을 허용한다는 점에서 fasttemplate(기본 템플릿 엔진)보다 더 강력해요.

제한사항 (Limitations)

Go 템플릿은 필드 단위로, 문자열 필드에만 적용돼요. Go 텍스트 템플릿으로 불가능한 몇 가지 예시:

  • boolean 필드 템플릿:

    apiVersion: argoproj.io/v1alpha1
    kind: ApplicationSet
    spec:
      goTemplate: true
      goTemplateOptions: ["missingkey=error"]
      template:
        spec:
          source:
            helm:
              useCredentials: "{{.useCredentials}}"  # This field may NOT be templated, because it is a boolean field.
    
  • 객체 필드 템플릿:

    apiVersion: argoproj.io/v1alpha1
    kind: ApplicationSet
    spec:
      goTemplate: true
      goTemplateOptions: ["missingkey=error"]
      template:
        spec:
          syncPolicy: "{{.syncPolicy}}"  # This field may NOT be templated, because it is an object field.
    
  • 필드 간 제어 키워드 사용:

    apiVersion: argoproj.io/v1alpha1
    kind: ApplicationSet
    spec:
      goTemplate: true
      goTemplateOptions: ["missingkey=error"]
      template:
        spec:
          source:
            helm:
              parameters:
              # Each of these fields is evaluated as an independent template, so the first one will fail with an error.
              - name: "{{range .parameters}}"
              - name: "{{.name}}"
                value: "{{.value}}"
              - name: throw-away
                value: "{{end}}"
    
  • Git generator를 사용할 때 템플릿화된 project 필드에 대한 서명 확인은 지원되지 않아요.

    apiVersion: argoproj.io/v1alpha1
    kind: ApplicationSet
    spec:
      goTemplate: true
      template:
        spec:
          project: {{.project}}
    

마이그레이션 가이드 (Migration guide)

전역 (Globals)

모든 템플릿은 파라미터를 GoTemplate 문법으로 바꿔야 해요:

예시: {{ some.value }}{{ .some.value }}가 돼요.

Cluster Generators

Go 템플릿을 활성화하면 {{ .metadata }}가 객체가 돼요.

  • {{ metadata.labels.my-label }}{{ index .metadata.labels "my-label" }}가 돼요
  • {{ metadata.annotations.my/annotation }}{{ index .metadata.annotations "my/annotation" }}가 돼요

Git Generators

Go 템플릿을 활성화하면 {{ .path }}가 객체가 돼요. 따라서 Git generators의 템플릿에 몇 가지 변경이 필요해요:

  • {{ path }}{{ .path.path }}가 돼요
  • {{ path.basename }}{{ .path.basename }}가 돼요
  • {{ path.basenameNormalized }}{{ .path.basenameNormalized }}가 돼요
  • {{ path.filename }}{{ .path.filename }}가 돼요
  • {{ path.filenameNormalized }}{{ .path.filenameNormalized }}가 돼요
  • {{ path[n] }}{{ index .path.segments n }}가 돼요
  • 파일 generator에서 사용된다면 {{ values }}{{ .values }}가 돼요

예시:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-addons
spec:
  generators:
  - git:
      repoURL: https://github.com/argoproj/argo-cd.git
      revision: HEAD
      directories:
      - path: applicationset/examples/git-generator-directory/cluster-addons/*
  template:
    metadata:
      name: '{{path.basename}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: '{{path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{path.basename}}'

는 이렇게 됩니다:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-addons
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - git:
      repoURL: https://github.com/argoproj/argo-cd.git
      revision: HEAD
      directories:
      - path: applicationset/examples/git-generator-directory/cluster-addons/*
  template:
    metadata:
      name: '{{.path.basename}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/argo-cd.git
        targetRevision: HEAD
        path: '{{.path.path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{.path.basename}}'

Sprig 함수를 사용해 path 변수를 수동으로 구성하는 것도 가능해요:

with goTemplate: false with goTemplate: true with goTemplate: true + Sprig
{{path}} {{.path.path}} {{.path.path}}
{{path.basename}} {{.path.basename}} {{base .path.path}}
{{path.filename}} {{.path.filename}} {{.path.filename}}
{{path.basenameNormalized}} {{.path.basenameNormalized}} {{normalize .path.path}}
{{path.filenameNormalized}} {{.path.filenameNormalized}} {{normalize .path.filename}}
{{path[N]}} - {{index .path.segments N}}

사용 가능한 템플릿 함수 (Available template functions)

ApplicationSet 컨트롤러가 제공하는 것:

  • env, expandenv, getHostByName을 제외한 모든 sprig Go 템플릿 함수
  • normalize: 다음 규칙을 준수하도록 입력을 정리해요:
    1. 253자를 넘지 않음
    2. 소문자 영숫자, - 또는 .만 포함
    3. 영숫자 문자로 시작하고 끝남
  • slugify: 소개 섹션에서 설명한 대로 normalize처럼 정리하고 스마트하게 자름(단어를 2개로 자르지 않음).
  • toYaml / fromYaml / fromYamlArray helm 같은 함수

예시 (Examples)

기본 Go 템플릿 사용 (Basic Go template usage)

이 예시는 기본 문자열 파라미터 치환을 보여줘요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  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: my-project
      source:
        repoURL: https://github.com/infra-team/cluster-deployments.git
        targetRevision: HEAD
        path: guestbook/{{.cluster}}
      destination:
        server: '{{.url}}'
        namespace: guestbook

미설정 파라미터 폴백 (Fallbacks for unset parameters)

일부 generator에서는 특정 이름의 파라미터가 항상 채워지지 않을 수 있어요(예: values generator나 git files generator). 이런 경우 Go 템플릿을 사용해 폴백 값을 제공할 수 있어요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - list:
      elements:
      - cluster: engineering-dev
        url: https://kubernetes.default.svc
      - cluster: engineering-prod
        url: https://kubernetes.default.svc
        nameSuffix: -my-name-suffix
  template:
    metadata:
      name: '{{.cluster}}{{dig "nameSuffix" "" .}}'
    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

이 ApplicationSet은 engineering-dev라는 Application과 engineering-prod-my-name-suffix라는 Application을 생성해요.

미설정 파라미터는 오류이므로 존재하지 않는 속성 조회는 피해야 해요. 대신 dig 같은 템플릿 함수를 사용해 기본값으로 조회하세요. 미설정 파라미터를 0으로 기본값 처리하고 싶다면 goTemplateOptions: ["missingkey=error"]를 제거하거나 goTemplateOptions: ["missingkey=invalid"]로 설정하면 돼요.

더 알아보기 (Learn more)