[Kubernetes] Helm Chart Template 정리

안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 헬름 차트의 템플릿에 대해서 정리해보도록 하겠습니다. 필자의 프로젝트에서는 k8s를 활용하여 서비스를 하고자 진행중입니다.POD, SVC, ALB 를 모두 만들어서 연결은 해두었느데, CI/CD를 어떻게 할지 고민중이였습니다. 그러던 중, Helm을 알게되었고, 제가 작성해둔 Yaml 파일들을 Helm Chart로 작성을 해두고 배포시에 install을 하는 개념으로 진행하기로했습니다.

지난 글들은 아래를 참고 해주시면 됩니다.

1. Chart Template 시작하기

# mkdir /lab/helm/chart
# cd /lab/helm/chart

# helm create mychart
Creating mychart

# tree
.
└── mychart
    ├── charts
    ├── Chart.yaml
    ├── templates
    │   ├── deployment.yaml
    │   ├── _helpers.tpl
    │   ├── ingress.yaml
    │   ├── NOTES.txt
    │   ├── service.yaml
    │   └── tests
    │       └── test-connection.yaml
    └── values.yaml

위의 예제에서 중요한 부분은 templates 하위의 파일들입니다. 이부분을 커스터마이징 하기 위해 삭제 합니다.

# rm -rf mychart/templates/*

2. 첫번째 Template

간단한 Kubernetes configmap Object를 하나 생성해 배포해보도록하겠습니다.

# gedit /lab/helm/chart/mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

helm install로 클러스터에 배포합니다.

# helm install ./mychart
NAME:   alliterating-eel
LAST DEPLOYED: Wed Mar 20 13:15:12 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME               DATA  AGE
mychart-configmap  1     

배포된 실제 차트를 확인하기 위해서는 get명령어로 manifest를 조회하면 됩니다.

# helm get manifest alliterating-eel

---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

2-1. 단순 template 호출

위의 예제에서 하드코딩된 name값을 헬름 내장 객체 release name으로 변경해보겠습니다.

TIP: name: 필드는 DNS의 제한때문에 63 character로 제한됩니다. 이에 대응해 release name은 53 character로 제한됩니다.

configmap.yaml을 아래와 같이 수정한 후 다시 install을 진행하겠습니다.

# gedit /lab/helm/chart/mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
# helm install ./mychart
NAME:   good-abalone
LAST DEPLOYED: Wed Mar 20 14:02:57 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                    DATA  AGE
good-abalone-configmap  1     

Helm에서는 위와 같이 편집중인 차트를 미리 확인 하기 위한 모드를 제공하고 있습니다. install명령어에 아래와 같이 옵션을 주면 실제로 install은 되지 않고 템플릿이 어떻게 랜더링되는지 확인 할 수 있습니다.

# helm install --debug --dry-run ./mychart
[debug] Created tunnel using local port: '33941'

[debug] SERVER: "127.0.0.1:33941"

[debug] Original chart version: ""
[debug] CHART PATH: /lab/helm/chart/mychart

NAME:   invisible-abalone
REVISION: 1
RELEASED: Wed Mar 20 14:12:30 2019
CHART: mychart-0.1.0
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
affinity: {}
fullnameOverride: ""
image:
  pullPolicy: IfNotPresent
  repository: nginx
  tag: stable
ingress:
  annotations: {}
  enabled: false
  hosts:
  - host: chart-example.local
    paths: []
  tls: []
nameOverride: ""
nodeSelector: {}
replicaCount: 1
resources: {}
service:
  port: 80
  type: ClusterIP
tolerations: []

HOOKS:
MANIFEST:

---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: invisible-abalone-configmap
data:
  myvalue: "Hello World"

3. Values Files

이번에는 Values 파일을 활용하여 템플릿을 변경해보도록 하겠습니다.

참고로 Values File은 아래와 같은 특징을 가지고 있습니다.

  • 차트안에 values.yaml 파일명으로 생성된 파일입니다.
  • 상위 차트의values.yaml에 의해 재정의 될 수 있습니다.
  • helm install or helm upgrade 시 -f 옵션으로 변경될 수 있습니다.(helm install -f myvals.yaml ./mychart)
  • 개별적인 속성 값은 --set옵션으로 변경할 수 있습니다. (such as helm install --set foo=bar ./mychart)

위의 예제에서 mychart/values.yaml을 변경해 ConfigMap template에 반영해봅시다.

# gedit /lab/helm/chart/mychart/values.yaml
favoriteDrink: coffee

그리고 template 폴더안의 configmap.yaml파일에 해당내용을 반영합니다.

# gedit /lab/helm/chart/mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favoriteDrink }}

렌더링해서 결과를 확인해 봅니다.

---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: kneeling-puffin-configmap
data:
  myvalue: "Hello World"
  drink: coffee

values.yaml파일에 정의한 coffee가 템플릿에 반영된 것을 확인 할 수 있습니다.

