第23章:Helm應用包管理器


Helm應用包管理器

3.1 為什么需要Helm

K8S上的應用對象,都是由特定的資源描述組成,包括deployment、service等。都保存各自文件中或者集中寫到一個配置文件。然后kubectl apply –f 部署。

yaml-all

如果應用只由一個或幾個這樣的服務組成,上面部署方式足夠了。 而對於一個復雜的應用,會有很多類似上面的資源描述文件,例如微服務架構應用,組成應用的服務可能多達十個,幾十個。如果有更新或回滾應用的需求,可能要修改和維護所涉及的大量資源文件,而這種組織和管理應用的方式就顯得力不從心了。 且由於缺少對發布過的應用版本管理和控制,使Kubernetes上的應用維護和更新等面臨諸多的挑戰,主要面臨以下問題:

(1) 如何將這些服務作為一個整體管理 (2) 這些資源文件如何高效復用 (3) 不支持應用級別的版本管理

3.2 Helm介紹

Helm是一個Kubernetes的包管理工具,就像Linux下的包管理器,如yum/apt等,可以很方便的將之前打包好的yaml文件部署到kubernetes上。Helm有3個重要概念如下: (1) helm # 一個命令行客戶端工具,主要用於Kubernetes應用chart的創建、打包、發布和管理。 (2) Chart # 應用描述,一系列用於描述 k8s 資源相關文件的集合。 (3) Release # 基於Chart的部署實體,一個 chart 被 Helm 運行后將會生成對應的一個 release;將在k8s中創建出真實運行的資源對象。

3.3 Helm v3 變化

Helm目前有兩個大版本:v2和v3,2019年11月,Helm團隊發布 v3 版本,v3版本相比v2版本最主要變化如下。

1 架構變化

最明顯的變化是 Tiller的刪除,並大部分代碼重構。

helm-arch

2 Release名稱可以在不同命名空間重用

3 支持將 Chart 推送至 Docker 鏡像倉庫中

4 使用JSONSchema驗證chart values

5 其他

(1) 為了更好地協調其他包管理者的措施 Helm CLI個別更名

helm delete 更名為 helm uninstall
helm inspect 更名為 helm show
helm fetch   更名為 helm pull

但以上舊的命令當前仍能使用。 (2) 移除了用於本地臨時搭建 Chart Repositoryhelm serve 命令。 (3) 自動創建名稱空間 在不存在的命名空間中創建發行版時,Helm 2創建了命名空間。Helm 3遵循其他Kubernetes對象的行為,如果命名空間不存在則返回錯誤。 (4) 不再需要requirements.yaml, 依賴關系是直接在chart.yaml中定義。

3.4 Helm客戶端

1 部署Helm客戶端

使用helm很簡單,你只需要下載一個二進制客戶端包即可,會通過kubeconfig配置(通常$HOME/.kube/config)來連接Kubernetes。 Helm客戶端下載地址:https://github.com/helm/helm/releases/

# 下載后解壓移動到/usr/bin/目錄即可
# wget https://get.helm.sh/helm-v3.7.1-linux-amd64.tar.gz
# tar -zxf helm-v3.7.1-linux-amd64.tar.gz
# mv linux-amd64/helm /usr/bin/

2 Helm常用命令

命令 描述
completion 命令補全,source <(helm completion bash)
create 創建一個chart並指定名字
dependency 管理chart依賴
get 下載一個release。可用子命令:all、hooks、manifest、notes、values
history 獲取release歷史
install 安裝一個chart
list 列出release
package 將chart目錄打包到chart存檔文件中
pull 從遠程倉庫中下載chart並解壓到本地 # helm pull stable/mysql --untar
repo 添加,列出,移除,更新和索引chart倉庫。可用子命令:add、index、list、remove、update
rollback 從之前版本回滾
search 根據關鍵字搜索chart。可用子命令:hub、repo
show 查看chart詳細信息。可用子命令:all、chart、readme、values
status 顯示已命名版本的狀態
template 本地呈現模板
uninstall 卸載一個release
upgrade 更新一個release
version 查看helm客戶端版本

3 配置Chart倉庫

(1) 常用倉庫 1)官方倉庫網址: https://hub.kubeapps.com/ 2)其它倉庫網址: https://artifacthub.io/

(2) 添加存儲庫並更新

# 添加阿里雲chart存儲倉庫,版本比較老
# helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
# 更新倉庫
# helm repo update

