ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Helm] 가이드 - Flow Control
    공부/쿠버네티스&헬름 2025. 3. 15. 20:33

    Helm 템플릿에서 Flow Control은 템플릿이 어떻게 렌더링될지 제어하는 데 사용되는 구문 구조를 의미합니다. 이를 통해 조건부 로직, 반복문 등을 템플릿 내에 구현하여 유연하고 동적인 매니페스트 생성을 가능하게 합니다. Helm의 Flow Control은 Go 템플릿 언어를 기반으로 하며, 특정 액션(Actions)을 사용하여 정의됩니다.

    if/else

    조건문의 기본 구조는 다음과 같습니다.

    {{ if PIPELINE }}
      # Do something
    {{ else if OTHER PIPELINE }}
      # Do something else
    {{ else }}
      # Default case
    {{ end }}

    파이프라인을 사용하면 조건문과 비슷한 표현을 할 수 있습니다. 파이프라인은 다음의 경우 false로 평가됩니다.

    • boolean 값 false
    • 숫자 0
    • 빈 문자열
    • nil (비어 있거나 null)
    • 빈 컬렉션 (맵, 슬라이스, 튜플, 딕트, 배열)

    다른 모든 조건에서는 조건이 true입니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ .Release.Name }}-configmap
    data:
      myvalue: "Hello World"
      drink: {{ .Values.favorite.drink | default "tea" | quote }}
      food: {{ .Values.favorite.food | upper | quote }}
      {{ if eq .Values.favorite.drink "coffee" }}mug: "true"{{ end }}
    
    
    -- 아래와 같이 확인 가능
      # Source: mychart/templates/configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: eyewitness-elk-configmap
    data:
      myvalue: "Hello World"
      drink: "coffee"
      food: "PIZZA"
      mug: "true"

    공백 제어

    아래의 yaml을 실행하면 mug 필드에 공백이 1개 더 추가되어 있어서 parsing error가 발생합니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ .Release.Name }}-configmap
    data:
      myvalue: "Hello World"
      drink: {{ .Values.favorite.drink | default "tea" | quote }}
      food: {{ .Values.favorite.food | upper | quote }}
      {{ if eq .Values.favorite.drink "coffee" }}
        mug: "true"
      {{ end }}
    
    -------
    $ helm install --dry-run --debug ./mychart
    SERVER: "localhost:44134"
    CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart
    Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key
    
    --------
    # Source: mychart/templates/configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: eyewitness-elk-configmap
    data:
      myvalue: "Hello World"
      drink: "coffee"
      food: "PIZZA"
        mug: "true"

    들여쓰기를 정상적으로 한다면 다음과 같이 어색하게 출력됩니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ .Release.Name }}-configmap
    data:
      myvalue: "Hello World"
      drink: {{ .Values.favorite.drink | default "tea" | quote }}
      food: {{ .Values.favorite.food | upper | quote }}
      {{ if eq .Values.favorite.drink "coffee" }}
      mug: "true"
      {{ end }}
    
    ------
    # Source: mychart/templates/configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: telling-chimp-configmap
    data:
      myvalue: "Hello World"
      drink: "coffee"
      food: "PIZZA"
    
      mug: "true"

    템플릿 엔진이 실행될 때 {{}} 안의 내용은 제거하지만 나머지 공백은 정확히 그대로 남겨둡니다.

    YAML은 공백에 의미를 부여하므로 공백 관리가 매우 중요해집니다. 이를 해결하는 방법으론 첫째, 템플릿 선언의 중괄호 문법은 템플릿 엔진에게 공백을 잘라내도록 지시하는 특수 문자로 수정할 수 있습니다. {{- (대시와 공백이 추가됨)는 왼쪽의 공백을 잘라내야 함을 나타내고, -}}는 오른쪽의 공백을 소비해야 함을 의미합니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ .Release.Name }}-configmap
    data:
      myvalue: "Hello World"
      drink: {{ .Values.favorite.drink | default "tea" | quote }}
      food: {{ .Values.favorite.food | upper | quote }}
      {{- if eq .Values.favorite.drink "coffee" }}
      mug: "true"
      {{- end }}
    
    -------
    # Source: mychart/templates/configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: clunky-cat-configmap
    data:
      myvalue: "Hello World"
      drink: "coffee"
      food: "PIZZA"
      mug: "true"

    만약 하이픈을 왼쪽 뿐만 아니라 오른쪽에도 붙인다면 양쪽 모두 줄바꿈 문자를 사용하기 때문에 아래와 같은 결과가 나옵니다.

    food: {{ .Values.favorite.food | upper | quote }}
      {{- if eq .Values.favorite.drink "coffee" -}}
      mug: "true"
      {{- end -}}
    
    ------
    food: "PIZZA"mug: "true"

    마지막으로, 템플릿 지시문의 간격 조정을 완벽하게 익히려고 애쓰는 대신, 템플릿 시스템에게 들여쓰기를 어떻게 할지 알려주는 것이 더 쉬울 때가 있습니다. 이러한 이유로 indent 함수({{ indent 2 "mug:true" }})를 사용하는 것이 유용할 때가 있습니다.

    with

    특정 객체의 스코프 내에서 템플릿의 일부를 실행하는 데 사용됩니다. 이를 통해 긴 경로를 반복해서 사용하는 것을 방지하고 템플릿을 더 간결하게 만들 수 있습니다. .은 현재 스코프에 대한 참조이므로 .Values는 템플릿에게 현재 스코프에서 Values 객체를 찾으라고 지시합니다.

    with의 문법은 간단한 if 구문과 유사합니다.

    {{ with PIPELINE }}
      # restricted scope
    {{ end }}

    스코프는 변경될 수 있습니다. with를 사용하면 현재 스코프(.)를 특정 객체로 설정할 수 있습니다. 예를 들어, 우리는 .Values.favorite로 작업을 해왔습니다. . 스코프가 .Values.favorite를 가리키도록 ConfigMap을 다시 작성해 보겠습니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ .Release.Name }}-configmap
    data:
      myvalue: "Hello World"
      {{- with .Values.favorite }}
      drink: {{ .drink | default "tea" | quote }}
      food: {{ .food | upper | quote }}
      {{- end }}

    with 뒤의 블록은 PIPELINE의 값이 비어 있지 않은 경우에만 실행됩니다.

    이제 .drink.food를 한정자 없이 참조할 수 있습니다. 이는 with 구문이 ..Values.favorite를 가리키도록 설정했기 때문입니다. .{{ end }} 뒤에 이전 스코프로 재설정됩니다.

    제한된 스코프 내에서는 ..을 사용하여 부모 스코프의 다른 객체에 접근할 수 없습니다. 예를 들어, 다음 코드는 실패합니다.

    {{- with .Values.favorite }}
    drink: {{ .drink | default "tea" | quote }}
    food: {{ .food | upper | quote }}
    release: {{ .Release.Name }}
    {{- end }}

    이는 Release.Name..에 대한 제한된 스코프 내에 없기 때문에 오류를 발생시킬 것입니다. 하지만 마지막 두 줄의 순서를 바꾸면 {{ end }} 이후에 스코프가 재설정되므로 모든 것이 예상대로 작동할 것입니다.

    {{- with .Values.favorite }}
    drink: {{ .drink | default "tea" | quote }}
    food: {{ .food | upper | quote }}
    {{- end }}
    release: {{ .Release.Name }}

    또는 부모 스코프에서 Release.Name 객체에 접근하기 위해 $를 사용할 수 있습니다. $는 템플릿 실행이 시작될 때 루트 스코프에 매핑되며 템플릿 실행 중에는 변경되지 않습니다. 다음 코드도 잘 작동할 것입니다.

    {{- with .Values.favorite }}
    drink: {{ .drink | default "tea" | quote }}
    food: {{ .food | upper | quote }}
    release: {{ $.Release.Name }}
    {{- end }}

    range

    리스트나 맵과 같은 컬렉션의 각 항목에 대해 템플릿의 특정 부분을 반복적으로 렌더링하는 데 사용됩니다.

    values.yaml 파일에 피자 토핑 목록이 있다고 가정합니다.

    favorite:
      drink: coffee
      food: pizza
    pizzaToppings:
      - mushrooms
      - cheese
      - peppers
      - onions
      - pineapple

    이제 pizzaToppings라는 리스트(템플릿에서는 슬라이스라고 함)가 생겼습니다. 이 리스트를 ConfigMap에 출력하도록 템플릿을 수정해봅니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ .Release.Name }}-configmap
    data:
      myvalue: "Hello World"
      {{- with .Values.favorite }}
      drink: {{ .drink | default "tea" | quote }}
      food: {{ .food | upper | quote }}
      {{- end }}
      toppings: |-
        {{- range .Values.pizzaToppings }}
        - {{ . | title | quote }}
        {{- end }}    

    부모 스코프에서 Values.pizzaToppings 리스트에 접근하기 위해 $를 사용할 수 있습니다. $는 템플릿 실행이 시작될 때 루트 스코프에 매핑되며 템플릿 실행 중에는 변경되지 않습니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ .Release.Name }}-configmap
    data:
      myvalue: "Hello World"
      {{- with .Values.favorite }}
      drink: {{ .drink | default "tea" | quote }}
      food: {{ .food | upper | quote }}
      toppings: |-
        {{- range $.Values.pizzaToppings }}
        - {{ . | title | quote }}
        {{- end }}    
      {{- end }}

    toppings: 리스트를 자세히 살펴보겠습니다. range 함수는 pizzaToppings 리스트를 "range over"(반복)합니다. 여기서 with.의 스코프를 설정하는 것처럼 range 연산자도 마찬가지입니다. 루프를 반복할 때마다 .은 현재 피자 토핑으로 설정됩니다. 즉, 처음에는 .mushrooms로 설정됩니다. 두 번째 반복에서는 cheese로 설정되는 식입니다.

    .의 값을 파이프라인으로 직접 보낼 수 있으므로 {{ . | title | quote }}를 실행하면 .title (제목 케이스 함수)로 보내진 다음 quote로 보내집니다. 이 템플릿을 실행하면 다음과 같은 출력이 생성됩니다.

    # Source: mychart/templates/configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: edgy-dragonfly-configmap
    data:
      myvalue: "Hello World"
      drink: "coffee"
      food: "PIZZA"
      toppings: |-
        - "Mushrooms"
        - "Cheese"
        - "Peppers"
        - "Onions"
        - "Pineapple"

    이제 이 예제에서 toppings: |- 줄은 여러 줄 문자열을 선언하고 있습니다. 따라서 토핑 목록은 실제로 YAML 목록이 아니라 하나의 큰 문자열입니다. 이렇게 한 이유는 ConfigMap의 data는 키/값 쌍으로 구성되어 있으며 키와 값 모두 단순한 문자열이기 때문입니다.

    템플릿 내에서 빠르게 리스트를 만들고 그 리스트를 순회하는 것이 유용할 때가 있습니다. tuple 함수를 사용하면 이를 쉽게 구현할 수 있습니다.

      sizes: |-
        {{- range tuple "small" "medium" "large" }}
        - {{ . }}
        {{- end }} 
    
    --------
    sizes: |-
      - small
      - medium
      - large  

    레퍼런스

    https://helm.sh/docs/chart_template_guide/control_structures/

    댓글