Overview
오늘은 Helm Chart Template 문법에 대해서 알아보자.
Helm Chart Template 문법
Helm에서 YAML 파일은 차트 템플릿 및 값에 사용되어 Kubernetes 리소스에 대한 구성을 정의한다. Helm의 템플릿 구문은 Go 템플릿을 사용하여 동적 구성을 활성화하므로 Helm 차트 템플릿 내에서 표준 YAML과 Go 템플릿의 조합을 찾을 수 있다. 주요 구문 패턴은 다음과 같다.
Standard YAML Syntax
Helm 차트는 들여쓰기 및 `key:value` 쌍을 사용하여 구성 설정을 정의하는 YAML로 작성된다.
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app: my-app
Go Templating Syntax (`{{ ... }}`)
Helm은 `{{ ... }}` 로 구분된 YAML 파일 내 동적 값에 Go 템플릿을 사용한다.
metadata:
name: {{ .Release.Name }}-service
Values Reference (`.Values`)
`.Values` 는 사용자 제공 구성을 위해 `values.yaml` 파일에 액세스 한다.
spec:
replicas: {{ .Values.replicaCount }}
Release and Chart Metadata (`.Release, .Chart`)
`.Release: .Release.Name`, .`Release.Namespace`, .`Release.Revision` 등 릴리스에 대한 세부 정보를 제공한다.
`.Chart: .Chart.Name`, .`Chart.Version` 과 같이 `Chart.yaml` 파일에 정의된 메타데이터에 액세스한다.
metadata:
labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
Conditional Logic (`if/else Statements`)
조건문을 사용하면 지정된 조건에 따라 섹션을 렌더링할 수 있다.
{{ if .Values.service.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-service
{{ end }}
Loops (`range`)
`ragne` 는 목록이나 맵을 반복하며 여러 리소스를 동적으로 생성하는 데 유용하다.
ports:
{{- range .Values.ports }}
- port: {{ . }}
{{- end }}
Default Values (default function)
`default` 는 값이 설정되지 않은 경우 대체 값을 제공한다.
replicas: {{ .Values.replicaCount | default 1 }}
Defining and Using Templates
Helm을 사용하면 define 및 template을 사용하여 차트 내에서 재사용 가능한 템플릿을 정의할 수 있다.
정의
{{- define "mychart.labels" -}}
app: {{ .Chart.Name }}
release: {{ .Release.Name }}
{{- end }}
사용
metadata:
labels:
{{ include "mychart.labels" . | nindent 4 }}
Pipeline Operators (`|`)
파이프(`|`)는 한 함수에서 다른 함수로 출력을 보낸다. 일반적으로 `quote`, `default` 또는 `toYaml` 과 같은 함수에 사용
host: {{ .Values.hostname | quote }}
- 여기서는 `.Values.hostname` 값에 `quote` 를 적용하여 문자열로 포맷한다.
사용 에시
host: "example.com"
`toYaml` 은 데이터 구조(예: 배열, 사전 또는 중첩 객체)를 YAML 형식의 문자열로 변환합니다. 이는 복잡한 데이터 구조를 YAML 구문으로 직접 변환하는 데 특히 유용하다.
env:
{{ .Values.envVars | toYaml | indent 4 }}
- 여기서 `.Values.envVars` 는 복잡한 데이터 구조이며 list or dictionary 일 수 있다. `toYaml` 은 이를 YAML 형식의 텍스트로 변환하고, `indent 4` 는 상위 구조 내에서 올바르게 정렬한다.
사용예시
envVars:
- name: ENV_VAR1
value: "value1"
- name: ENV_VAR2
value: "value2"
결과값
env:
- name: ENV_VAR1
value: "value1"
- name: ENV_VAR2
value: "value2"
Indentation and Nesting (`indent, nindent`)
`indent` 및 `nindent`'는 특히 중첩된 YAML 구조에서 간격을 관리하는 데 도움이 된다.
- `indent`: 시작 부분에 줄 바꿈을 추가하지 않고 텍스트의 각 줄 앞에 지정된 수의 공백을 추가한다.
- `nindent`: indent 와 비슷하지만 시작 부분에 줄 바꿈이 포함되어 있어 YAML 내에서 새 섹션을 시작하는 데 유용하다.
metadata:
labels:
{{- include "mychart.labels" . | nindent 6 }}
- `nindent 6` 은 출력의 각 줄 시작 부분에 6개의 공백을 추가하고 줄 바꿈으로 시작하여 labels 내에서 정렬한다.
env:
{{ .Values.envVars | toYaml | indent 4 }}
- `.Values.envVars` 의 YAML 구조를 4칸 들여쓰기한다.
Use `include`
`include` 기능을 사용하면 차트 내에서 다른 템플릿을 호출하거나 재사용할 수 있다.
`include` 는 포함할 템플릿 이름과 템플릿의 컨텍스트(또는 범위)라는 두 가지 인수를 사용한다.
{{ include "template-name" . }}
일단 정의되면 `include` 를 사용하여 템플릿을 차트의 어느 곳에나 포함할 수 있다.
metadata:
labels:
{{ include "mychart.labels" . | nindent 4 }}
정의는 `templates/_helpers.tpl` 에 정의하면 된다. `helm create` 로 생성하면, 기본적으로 정의된다.
{{/*
Expand the name of the chart.
*/}}
{{- define "somaz.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "somaz.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "somaz.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "somaz.labels" -}}
helm.sh/chart: {{ include "somaz.chart" . }}
{{ include "somaz.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "somaz.selectorLabels" -}}
app.kubernetes.io/name: {{ include "somaz.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "somaz.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "somaz.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Helm Chart Template 활용
이제 deployment template 을 예시로 활용해서 template 작성후해보자.
아래와 같이 작성이 가능하다.
`templates/deployment.yaml`
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "somaz.fullname" . }}
labels:
{{- include "somaz.labels" . | nindent 4 }}
spec:
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "somaz.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "somaz.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "somaz.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
volumes:
{{- range $persistentVolumeClaim := .Values.persistentVolumeClaims }}
- name: {{ $persistentVolumeClaim.type }}
persistentVolumeClaim:
claimName: {{ $persistentVolumeClaim.name }}
{{- end}}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
{{- range $key, $value := .Values.envConfig }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
envFrom:
{{- range $config := .Values.configs }}
- configMapRef:
name: {{ $config.name }}
{{- end}}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
volumeMounts:
{{- range $persistentVolumeClaim := .Values.persistentVolumeClaims }}
- name: {{ $persistentVolumeClaim.type }}
mountPath: {{ $persistentVolumeClaim.mountPath }}
{{- end}}
livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
`somaz.values.yaml`
# Default values for somaz.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: harbor.somaz.link/somaz/game
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "362aa67"
imagePullSecretCreate:
enabled: true
name: harbor-robot-secret
dockerconfigjson: # dockerconfigjson
imagePullSecrets:
- name: harbor-robot-secret
nameOverride: "somaz"
fullnameOverride: "somaz"
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
targetPort: 3000
ingress:
name: somaz-ingress
enabled: true
className: ""
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: clouddns-issuer # your clusterissuer
hosts:
- host: dev1-game.somaz.link
paths:
- path: /
pathType: Prefix
backend:
service:
name: somaz-svc
port: 80
tls:
- secretName: dev1-game-tls
hosts:
- dev1-game.somaz.link
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
rbac:
enabled: true
serviceAccountName: "" # Leave empty to use admin.fullname as default
role:
name: cert-job-manager-game
resources:
- apiGroups: ["cert-manager.io"]
resources: ["certificaterequests"]
verbs: ["get", "list", "watch", "delete"]
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "delete"]
roleBinding:
name: cert-job-manager-binding-game
nodeSelector: {}
tolerations: []
affinity: {}
revisionHistoryLimit: 1
namespace: somaz-dev1
envConfig:
NODE_ENV: dev1
configs:
- name: somaz-dev1-config
namespace: somaz-dev1
datas:
SERVER_PORT: 3000
REDIS_DB_HOST: dev1-redis.somaz.link
REDIS_DB_PORT: 30480
ADMIN_DB_HOST: dev1-db.somaz.link
ADMIN_DB_PORT: 30737
ADMIN_DB_NAME: admin
ADMIN_DB_ID: somaz
ADMIN_DB_PW: somaz94
ADMIN_DB_SYNCHRONIZE: true
persistentVolumes:
- name: somaz-dev1-data-pv
type: data
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
reclaimPolicy: Retain
storageClassName: nfs-client
path: /data/somaz/gamedata/dev1/data
server: nfs-server.somaz.link
persistentVolumeClaims:
- name: somaz-dev1-data-pv-claim
accessModes:
- ReadWriteOnce
storageClassName: nfs-client
storage: 5Gi
type: data
mountPath: /app/data
# AWS
certificate:
enabled: true
secretName: dev1-game-tls
commonName: dev1-game.somaz.link
duration: 2160h0m0s # 90d
renewBefore: 720h0m0s # 30d
dnsNames:
- dev1-game.somaz.link
issuerName: route53-issuer
issuerKind: ClusterIssuer
# # GCP
# certificate:
# enabled: true
# secretName: dev1-game-tls
# commonName: dev1-game.somaz.link
# duration: 2160h0m0s # 90d
# renewBefore: 720h0m0s # 30d
# dnsNames:
# - dev1-game.somaz.link
# issuerName: clouddns-issuer
# issuerKind: ClusterIssuer
certCleanup:
enabled: false
CronJobName: cert-cleanup-cronjob-game
olderThanDays: 100
YesterDays: 1
Create ImagePullSecret
아래와 같이 `helper template` 과 조합하여 `imagepullsecret` 을 쉽게 만들 수 있다.
`templates/_helpers.tpl`
{{- define "imagePullSecret" }}
{{- with .Values.imageCredentials }}
{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"email\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password .email (printf "%s:%s" .username .password | b64enc) | b64enc }}
{{- end }}
{{- end }}
`templates/imagePullSecret.yaml`
{{- if .Values.imageCredentials.enabled -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.imageCredentials.name }}
labels:
{{- include "somaz.labels" . | nindent 4 }}
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "imagePullSecret" . }}
{{- end }}
`values.yaml`
imageCredentials:
enabled: true
registry: quay.io
username: someone
password: sillyness
email: someone@host.com
Reference
https://helm.sh/ko/docs/chart_best_practices/templates/
'Container Orchestration > Kubernetes' 카테고리의 다른 글
Kubernetes Garbage Collection (0) | 2024.08.30 |
---|---|
Kubernetes 생태계 표준화와 Container Interface(CRI, CSI, CNI) (0) | 2024.07.15 |
Kubernetes Pod를 안전하게 종료하는 방법(cordon, uncordon, drain, scale) (0) | 2024.07.09 |
Ingress Nginx란? (0) | 2024.07.04 |
Kubernetes Volumes 및 StorageClass: CSI 드라이버 사용 가이드 (0) | 2024.04.28 |