(3) 查看配置的存儲庫

# helm repo list

(4) 查找chart應用

helm search repo <應用名>

(5) 刪除存儲庫

# helm repo remove <倉庫名>

3.5 Helm基本使用

1 Helm管理應用生命周期

(1) 創建Chart應用示例
# helm create
(2) 部署
# helm install
(3) 更新
# helm upgrade
(4) 回滾
# helm rollback
(5) 卸載
# helm uninstall

2 使用chart部署一個應用

(1) 查找chart

# helm search repo mysql
NAME                         CHART VERSIONAPP VERSIONDESCRIPTION                                      
aliyun/mysql                 0.3.5                  Fast, reliable, scalable, and easy to use open-...
aliyun/percona               0.3.0                  free, fully compatible, enhanced, open source d...
aliyun/percona-xtradb-cluster0.0.2       5.7.19     free, fully compatible, enhanced, open source d...
aliyun/gcloud-sqlproxy       0.2.3                  Google Cloud SQL Proxy                           
aliyun/mariadb               2.1.6       10.1.31   Fast, reliable, scalable, and easy to use open-...
# 為什么mariadb也在列表中,因為他和mysql有關。

(2) 查看chart的基本信息

# helm show chart aliyun/mysql

(3) 安裝chart應用

# helm install db aliyun/mysql -n default

(4) 安裝后查看chart幫助信息

# helm status db -n default

3 安裝前自定義chart配置選項

(1) chart 上面部署的mysql並沒有成功,這是因為並不是所有的 chart 都能按照默認配置運行成功,可能會需要一些環境依賴,例如PV。 所以我們需要自定義 chart 配置選項(覆蓋values.yaml),安裝過程中有兩種方法可以傳遞配置數據: --values 或 -f # 指定帶有覆蓋的YAML文件,這可以多次指定,最右邊的文件優先。 --set # 在命令行上指定替代,如果兩者都用,--set優先級高

# 把chart包下載下來查看詳情
# helm pull aliyun/mysql --untar
# tree mysql/
mysql/
├── Chart.yaml
├── README.md
├── templates
│   ├── configmap.yaml
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── NOTES.txt
│   ├── pvc.yaml
│   ├── secrets.yaml
│   └── svc.yaml
└── values.yaml

1 directory, 10 files

# helm show values ./mysql <=> # cat mysql/values.yaml # 查看yaml模板變量
# helm show chart ./mysql/ <=> # cat mysql/Chart.yaml # 查看chart基本信息

# 由於我這里使用的是k8s版本為1.20,Deployment yaml配置文件需要進行修改,否則無法部署
# vim mysql/templates/deployment.yaml

helm-aliyun-mysql

 
           
# cat > config.yaml << EOF
persistence:
  enabled: true
  accessMode: ReadWriteOnce
  size: 8Gi
mysqlUser: "k8s"
mysqlPassword: "123456"
mysqlDatabase: "k8s"
EOF

# kubectl create namespace mysql-db

# 創建MySQL用戶k8s,並授予此用戶訪問新創建的k8s數據庫的權限,並指定資源所在的名稱空間,
# --set使用命令行替代變量,未指定的使用默認值。
# helm install db -f config.yaml -n mysql-db --set persistence.storageClass="managed-nfs-storage" ./mysql/

#  kubectl get pod -n mysql-db
NAME                        READY   STATUS    RESTARTS   AGE
db-mysql-5c695fcdfb-g6jt6   1/1     Running   0          77s

# helm list -n mysql-db
NAME    NAMESPACE    REVISION    UPDATED                                    STATUS      CHART          APP VERSION
db      mysql-db     1           2021-10-22 17:17:32.401870823 +0800 CST    deployed    mysql-0.3.5               

# kubectl get svc -n mysql-db
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
db-mysql   ClusterIP   172.28.104.81   <none>        3306/TCP   2m38s

# yum install mysql -y
# mysql -uk8s -p123456 -h172.28.104.81 k8s
MySQL [k8s]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| k8s                |
+--------------------+
2 rows in set (0.00 sec)

mysql-aliyun-pvc-pv

# 卸載helm應用(pvc,pv,存儲資源被刪除)
# helm uninstall db -n mysql-db

(2) values.yaml參數格式對應set變量格式表

yaml-set

