[Kubernetes] Helm Chart Template 정리
안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 헬름 차트의 템플릿에 대해서 정리해보도록 하겠습니다. 필자의 프로젝트에서는 k8s를 활용하여 서비스를 하고자 진행중입니다.POD, SVC, ALB
를 모두 만들어서 연결은 해두었느데, CI/CD를 어떻게 할지 고민중이였습니다. 그러던 중, Helm을 알게되었고, 제가 작성해둔 Yaml 파일들을 Helm Chart로 작성을 해두고 배포시에 install을 하는 개념으로 진행하기로했습니다.
지난 글들은 아래를 참고 해주시면 됩니다.
- 쿠버네티스 1편 : 설치 가이드
- 쿠버네티스 2편 : pod
- 쿠버네티스 3편 : service
- 쿠버네티스 4편 : deployment
- 쿠버네티스 5편 : pod 설정
- 쿠버네티스 6편 : 배포 전략
- 쿠버네티스 7편 : volume
- 쿠버네티스 8편 : daemonset
- 쿠버네티스 9편 : 테라폼을 통한 클러스터 구성
- 쿠버네티스 10편 : eks에서 volume 사용하기
- 쿠버네티스 11편 : helm
- 쿠버네티스 12편 : helm chart template
- 쿠버네티스 13편 : helm deploy
- 쿠버네티스 14편 : fluentd를 통한 log수집
- 쿠버네티스 15편 : chartmuseum
- 쿠버네티스 16편 : 배포툴(ArgoCD 설치방법/사용법)
- 쿠버네티스 17편 : 배포툴(ArgoCD 구성/알람)
- 쿠버네티스 18편 : 쿠버네티스 Autoscailing
- 쿠버네티스 19편 : 쿠버네티스 로깅 아키텍처
1. Chart Template 시작하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 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
하위의 파일들입니다. 이부분을 커스터마이징 하기 위해 삭제 합니다.
1 2 |
# rm -rf mychart/templates/* |
2. 첫번째 Template
간단한 Kubernetes configmap Object를 하나 생성해 배포해보도록하겠습니다.
1 2 |
# gedit /lab/helm/chart/mychart/templates/configmap.yaml |
1 2 3 4 5 6 7 |
apiVersion: v1 kind: ConfigMap metadata: name: mychart-configmap data: myvalue: "Hello World" |
helm install로 클러스터에 배포합니다.
1 2 3 4 5 6 7 8 9 10 11 12 |
# 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 <invalid> |
배포된 실제 차트를 확인하기 위해서는 get명령어로 manifest를 조회하면 됩니다.
1 2 3 4 5 6 7 8 9 10 11 |
# 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을 진행하겠습니다.
1 2 |
# gedit /lab/helm/chart/mychart/templates/configmap.yaml |
1 2 3 4 5 6 7 |
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" |
1 2 3 4 5 6 7 8 9 10 11 |
# 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 <invalid> |
Helm에서는 위와 같이 편집중인 차트를 미리 확인 하기 위한 모드를 제공하고 있습니다. install명령어에 아래와 같이 옵션을 주면 실제로 install은 되지 않고 템플릿이 어떻게 랜더링되는지 확인 할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# 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
orhelm upgrade
시 -f 옵션으로 변경될 수 있습니다.(helm install -f myvals.yaml ./mychart
)- 개별적인 속성 값은
--set
옵션으로 변경할 수 있습니다. (such ashelm install --set foo=bar ./mychart
)
위의 예제에서 mychart/values.yaml
을 변경해 ConfigMap template에 반영해봅시다.
1 2 |
# gedit /lab/helm/chart/mychart/values.yaml |
1 2 |
favoriteDrink: coffee |
그리고 template 폴더안의 configmap.yaml파일에 해당내용을 반영합니다.
1 2 |
# gedit /lab/helm/chart/mychart/templates/configmap.yaml |
1 2 3 4 5 6 7 8 |
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favoriteDrink }} |
렌더링해서 결과를 확인해 봅니다.
1 2 3 4 5 6 7 8 9 10 |
--- # 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 옵션으로 아래와 같이 오버라이딩 될 수 있습니다.
1 2 |
# helm install --dry-run --debug --set favoriteDrink=slurm ./mychart |
1 2 3 4 5 6 7 8 9 |
# 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 함수를 사용할 수 있습니다.
1 2 3 4 5 6 7 8 9 |
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의 개념과 동일
1 2 |
gedit /lab/helm/chart/mychart/templates/configmap.yaml |
1 2 3 4 5 6 7 8 9 |
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" drink: {{ .Values.favorite.drink | quote }} food: {{ .Values.favorite.food | upper | quote }} |
위의 예제는 아래와 같이 렌더링됩니다.
1 2 3 4 5 6 7 8 9 |
apiVersion: v1 kind: ConfigMap metadata: name: trendsetting-p-configmap data: myvalue: "Hello World" drink: "coffee" food: "PIZZA" |
4-2. default function
default
함수는 비교적 자주사용되는 함수로 Value값이 생략 된 경우 템플릿 내부에 기본값을 지정할 수 있게합니다.
1 2 3 4 5 6 7 8 9 |
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 templatetemplate
imports a named templateblock
declares a special kind of fillable template area
5-1. IF/Else
1 2 3 4 5 6 7 8 |
{{ 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
)
1 2 |
gedit /lab/helm/chart/mychart/templates/configmap.yaml |
1 2 3 4 5 6 7 8 9 10 |
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 }} |
1 2 |
helm install --dry-run --debug ./mychart |
1 2 3 4 5 6 7 8 9 10 |
apiVersion: v1 kind: ConfigMap metadata: name: eyewitness-elk-configmap data: myvalue: "Hello World" drink: "coffee" food: "PIZZA" mug: true |
5-2. with
1 2 3 4 |
{{ with PIPELINE }} # restricted scope {{ end }} |
1 2 |
gedit /lab/helm/chart/mychart/templates/configmap.yaml |
1 2 3 4 5 6 7 8 9 10 11 |
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 }} |
1 2 |
helm install --dry-run --debug ./mychart |
5-3. ragne
foreach
loop와 동일한 성격의 제어문으로 예제를 아래와 같이 수정하겠습니다.
1 2 |
gedit /lab/helm/chart/mychart/values.yaml |
1 2 3 4 5 6 7 8 9 |
favorite: drink: coffee food: pizza pizzaToppings: - mushrooms - cheese - peppers - onions |
1 2 |
gedit /lab/helm/chart/mychart/templates/configmap.yaml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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 }} |
1 2 |
helm install --dry-run --debug ./mychart |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 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블럭 안에서는 사용될 수 없기 때문입니다. 이런 경우에 변수를 생성하여 활용할 수 있습니다.
1 2 |
gedit /lab/helm/chart/mychart/templates/configmap.yaml |
1 2 3 4 5 6 |
{{- with .Values.favorite }} drink: {{ .drink | default "tea" | quote }} food: {{ .food | upper | quote }} release: {{ .Release.Name }} {{- end }} |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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 }} |
1 2 |
helm install --dry-run --debug ./mychart |
1 2 3 4 5 6 7 8 9 10 11 |
# 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 문과 같이 사용하면 효과적일 수 있습니다.
1 2 3 4 5 6 7 8 9 10 |
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: myvalue: "Hello World" {{- range $key, $val := .Values.favorite }} {{ $key }}: {{ $val | quote }} {{- end}} |
1 2 |
helm install --dry-run --debug ./mychart |
1 2 3 4 5 6 7 8 9 10 |
# 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파일과 마찬가지로 헬름차트안에 포함되지 않을 파일들을 명세하는 파일입니다.
1 2 3 4 5 6 |
# comment .git */temp* */*/temp* temp? |
- NOTES.txt
1 2 |
gedit /lab/helm/chart/mychart/templates/NOTES.txt |
1 2 3 4 5 6 7 8 9 |
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 }} |
1 2 |
helm install ./mychart |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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을 통한 배포 관리에 대한 내용으로 다음시간에 정리해보도록 하겠습니다.