이렇게 Values로 정의 된 속성은 위에서 언급했지만 install 명령어시 –set 옵션으로 아래와 같이 오버라이딩 될 수 있습니다.

# helm install --dry-run --debug --set favoriteDrink=slurm ./mychart
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: dusty-nightingale-configmap
data:
  myvalue: "Hello World"
  drink: slurm

4. Template Functions and Pipelines

이번에는 Template 파일들 안에서 사용할 수 있는 함수와 Pipeline에 대해 살펴보겠습니다.

ConfigMap 객체에 문자열을 삽입할 때 quote 함수를 사용할 수 있습니다.

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

Template 함수들은 functionName arg1 arg2.... 와 같은 신텍스를 가집니다.

Helm은 60개 이상의 함수들을 사용할 수 있습니다. 해당내용은 Go template language , Sprig template library에서 확인 할 수 있습니다.

4-1. Pipelines

UNIX의 개념과 동일

gedit /lab/helm/chart/mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

위의 예제는 아래와 같이 렌더링됩니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: trendsetting-p-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"

4-2. default function

default함수는 비교적 자주사용되는 함수로 Value값이 생략 된 경우 템플릿 내부에 기본값을 지정할 수 있게합니다.

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 }}

5. Flow Control

Flow Control로 템플릿 구조의 흐름을 제어할 수 있습니다.

  • if/else 조건 블록 생성
  • with범위 지정
  • range, “for each”-style loop

In addition to these, it provides a few actions for declaring and using named template segments:

  • define declares a new named template inside of your template
  • template imports a named template
  • block declares a special kind of fillable template area

5-1. IF/Else

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

파이프라인은 value가 아래와 같을 때 false로 인식합니다.

  • a boolean false
  • a numeric zero
  • an empty string
  • a nil (empty or null)
  • an empty collection (map, slice, tuple, dict, array)
gedit /lab/helm/chart/mychart/templates/configmap.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 and .Values.favorite.drink (eq .Values.favorite.drink "coffee") }}mug: true{{ end }}
helm install --dry-run --debug ./mychart
apiVersion: v1
kind: ConfigMap
metadata:
  name: eyewitness-elk-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  mug: true

5-2. with

{{ with PIPELINE }}
  # restricted scope
{{ end }}
gedit /lab/helm/chart/mychart/templates/configmap.yaml
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 }}
helm install --dry-run --debug ./mychart

5-3. ragne

foreach loop와 동일한 성격의 제어문으로 예제를 아래와 같이 수정하겠습니다.

gedit /lab/helm/chart/mychart/values.yaml
favorite:
  drink: coffee
  food: pizza
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions
gedit /lab/helm/chart/mychart/templates/configmap.yaml
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 }}
helm install --dry-run --debug ./mychart
# 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"

6. Variables

다른 프로그램언어와 마찬가지로 변수를 생성해 활용할 수 있습니다.

위의 예제를 아래와 같이 수정하면 에러가 발생하는데 원인은 .Release.Name은 with블럭 안에서는 사용될 수 없기 때문입니다. 이런 경우에 변수를 생성하여 활용할 수 있습니다.

gedit /lab/helm/chart/mychart/templates/configmap.yaml
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  release: {{ .Release.Name }}
  {{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {{- $relname := .Release.Name -}}
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  release: {{ $relname }}
  {{- end }}
helm install --dry-run --debug ./mychart
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: viable-badger-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  release: viable-badger

이러한 변수를 range 문과 같이 사용하면 효과적일 수 있습니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end}}
helm install --dry-run --debug ./mychart
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: eager-rabbit-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"

7. ETC

  • .helmignore

.helmignore 파일은 gitignore와 dockeriignore파일과 마찬가지로 헬름차트안에 포함되지 않을 파일들을 명세하는 파일입니다.

# comment
.git
*/temp*
*/*/temp*
temp?
  • NOTES.txt
gedit /lab/helm/chart/mychart/templates/NOTES.txt
Thank you for installing {{ .Chart.Name }}.

Your release is named {{ .Release.Name }}.

To learn more about the release, try:

  $ helm status {{ .Release.Name }}
  $ helm get {{ .Release.Name }}
helm install ./mychart
RESOURCES:
==> v1/Secret
NAME                   TYPE      DATA      AGE
rude-cardinal-secret   Opaque    1         0s

==> v1/ConfigMap
NAME                      DATA      AGE
rude-cardinal-configmap   3         0s


NOTES:
Thank you for installing mychart.

Your release is named rude-cardinal.

To learn more about the release, try:

  $ helm status rude-cardinal
  $ helm get rude-cardinal

8. 마치며..

이번시간에는 helm template에 대한 기본 사용버베 대해서 알아보는 시간을 갖었습니다. 헬름은 필자가 느끼기에는 패키징 셋트 같습니다. 여러개의 resource들을 하나의 묶음으로 만들어서 install 하게되면 k8s 의 리소스들이 하나씩 모두 올라오게 됩니다. helm을 통한 배포 관리에 대한 내용으로 다음시간에 정리해보도록 하겠습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다