helm install命令可以從多個來源安裝:chart存儲庫、本地chart存檔(helm install mysql-0.3.5.tgz)、chart目錄(helm install path/to/mysql)、完整的URL(helm install https://example.com/charts/mysql-0.3.5.tgz)

4 構建一個Helm Chart

(1) 自動生成目錄

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

3 directories, 10 files

1)charts # 目錄里存放這個chart依賴的所有子chart。 2)Chart.yaml # 用於描述這個Chart的基本信息,包括名字、描述信息以及版本等。 3)Templates # 目錄里面存放所有yaml模板文件。 4)NOTES.txt # 用於介紹Chart幫助信息,helm install 部署后展示給用戶。例如:如何使用這個 Chart、列出缺省的設置等。 5)_helpers.tpl # 放置模板助手的地方,可以在整個 chart 中重復使用。 6)values.yaml # 用於存儲 templates 目錄中模板文件中用到變量的值。

(2) 創建Chart后,接下來就是將其部署

 
           
# 修改service的type為NodePort,方便實驗
# vim mychart/values.yaml
service:
  type: NodePort
  port: 80

# helm install web -n default mychart/

(3) 查看Release

# helm list -n default
NAMENAMESPACEREVISIONUPDATED                               STATUS CHART       APP VERSION
web default 1       2021-10-23 23:11:12.33497844 +0800 CSTdeployedmychart-0.1.01.16.0    

(4) 查看部署的pod

# kubectl get pod,svc -n default
NAME                                         READY   STATUS   RESTARTS   AGE
pod/nfs-client-provisioner-666969576d-k2pgw   1/1     Running   1         31h
pod/web-mychart-5b58c47cd6-nsk4r             1/1     Running   0         57s

NAME                 TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)       AGE
service/kubernetes   ClusterIP   172.28.0.1     <none>       443/TCP       33d
service/web-mychart   NodePort   172.28.48.236   <none>       80:31644/TCP   57s

(5) 打包推送到chart倉庫共享給別人使用

# helm package mychart/
Successfully packaged chart and saved it to: /root/helm_dir/mychart-0.1.0.tgz

5 升級、回滾和刪除

(1) 升級

1)使用Chart升級應用有兩種方法: --values,-f # 指定yaml文件覆蓋values.yaml文件中的值,沒有覆蓋的保持默認 --set # 在命令行上指定覆蓋values.yaml文件中的值,沒有覆蓋的保持默認 注: 如果兩種方法一起使用,--set優先級高 2)發布新版本的chart時,或者當您要更改發布的配置時,可以使用該helm upgrade 命令

 
           
# 第一種方式,將nginx服務升級到1.18版本
# vim values.yaml
image:
  tag: "1.18"
# helm upgrade -f values.yaml web mychart/ -n default

# 第二種方式,將nginx服務升級到1.19版本
# helm upgrade --set image.tag=1.19 web mychart/ -n default

(2) 回滾 如果在發布后沒有達到預期的效果,則可以使用helm rollback回滾到之前的版本。 1)查看歷史版本

# helm history web -n default
REVISIONUPDATED                 STATUS   CHART       APP VERSIONDESCRIPTION    
1       Sat Oct 23 23:28:45 2021supersededmychart-0.1.01.16.0     Install complete
2       Sat Oct 23 23:30:22 2021supersededmychart-0.1.01.16.0     Upgrade complete
3       Sat Oct 23 23:33:15 2021deployed mychart-0.1.01.16.0     Upgrade complete

注:
REVISION 1 表示的是nginx:1.16版本
REVISION 2 表示的是nginx:1.18版本
REVISION 3 表示的是nginx:1.19版本

2)將應用回滾到指定版本

# helm rollback web 2 -n default
Rollback was a success! Happy Helming!

注: 回滾到上一個版本使用如下命令
helm rollback web -n default

(3) 卸載chart應用

# helm uninstall web -n default
release "web" uninstalled

6 Helm工作流程

Helm-Workflow

3.6 Chart模板

1 介紹 Helm最核心的就是模板,即模板化的K8S YAML文件,它本質上就是一個Go的template模板,Helm在Go template模板的基礎上,還會增加 很多東西,如一些自定義的元數據信息、擴展的庫以及一些類似於編程形式的工作流,例如條件語句、管道等等,這些東西都會使得我們的 模板變得更加豐富。 通過模板實現Chart的高效復用,當部署多個應用時,可以將差異化的字段進行模板化,在部署時使用 -f 或者 --set 動態覆蓋默認值,從而適配多個應用。

