Setting:
1 2 3 4 5 6 7 | #https://helm.sh/docs/intro/install/ curl -k -O https://get.helm.sh/helm-canary-linux-amd64.tar.gz tar -xvzf helm-canary-linux-amd64.tar.gz cd linux-amd64/ mv helm /usr/bin/ chmod 755 /usr/bin/helm |
#Bash Complete for helm
1 2 3 4 | yum install bash-completion -y helm completion bash > /etc/bash_completion.d/helm Thoát session ssh và vào lại hoặc |
P1: Getting to know Helm Chart
1 2 3 4 5 6 7 8 | # Add Repo helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add stable https://charts.helm.sh/stable --force-update (Note: khi add repo, helm sẽ tạo file config tại ~/.config/helm/repositories.yaml) helm repo list #(liệt kê repo) helm repo update #(cập nhập repo) helm search repo nginx #(search nginx từ các repo đã add) |
1.1 Download helm chart from ArtifactHub
https://artifacthub.io/ contains a lot of helm shared from the community.
1 2 3 | helm pull bitnami/nginx helm pull bitnami/nginx --untar |
1.2 Run helm chart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - Chạy helm trực tiếp từ repo internet # helm install first-chart1 bitnami/nginx -n tuanda --create-namespace # helm ls -A - Chạy helm từ folder đã pull về # helm pull bitnami/nginx --untar # cd nginx # helm template first-chart2 . --namespace=tuanda #(Kiểm tra helm) # helm install first-chart2 . --namespace=tuanda --create-namespace #(install nginx bitnami) # helm ls -A - Xóa helm chart helm status first-chart2 -n tuanda helm uninstall first-chart2 -n tuanda |
1.3 Test Chart
We have 3 ways to check if the helm config is correct:
1 2 3 4 5 | cd nginx helm template . helm lint . helm install nginx . --dry-run --debug |
1.4 Show chart information on ArtifactHub
1 2 3 | helm show chart bitnami/nginx helm show values bitnami/nginx |
1.5 List which charts are running
1 2 3 | helm ls -n tuanda #(-n là namespace) helm ls -A |
P2: Create your own Helm Chart
2.1 Create a self-chart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # helm create nginx-test2 > Cấu trúc thư mục helm như sau: ├── charts ├── Chart.yaml ├── templates (chứa toàn bộ thông tin yaml để deploy k8s) │ ├── deployment.yaml (Chứa deployment k8s) │ ├── _helpers.tpl (chứa teamplate / include) │ ├── hpa.yaml │ ├── ingress.yaml │ ├── NOTES.txt │ ├── serviceaccount.yaml │ ├── service.yaml │ └── tests │ └── test-connection.yaml └── values.yaml (chứ tham số để thay vào file yaml trong thư mục template) |
2.2 Upgrade Chart
If the yaml Chart has an update (eg add a variable in the configmap, change the image deployment), we run the following:
1 2 3 4 5 6 7 | helm template nginx-test2 . --namespace=tuanda helm install nginx-test2 . -n tuanda #Ta tăng số pod lên 5 và thử chạy upgrade (vim values.yaml và sửa replicaCount: 5) helm upgrade nginx-test2 . -n tuanda |
2.3 Rollback Chart
1 2 3 4 5 6 7 8 | $ helm history nginx-test2 -n tuanda REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION 1 Sat Oct 15 10:57:24 2022 superseded nginx-test2-0.1.0 1.16.0 Install complete 2 Sat Oct 15 10:59:37 2022 deployed nginx-test2-0.1.0 1.16.0 Upgrade complete $ helm rollback nginx-test2 -n tuanda (về bản trước đó) $ helm rollback nginx-test2 1 -n tuanda (về bản chỉ định) |
P3: .Values / .Chart
To prepare for the tests from part 3, 4… onwards, we delete the following folders
1 2 3 4 5 6 7 8 9 | helm create nginx-test3 cd nginx-test3 rm -rf templates/* cat /dev/null > values.yaml # tạo 2 file MẪU kubectl create configmap nginx-test3-cfg --from-literal=PORT=80 --dry-run=client -o yaml > templates/configmap.yaml kubectl create deployment nginx-test3-dpl --image=nginx:alpine --replicas=2 --dry-run=client -o yaml > templates/deployment.yaml |
Example1: Load parameter .Values from values.yaml
B1: Prepare values.yaml
1 2 | echo 'replicaCount: 5' > values.yaml |
Step 2: Edit deployment.yaml
1 2 3 4 5 6 | vi templates/deployment.yaml sửa replicas: 2 thành: replicas: {{ .Values.replicaCount }} |
B3: Result
Replicas were overwritten from 2 to 5 when running helm template (or install/upgrade)
Example2: Load parameter .Chart from Chart.yaml
B1: values.yaml
1 2 3 4 | replicaCount: 2 image: repository: nginx:alpine |
Step 2: Edit deployment.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: {{ .Chart.Name }}-dpl name: {{ .Chart.Name }}-dpl spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Chart.Name }}-dpl strategy: {} template: metadata: creationTimestamp: null labels: app: {{ .Chart.Name }}-dpl spec: containers: - image: {{ .Values.image.repository }} name: {{ .Chart.Name }} resources: {} |
B3: Result
In addition, we also have some Values, chart build-ins available or used:
1 2 3 4 5 6 | Release.Name Chart.Name Chart.ApiVersion ... URL: https://helm.sh/docs/chart_template_guide/builtin_objects/ |
P4: Function and Pipeline
The helm functions can be found here:https://helm.sh/docs/chart_template_guide/function_list/#string-functions
VD1: Function
B1: Edit values.yaml and Chart.yaml files
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # vim values.yaml replicaCount: 2 image: repository: nginx:alpine ----------------- #vim Chart.yaml apiVersion: v2 name: nginx-test3 description: A Helm chart for Kubernetes type: application version: 0.1.0 appVersion: "1.16.0" |
Step 2: Edit deployment.yaml. Apply function: upper, title, replace, camelcase…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: {{ upper .Chart.Name }}-dpl name: {{ title .Chart.Name }}-dpl spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ replace "nginx" "test" .Chart.Name }}-dpl strategy: {} template: metadata: creationTimestamp: null labels: app: {{ camelcase .Chart.Name }}-dpl spec: containers: - image: {{ .Values.image.repository }} name: {{ .Chart.Name }} resources: {} |
B3: Result
VD2: Pipeline
Pipeline has the same result as function, we can see the example below about upper, title, replace, camelcase…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | apiVersion: apps/v1 kind: Deployment metadata: creationTimestamp: null labels: app: {{ .Chart.Name | upper }}-dpl name: {{ .Chart.Name | title }}-dpl spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Chart.Name | replace "nginx" "test" }}-dpl strategy: {} template: metadata: creationTimestamp: null labels: app: {{ .Chart.Name | camelcase }}-dpl spec: containers: - image: {{ .Values.image.repository }} name: {{ .Chart.Name }} resources: {} |
Result:
Part 5: IF
Function: (1) compare, (2) If exist will print out
Example1: Check existence by if
B1: File values.yaml
1 2 | replicaCount: 5 |
Step 2: Edit deployment.yaml
1 2 3 4 5 | spec: {{- if .Values.replicaCount }} replicas: {{ .Values.replicaCount }} {{- end }} |
B3: Result
Example2: Comparative examples of IF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | {{- if and (eq $.Values.service.type "NodePort") .Values.nodePort }} > nếu service.type là NodePort -VÀ- nodePort=8080 tồn tại thì thực hiện ... {{- if eq (include "paperless.trash.enabled" .) "true" }} > nếu template paperless.trash.enabled được khai báo thì thực hiện ... {{- if or .Values.serverBlock .Values.existingServerBlockConfigmap }} > nếu tồn tại 1 trong 2 value thì thực hiện ... {{- if or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort") }} > nếu svc khai báo là "LoadBalancer hoặc NodePort" thì thực hiện ... {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.http)) }} nodePort: {{ .Values.service.nodePorts.http }} {{- end }} |
P6: With
Function:
- Used to shorten Chart.
- Check exists, if yes, insert., if not, delete (like IF).
- Used to load a list of strings into Chart.
Example1: Shorten Chart
B1: File values.yaml
1 2 3 4 5 6 7 8 | app: mobile: account: taikhoan password: matkhau db: max: 15 min: 5 |
B2: File configmap.yaml when not edited
1 2 3 4 5 6 7 8 9 10 | apiVersion: v1 kind: ConfigMap metadata: name: test data: account: {{ .Values.app.mobile.acc }} password: {{ .Values.mobile.ui.pwd }} max: {{ .Values.app.db.max }} min: {{ .Values.app.db.min }} |
B3: Edit configmap.yaml to shorten “.Values.app.” put in with
1 2 3 4 5 6 7 8 9 10 11 | apiVersion: v1 kind: ConfigMap metadata: name: test data: {{- with .Values.app. }} account: {{ .mobile.account }} password: {{ .mobile.password }} max: {{ .db.max }} min: {{ .db.min }} |
B4: Result
Example2: check if exists, insert., if not, delete (same as IF)
B1: File values.yaml
1 2 3 4 | pod: labels: app: test |
Step 2: Edit deployment.yaml
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 | apiVersion: apps/v1 kind: Deployment metadata: {{- with .Values.pod.labels }} labels: {{ toYaml . }} {{- end }} name: test spec: replicas: 3 selector: matchLabels: app: test strategy: {} template: metadata: {{- with .Values.pod.labels }} labels: {{ toYaml . }} {{- end }} spec: containers: - image: nginx name: nginx |
B3: Result
P7: Range (for i)
Range is almost like with for loading values, but used for array values. You can see the following example
Example1: Range is used to fill array list
B1: File values.yaml
1 2 3 4 5 6 | configMapReload: #extraArgs: [] extraArgs: - --webhook-method HEAD - --webhook-retries 5 |
Step 2: Edit deployment.yaml
1 2 3 4 5 6 | args: - --webhook-url=http://127.0.0.1:{{ .Values.ports.http.port }}/-/reload {{- range $i, $val := .Values.configMapReload.extraArgs }} - {{ $val }} {{- end }} |
B3: Result
1 2 3 4 5 | args: - --webhook-url=http://127.0.0.1:9090/-/reload - --webhook-method HEAD - --webhook-retries 5 |
Example2: Range with multi values
B1: File values.yaml
1 2 3 4 5 6 7 | env: # -- Timezone for the container. - name: TZ value: UTC - name: VN value: GMT |
Step 2: Edit deployment.yaml
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 | apiVersion: apps/v1 kind: Deployment metadata: labels: app: test name: test spec: replicas: 3 selector: matchLabels: app: test strategy: {} template: metadata: labels: app: test spec: containers: - image: nginx name: nginx env: {{- range $i, $val := .Values.env }} - name: {{ $val.name | quote }} value: {{ $val.value | quote }} {{- end }} |
B3: Result
Example3: Range without $val
B1: File values.yaml
1 2 3 4 5 6 7 | configMapReload: extraConfigMapMounts: - name: alerts configMap: prometheus-alerts mountPath: /etc/alerts subPath: 'test' |
Step 2: Edit deployment.yaml
1 2 3 4 5 6 | {{- range .Values.configMapReload.extraConfigMapMounts }} - name: {{ .name }} configMap: name: {{ .configMap }} {{- end }} |
B3: Result
1 2 3 4 | - name: alerts configMap: name: prometheus-alerts |
P8: Include/Template
1 2 | helm create self-chart |
B1: File _helper.tpl
1 2 3 4 5 6 7 8 9 | {{- define "self-chart.labels" -}} helm.sh/chart: {{ include "self-chart.chart" . }} {{ include "self-chart.selectorLabels" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} |
B2: In deployment.yaml call include
1 2 3 4 5 6 7 8 | apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "self-chart.fullname" . }} labels: {{- include "self-chart.labels" . | nindent 4 }} spec: |
B3: Result
1 2 3 4 5 6 7 8 9 10 11 12 | apiVersion: apps/v1 kind: Deployment metadata: name: release-name-nginx-test3 labels: helm.sh/chart: nginx-test3-0.1.0 app.kubernetes.io/name: nginx-test3 app.kubernetes.io/instance: release-name app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: |
P9: Print function
B1: File values.yaml
1 2 3 | configProperties: codeString: dynamic |
Step 2: Edit configmap.yaml
1 2 3 4 5 | apiVersion: v1 kind: ConfigMap data: TEST: {{ printf "static-%s" (.Values.configProperties.codeString) -}} |
B3: Result
P10: Default
B1: File values.yaml
1 2 | imageName: tomcat |
Step 2: Edit deployment.yaml
1 2 3 4 5 6 | spec: containers: - image: {{- default "nginx" .Values.imageName }} name: {{- default "nginx" .Values.imageName }} resources: {} |
B3: Result
P11: Push Helm Chart to ArtifactHub or Local registry
(updating…)
The article is within the knowledge of the writer, maybe you have a better idea, please guide. Thanks!