helm-template

 
           
# cd /root/helm_dir/mychart/
# cat > values.yaml << EOF
replicas: 1
label:
  project: ms
  app: nginx
image: nginx
imageTag: "1.20"
EOF

# rm -rf templates/*
# cat > templates/deployment.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-deployment
spec:
  replicas: {{ .Values.replicas }}
  selector:
    matchLabels:
      project: {{ .Values.label.project }}
      app: {{ .Values.label.app }}
  template:
    metadata:
      labels:
        project: {{ .Values.label.project }}
        app: {{ .Values.label.app }}
    spec:
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
        name: nginx
EOF

2 內置對象

Release對象獲取發布記錄信息。 在上面示例中,模板文件中.Release.Values是Helm內置對象,頂級開頭寫。

(1) Release對象 使用 {{.Release.Name}}將 release 的名稱插入到模板中,下面是一些常用的內置對象。

Release.Name release 名稱
Release.Name release 的名稱
Release.Time release 的時間
Release.Namespace release 的命名空間
Release.Service release 的服務名稱
Release.Revision release 的修訂版本號,從1開始累加

(2) Values對象

1)Values對象是為Chart模板提供值,這個對象的值有3個來源: A、chart 包中的 values.yaml 文件 B、通過 helm install 或者 helm upgrade 的 -f或者 --values參數傳入的自定義的 yaml 文件 C、通過 --set 參數傳入的值 2)chart 的 values.yaml 提供的值可以被用戶提供的 values 文件覆蓋,而該文件同樣可以被 --set提供的參數所覆蓋。

(3) Chart對象

可以通過Chart對象訪問Chart.yaml文件的內容,例如: {{ .Chart.AppVersion }}

3 調試

Helm也提供了--dry-run --debug調試參數,幫助你驗證模板正確性,在執行helm install時候帶上這兩個參數就可以把對應的 values值和渲染的資源清單打印出來,而不會真正的去部署一個release。

比如我們來調試上面創建的 chart 包:

 
           
# helm install --dry-run --debug web ./mychart/ -n default
install.go:178: [debug] Original chart version: ""
install.go:199: [debug] CHART PATH: /root/helm_dir/mychart

NAME: web
LAST DEPLOYED: Sun Oct 24 19:46:42 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
image: nginx
imageTag: "1.20"
label:
  app: nginx
  project: ms
replicas: 1

HOOKS:
MANIFEST:
---
# Source: mychart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      project: ms
      app: nginx
  template:
    metadata:
      labels:
        project: ms
        app: nginx
    spec:
      containers:
      - image: nginx:1.20
        name: nginx

4 函數與管道

前面講的模塊,其實就是將變量值傳給模板引擎進行渲染,模板引擎還支持對拿到數據進行二次處理。 (1) 常用函數

quote      # 將值轉換為字符串,即加雙引號
default      # 設置默認值,如果獲取的值為空則為默認值
indent、nindent# 縮進字符串
toYaml      # 引用一塊YAML內容

其他函數:
upper、title等

(2) quote,將值轉換為字符串,即加雙引號

例如:從 .Values 中讀取的值變成字符串,可以使用quote函數實現。 nodeSelector標簽的值用了true正常使用會報錯,這是因為它是關鍵字,需要加引號才可以。

 
           
# vim values.yaml
nodeSelector:
  gpu: true

# vim templates/deployment.yaml
......
nodeSelector:
  disktype: {{ quote .Values.nodeSelector.gpu }}

(3) default,設置默認值,如果獲取的值為空則為默認值 示例:以防止忘記定義而導致模板文件缺少字段無法創建資源,這時可以為字段定義一個默認值。

# vim templates/deployment.yaml
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}

注:
這里用到了管道符"|",前面的值傳遞后函數驗證是否為空。

(4) indent和nindent函數都是縮進字符串,主要區別在於nindent會在縮進前多添加一個換行符 示例:

 
           
# vim templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: {{ .Release.Name | indent 0 }}
......

(5) toYaml,引用一塊YAML內容

示例:在values.yaml里寫結構化數據,引用內容塊

 
           
# vim values.yaml
resources:
  limits:
    cpu: 100m
    memory: 128Mi
  requests:
    cpu: 100m
    memory: 128Mi

# vim templates/deployment.yaml
......
    spec:
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
        name: nginx
        resources: {{ toYaml .Values.resources | nindent 10 }}

(6) 其他函數

# vim templates/deployment.yaml
......
{{ upper .Values.resources }}# 大寫
{{ title .Values.resources }}# 首字母大寫

5 流程控制

流程控制是為模板提供了一種能力,滿足更復雜的數據邏輯處理,Helm模板語言提供的控制語句有,if/else 條件判斷、range 循環、with 指定變量作用域。

(1) 流程控制之 if/else 1)if/else 塊是用於在模板中有條件的包含文本塊的方法

helm-if-else

條件判斷,根據不同的條件做不同的行為,語法如下:
{{ if <表達式> }}
# 做某事
{{ else if <表達式> }}
# 做某事
{{ else }}
# 默認
{{ end }}

2)示例 部署一個應用,在沒明確啟用ingress時,默認情況下不啟用。

 
           
# vim values.yaml
ingress:
  enabled: false
  annotations:
     kubernetes.io/ingress.class: nginx
     kubernetes.io/tls-acme: "true"
  hosts:
     host: www.lc.com
     path: /
  tls:
    secretName: chart-example-tls
    hosts: www.lc.com

# vim templates/ingress.yaml
{{ if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  labels: {{ include "labels" . | nindent 4 }}
  name: {{ include "fullname" . }}
  annotations: {{ toYaml .Values.ingress.annotations | nindent 4 }}
spec:
  {{- if .Values.ingress.tls }}
  tls:
  - hosts:
      - {{ .Values.ingress.tls.hosts }}
    secretName: {{ .Values.ingress.tls.secretName }} 
  {{- end }}
  rules:
  - host: {{ .Values.ingress.hosts.host }}
    http:
      paths:
      - path: {{ .Values.ingress.hosts.path }}
        pathType: Prefix
        backend:
          service:
            name: {{ include "fullname" . }} 
            port:
              number: {{ .Values.service.port }}
{{ end }}

# 測試
# helm install test --set ingress.enabled=true --dry-run ./mychart/

# 如果值為以下幾種情況則為false
一個布爾類型 false
一個數字 0
一個空的字符串
一個 nil(空或 null)
一個空的集合( map、 slice、 tuple、 dict、 array)
除了上面的這些情況外,其他所有條件都為真。

# 條件表達式也支持操作符
eq 等於
ne 不等於
lt 小於
gt 大於
and 邏輯與
or 邏輯或

3)消除判斷空格

 
           
示例:如果是一個空的集合則不啟用資源配額

# vim values.yaml
resources:
  limits:
    cpu: 100m
    memory: 128Mi
  requests:
    cpu: 100m
    memory: 128Mi

# vim templates/deployment.yaml
......
    spec:
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
        name: nginx
        {{ if .Values.resources }}
        resources: {{ toYaml .Values.resources | nindent 10 }}
        {{ end }}

驗證渲染結果:
# helm install test --dry-run ./mychart/
渲染結果會發現有多余的空行,這是因為模板渲染時會將指令刪除,所以原有的位置就空白了,可以使用橫杠"-"消除空行。
"{{-" 表示刪除左邊的所有空格,直到非空格字符,"-}}" 表示刪除右邊的所有空格,還包括換行符、TAB字符。

示例:
# vim templates/deployment.yaml
......
    spec:
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
        name: nginx
        {{- if .Values.resources }}
        resources: {{ toYaml .Values.resources | nindent 10 }}
        {{- end }}

4)判斷一個空的數組

 
           
# vim values.yaml
resources: {}

# vim templates/deployment.yaml
......
    spec:
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
        name: nginx
        {{- if .Values.resources }}
        resources:
{{ toYaml .Values.resources | indent 10 }}
        {{- end }}

(2) range

helm-range

循環: 一般用於遍歷序列結構的數據,例如序列、鍵值。

 
           
語法:
{{ range <值> }}
# 引用內容
{{ end }}

示例: 遍歷數據
在 Helm 模板語言中,使用 range 關鍵字來進行循環操作,我們在 values.yaml 文件中添加上一個變量列表
# cat values.yaml
env:
  - 1
  - 2
  - 3

# vim templates/deployment.yaml
......
    spec:
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
        name: nginx
        env:
          {{- range $k,$v := .Values.env }}
          - name: {{ $k }}
            value: {{ quote $v }}
          {{- end }}

# 循環打印該列表
# vim templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}
data:
  test: |
  {{- range .Values.env }}
    {{ . }}
  {{- end }}

注:
循環內部我們使用的是一個".",這是因為當前的作用域就在當前循環內,這個"."引用的是當前讀取的元素。

(3) with with: 控制變量作用域 之前我們的 {{ .Release.xxx }}或者 {{ .Values.xxx }},其中的 .就是表示對當前范圍的引用, .Values就是告訴模板在當 前范圍中查找 Values對象的值,而 with語句就可以來控制變量的作用域范圍。

語法:
{{ with <值> }}
# 限制范圍
{{ end }}

with語句可以允許將當前范圍 . 設置為特定的對象,比如使用.Values.nodeSelecotr,我們可以使用 with來將. 范圍指向 .Values.nodeSelecotr

 
           
# vim values.yaml
nodeSelector:
  team: a
  gpu: yes

# vim templates/deployment.yaml
......
    spec:
      {{- $ReleaseName := .Release.Name -}}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        team: {{ .team }}
        gpu: {{ .gpu }}
        test: {{ $ReleaseName }}
      {{- end }}
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
......
注: 
上面增加了一個"{{- with .Values.label }} xxx {{- end }}"的一個塊,這樣的話就可以在當前的塊里面直接引用".team"".gpu"了。"with"是一個循環構造,使用".Values.nodeSelector"中的值,將其轉換為Yaml。
with 塊限制了變量作用域,也就是無法直接引用模板對象,例如".Values"".Release",with 語句塊內不能再使用
".Release.Name"對象,否則報錯,我們可以將該對象賦值給一個變量來解決這個問題,可以在 with 語句上面增加一句
"{{- $ReleaseName := .Release.Name -}}",其中"$ReleaseName"就是后面的對象的一個引用變量,它的形式就
是"$name",賦值操作使用":=",這樣 with 語句塊內部的"$ReleaseName"變量仍然指向的是".Release.Name"。

# 優化一下
# vim templates/deployment.yaml
......
    spec:
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
......
注: toYaml之后的點是循環中".Values.nodeSelector"的當前值

6 變量 變量在實際應用中不多,但有時候結合withrange能更好的處理數據。

獲取列表鍵值

 
           
# vim values.yaml
env:
  NAME: "gateway"
  JAVA_OPTS: "-Xmx1G"
  hello: world

# vim templates/deployment.yaml
......
    spec:
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
        name: nginx
        env:
          {{- range $k,$v := .Values.env }}
          - name: {{ $k }}
            value: {{ quote $v }}
          {{- end }}
注: 上面在 range 循環中使用 "$key""$value" 兩個變量來接收后面列表循環的鍵和值。
# 輸出結果
env:
  - name: JAVA_OPTS
    value: "-Xmx1G"
  - name: NAME
    value: "gateway"


# vim templates/deployment.yaml
......
      containers:
      - image: {{ .Values.image }}:{{ .Values.imageTag }}
        name: nginx
        env:
          - name: NAME
            {{- if eq .Values.env.hello "world" }}
            value: true
            {{- else }}
            value: false
            {{- end }}
# 輸出結果
env:
  - name: NAME
    value: true

7 命名模板 命名模板類似於開發語言中的函數,指一段可以直接被另一段程序或代碼引用的程序或代碼。在編寫chart時,可以將一些重復使用的內容 寫在命名模板文件中供公共使用,這樣可減少重復編寫程序段和簡化代碼結構。命名模塊使用define字段定義,模板中使用template字段 或include字段引入,在templates目錄中默認下划線開頭的文件為公共模板(_helpers.tpl)。

 
           
示例: 將資源名稱生成指令放到公共模板文件中作為所有資源名稱
# vim templates/_helpers.tpl
{{- define "fullname" -}}
{{- .Chart.Name }}-{{ .Release.Name }}
{{- end }}

{{- define "labels" -}}
app: {{ template "fullname" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
release: {{ .Release.Name }}
{{- end }}

# vim templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ template "fullname" . }}
  labels:
    {{- include "labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicas }}
......

# 得到的結果為
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mychart-test
  labels:
    app: mychart-test
    chart: mychart-0.1.0
    release: test
spec:
  replicas: 1
......

template指令是將一個模板包含在另一個模板中的方法,但是template函數不能用於Go模板管道,為了解決該問題,引入了 include 指令。
上面包含一個名為 labels 的模板,然后將值 "." 傳遞給模板,最后將該模板的輸出傳遞給 nindent 函數。

3.7 寫一個通用的Chart

1 創建步驟

(1) 先創建模板示例 helm create demo
(2) 修改Chart.yaml,Values.yaml,參考示例預留變動的字段值
(3) 在templates目錄下准備部署應用所需的yaml文件,並添加指令引用Values.yaml字段
(4) 將重復使用的內容放到命名模板文件中
(5) 使用Chart結合參數部署多個同類服務

2 查看Chart的目錄結構

# tree demo
demo
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── ingress.yaml
│   ├── NOTES.txt
│   └── service.yaml
└── values.yaml

1 directory, 7 files

3 Chart.yaml

# cat demo/Chart.yaml
apiVersion: v2
appVersion: 0.1.0
description: java demo
name: demo
type: application
version: 0.1.0


創建Chart時的默認配置:
# egrep -v "^$|^#" mychart/Chart.yaml
apiVersion: v2
# Chart的api版本

name: mychart
# Chart的名稱

description: A Helm chart for Kubernetes
# Chart的描述信息

type: application
# Chart可以是"應用程序"或"庫"Chart。
# 應用程序Chart是一組模板,可以打包到要部署的版本化歸檔中。
# 庫為Chart開發人員提供了有用的實用程序或函數。
# 它們作為應用程序Chart的依賴項包含在其中,用於將這些實用程序和函數注入渲染管道。
# 庫Chart不定義任何模板,因此無法部署。

version: 0.1.0
# 這是Chart版本。
# 每次更改Chart及其模板(包括應用程序版本)時,此版本號應增加。
# 版本應遵循語義版本控制(https://semver.org/)。

appVersion: "1.16.0"
# 這是正在部署的應用程序的版本號。
# 每次更改應用程序時,此版本號都應遞增。
# 版本不應遵循語義版本控制。
# 它們應該反映應用程序正在使用的版本。
# 建議將其與引號一起使用。

4 values.yaml

 
           
# cat demo/values.yaml
image:
  pullPolicy: IfNotPresent
  repository: lizhenliang/java-demo
  tag: latest
imagePullSecrets: []
ingress:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: 100m
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
  enabled: true
  host: example.lc.com
  tls:
    secretName: example-lc-com-tls
nodeSelector: {}
replicaCount: 3
resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 100m
    memory: 128Mi
service:
  port: 80
  type: ClusterIP
tolerations: []

5 templates

 
           
(1) deployment.yaml
# cat demo/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "demo.fullname" . }}
  labels:
    {{- include "demo.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "demo.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "demo.selectorLabels" . | nindent 8 }}
    spec:
    {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
    {{- end }}
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}

(2) _helpers.tpl
# cat demo/templates/_helpers.tpl
{{- define "demo.fullname" -}}
{{- .Chart.Name -}}-{{ .Release.Name }}
{{- end -}}

{{/*
公用標簽
*/}}
{{- define "demo.labels" -}}
app: {{ template "demo.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
{{- end -}}

{{/*
標簽選擇器
*/}}
{{- define "demo.selectorLabels" -}}
app: {{ template "demo.fullname" . }}
release: "{{ .Release.Name }}"
{{- end -}}

(3) ingress.yaml
# cat demo/templates/ingress.yaml
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: {{ include "demo.fullname" . }} 
  labels:
    {{- include "demo.labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
{{- if .Values.ingress.tls }}
  tls:
    - hosts:
        - {{ .Values.ingress.host }} 
      secretName: {{ .Values.ingress.tls.secretName }}
{{- end }}
  rules:
    - host: {{ .Values.ingress.host }} 
      http:
        paths:
        - path: / 
          backend:
            serviceName: {{ include "demo.fullname" . }} 
            servicePort: {{ .Values.service.port }}
{{- end }}

(4) NOTES.txt
# cat demo/templates/NOTES.txt
訪問地址:
{{- if .Values.ingress.enabled }}
  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .Values.ingress.host }}
{{- end }}
{{- if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "demo.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- end }}

(5) service.yaml
# cat demo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "demo.fullname" . }}
  labels:
    {{- include "demo.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "demo.selectorLabels" . | nindent 4 }}



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM