Helm是一款非常流行的k8s包管理工具,以前就一直想用它,但看到它產生的檔案比k8s要復雜許多,就一直猶豫,不知道它的好處能不能抵消掉它的復雜度,但如果不用,而是用Kubectl來進行調式真的很麻煩,正好最近Helm3正式版出來了,比原來的Helm2簡單了不少,就決定還是試用一下,結果證明確實很復雜,它的好處和壞處大致相當,有了它確實能大大簡化對k8s的調式,但也需要花費比較多的時間來學習,而且產生的組態檔要復雜許多,但是事實是現在沒有什么很方便的幫助調式k8s的工具,在沒有更好的方案之前,我還是建議用它,只是前期需要花些功夫學習和掌握它,
Helm3和Helm2的語法差不太多,只是使用起來更方便,不用安裝Tiller,一個比較明顯的變化是不再需要“requirements.yaml”, 依賴關系是直接在“chart.yaml”中定義,有關Helm3和Helm2的區別,詳情請參見CHANGES SINCE HELM 2,
網上有不少講述Helm的文章,但大部分都是主要講解安裝和舉一個簡單的例子,但Helm使用起來還是比較復雜的,一定要有一個復雜的例子才能把它的功能講清楚,里面有不少設計方面的問題需要思考,我剛開始接觸的時候就覺得頭緒繁多,不知從哪下手,本文就通過一個相對復雜的例子來講解用Helm3來設計組態檔的思路,使上手更容易,
這里不講Helm3的安裝,它比較很容易,也不講解Helm的基本語法,你可以自己去看其他檔案,即使你不懂Helm,應該也能猜出七八成,剩下的就要讀檔案了(Charts),Helm的語法還是比較復雜的,要想搞懂可能要花一兩天時間,
本文假設你對helm有一個大概的了解,想要構建一個復雜的微服務,但有不知如何下手;或者你想了解一下構建Helm的最佳實踐,那就請你繼續讀下去,
Helm檔案結構
chart里一個很重要的概念就是模板(template),它就是Go語言模板,它是里面加入了編程邏輯的k8s檔案,這些模板檔案在使用時都要先進行模板決議,把其中的程式邏輯轉化成對應的編碼,最終生成k8s組態檔,

以上就是Helm自動生成的chart目錄結構,在Helm里每個專案叫一個chart,它由下面幾個組成部分:
- "Chart.yaml":存有這個chart的基本資訊,
- "values.yaml":定義模板中要用到的常量,
- “template”目錄:里面存有全部的模板檔案,其中最重要的是“deployment.yaml”和“service.yaml”,分別是部署和服務檔案. "helpers.tpl"用來定義變數,"ingress.yaml"和"serviceaccount.yaml"分別是對外介面和服務賬戶,這里暫時沒用, “NOTES.txt”是注釋檔案,
- “charts”目錄: 存有這個chart依賴的所有子chart,
Helm的基本元素
Helm有四個基本元素,值,常量,變數和共享常量(這個后面會講)
值(literal)
Helm在k8s的基礎之上增加了模板功能,使k8s的組態檔更加靈活,里面的主要概念就是模板(Template),也就是在k8s的組態檔里增加了常量和變數以及編程邏輯,如果你不用這些新增功能,那么就是普通的YAML檔案(k8s組態檔),里面用到的基本元素就是值,
常量
節點定位(Node Anchor):
如果你想復用重復的值,能把它定義成常量嗎?YAML有一個功能叫節點定位(Node Anchor),類似于定義一個常量,然后參考,但它有一些限制,定義的必須是一個節點,因此不如真正的常量靈活,
例如如下檔案中,用“&”定義了一個常量“&k8sdemoDatabaseService”,然后用“*k8sdemoDatabaseService”參考它,
global:
k8sdemoDatabaseService: &k8sdemoDatabaseService k8sdemo-database-service
mysqlHost: *k8sdemoDatabaseService
這時,“k8sdemoDatabaseService:”是YAML檔案節點的鍵名,“&k8sdemoDatabaseService”是節點定位的名字,相當于常量名,“k8sdemo-database-service”是YAML節點的鍵值,在上述代碼中,k8sdemoDatabaseService和mysqlHost的值都是“k8sdemo-database-service”,
有關節點定位(Node Anchor)的詳細內容,請參見 YAML,
常量:
由于節點定位的局限性,Helm引入了真正的常量,也就是在"values.yaml"里定義的內容,它可以定義是任何東西,不只限于節點,
在"values.yaml"里定義常量:
replicaCount: 1
在部署模板里參考:
replicas: {{ .Values.replicaCount }}
那么什么時候用常量,什么時候用值(Literal)呢?如果一個值在模板中出現多次,就要定義常量,避免重復,例如“accessModes”,既要在存盤卷里出現,又要在存盤卷申請里出現,另外如果值有可能變化(不論是隨部署環境變化,還是隨時間變化),那么就定義成常量,這樣在修改時就只用改"values.yaml",而不必修改模板檔案,例如“replicas”的值(也就是集群的個數)是可能變化的,就要定義成常量,在模板里可以參考常量的,但在"values.yaml"里不行,因為它只是普通YAML檔案,沒有模板決議功能,因此不支持常量,這里就只能用節點定位(來代替常量),
有關Helm常量的詳細內容,請參見 Use placeholders in yaml和Use YAML with variables,
變數
節點定位的功能是有限的,例如你想利用已有的節點定位,對它進行轉換,定義一個新的節點定位,這在"values.yaml"里就不行了,
例如你已有節點定位“name”,你想在這個基礎上定義一個新的節點定位“serviceName”,這個"values.yaml"就不支持了,你必須要用模板,
如下所示,這在"values.yaml"里是不支持的,
name: &name k8sdemo-backend
serviceName:*name-service
這就引出了變數的概念,但它只能在模板里才行, 換句話說,模板既支持常量,也支持變數,但如果把變數的定義邏輯放在Helm每個模板里,就顯得很亂,因此一般的做法是把這些邏輯放在一個單獨的模板檔案里,這個就是前面講到的"_helpers.tpl"檔案,當你需要對常量進行轉換,生成新的常量,你就在定義變數,這部分代碼就放在"_helpers.tpl"里,
下面就是"_helpers.tpl"中定義"k8sdemo.name"的代碼,
{{- define "k8sdemo.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
在以上這些元素中,常量(也就是在"values.yaml"中定義的)是最靈活的,能用它時盡量用它,而且因為它是定義在普通YAML檔案中("values.yaml"),應用程式可以直接訪問它,這樣可以實作應用程式和k8s之間的資料共享,但如果你需要對常量進行編程轉換,那就沒辦法了,只能定義變數,把它放在"_helpers.tpl"中,
ConfigMap和Secret
在k8s中ConfigMap和Secret是用來存盤共享配置引數和保密引數的,但在Helm中,由于有了上面講的Helm基本元素,它們完全可以代替ConfigMap的功能,因此ConfigMap就不需要了,但Secret還是需要的,因為要存盤加密資訊,下面會講解,
有關ConfigMap的設計局限性,請參見把應用程式遷移到k8s需要修改什么?
Chart設計
現在我們就用一個具體的例子來展示Helm的chart設計,這個例子是一個微服務應用程式,它共有三層: 前端,后端和資料庫,只有這樣才能讓Helm的一些設計問題付出水面,如果只有一層的話,就太簡單了,沒有參考價值,
在k8s中,每一層就是一個單獨的服務,它里面有各種組態檔,Helm的優勢是把這些不同的服務組成一個Chart來共同管理和調式,方便了許多,

上面就是最終的chart目錄結構圖,“chart”是總目錄,里面有三個子目錄“k8sdemo”,“k8sdemo-backend”,“k8sdemo-database”, 每一個對應一個服務,每個服務都是一個獨立的chart,能單獨調式部署,chart之間也可以有依賴關系,其中“k8sdemo”是父chart,同時也是前端服務,它的“charts”目錄里有它依賴的另外兩個服務,“k8sdemo-backend”是后端服務,“k8sdemo-database”是資料庫服務,
處理Chart的依賴關系有兩種方式:
- 嵌入式:就是直接把依賴的chart放在“charts”子目錄里,這樣子chart是父chart的一部分,它是一種緊耦合的關系,好處是比較簡單,但不夠靈活,
- 依賴匯入式:就是各個chart是并列關系,各自單獨除錯部署,互相獨立,需要合并時再把子chart匯入父chart里,它是一種松耦合的關系,好處是比較靈活,但設計更復雜, 在這種結構下,各個chart可以單獨作業也可以聯合作業,不過你需要更好的設計,
這里采用的是依賴匯入式方式,主要原因是我原來認為嵌入式需要一起除錯,復雜度太高,如果你覺得這不是問題,這也是個不錯的辦法,用依賴匯入式方式,可以單獨除錯各個chart,簡單了很多,后來發現其實采用嵌入式也可以單獨除錯子chart,只是父chart不能單獨除錯而已,
除錯順序:
當你采用依賴匯入式方式時,除錯順序關系不大,因為各個chart是各自獨立的,可以單獨除錯,舉個例子,雖然“k8sdemo-backend”需要“k8sdemo-database”才能正常運行,但當沒有資料庫服務時,你的程式也可以運行,只不過輸出的是錯誤資訊,但這并不影響你除錯chart,
我先除錯“k8sdemo”,它雖然依賴另外兩個chart,但沒有它們也能單獨作業,然后再除錯“k8sdemo-backend”和“k8sdemo-database”,最后再把它們匯入到“k8sdemo”中去再進行聯調,
調式“k8sdemo”
它的除錯是最容易的,由于它里面沒有真正的前端代碼,只要把Nginx除錯成功了就可以了,只要在生成的檔案基礎上做些修改就行了,
鍵入如下命令創建chart,其中“k8sdemo”是chart的名字,這個名字很重要,服務的名字和label都是由它產生的,
helm create k8sdemo
這之后,系統會自動創建前面講到的chart目錄結構,讓后就是對已經生成的檔案進行修改,
修改"values.yaml":
以下是"values.yaml"主要修改的地方
image:
repository: nginx:1.17.6
pullPolicy: Never
imagePullSecrets: []
nameOverride: "k8sdemo"
fullnameOverride: "k8sdemo"
service:
type: NodePort
port: 80
nodePort: 31080
另外,由于"ingress.yaml"和"serviceaccount.yaml"暫時沒用,就把它們都設成了“false”
ingress:
enabled: false
serviceAccount:
# Specifies whether a service account should be created
create: false
修改"service.yaml":
apiVersion: v1
kind: Service
metadata:
name: {{ include "k8sdemo.fullname" . }}
labels:
{{- include "k8sdemo.labels" . | nindent 4 }}
spec:
type: {{.Values.service.type}}
ports:
- port: {{.Values.service.port}}
nodePort: {{.Values.service.nodePort}}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "k8sdemo.selectorLabels" . | nindent 4 }}
修改"deployment.yaml":
,,,
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: {{ .Values.image.repository }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
,,,
以上都是簡單的修改,不涉及到設計問題,由于篇幅的關系,這里沒有列出全部原始碼,如果有興趣請在本文末尾找到原始碼地址,
共享常量
在進行下面的除錯之前,先要講一個重要概念, 前面介紹Helm的基本元素時講的都是在一個chart里共享值,如果要在不同chart之間共享值(例如k8s服務名,資料庫用戶名和埠),那么這些還不夠,你需要共享常量. 通常情況下子chart和父chart之間的常量是不能共享的,如果需要共享,需要有一種特殊的方法來定義常量,這就是共享常量,它必須是定義在父chart中,
共享常量
例如,你在“k8sdemo”的“values.yaml”加入下面代碼,注意節點的名字必須是子chart名(例如“k8sdemo-backend”)
k8sdemo-backend:
replicaCount: 2
k8sdemo-database:
replicaCount: 2
在“k8sdemo”的模板里就可以通過“{{ .Values.k8sdemo-backend.replicaCount }}” 來訪問,當Helm發現節點名是子chart名時,它會自動拷貝這個常量到子chart的“values.yaml”中,因此,在“k8sdemo-backend”中,你也可以通過“{{ .Values.replicaCount }}” 來訪問這個常量,注意這里并沒有包含子chart名(“k8sdemo-backend”),而是只有常量名,因為子chart名只是一個標識,而不是常量名的一部分,
全域常量
共享常量只能把常量共享給一個字chart,如果你需要多個子chart之間共享,就需要創建全域常量,它用“global”來標識,下面是示例,
在“k8sdemo-backend”的"values.yaml"中定義:
global:
k8sdemoDatabaseService: &k8sdemoDatabaseService k8sdemo-database-service
mysqlUserName: dbuser
mysqlUserPassword: dbuser
mysqlPort: 3306
mysqlHost: *k8sdemoDatabaseService
mysqlDatabase: service_config
在“k8sdemo-backend”的“deployment.yaml”中參考,
env:
- name: MYSQL_USER_NAME
value: {{ .Values.global.mysqlUserName }}
- name: MYSQL_USER_PASSWORD
value: {{ .Values.global.mysqlUserPassword }}
- name: MYSQL_HOST
value: {{ .Values.global.mysqlHost }}
- name: MYSQL_PORT
value: "{{ .Values.global.mysqlPort }}"
- name: MYSQL_DATABASE
value: {{ .Values.global.mysqlDatabase }}
在“k8sdemo-database”的"values.yaml"中定義:
global:
k8sdemoDatabaseService: k8sdemo-database-service
mysqlUserName: dbuser
mysqlUserPassword: dbuser
mysqlRootPassword: root
mysqlDatabase: service_config
在“k8sdemo-database”的“deployment.yaml”中參考,
env:
- name: MYSQL_ROOT_PASSWORD
value: {{ .Values.global.mysqlRootPassword }}
- name: MYSQL_USER_NAME
value: {{ .Values.global.mysqlUserName }}
- name: MYSQL_USER_PASSWORD
value: {{ .Values.global.mysqlUserPassword }}
- name: MYSQL_DATABASE
value: {{ .Values.global.mysqlDatabase }}
當把“k8sdemo-backend”和“k8sdemo-database”匯入"k8sdemo"后進行聯調時, 就要把上面提到的全域常量寫入"k8sdemo"的"values.yaml"檔案中,這樣就能讓各個子chart共享這些常量,如下所示:
global:
k8sdemoBackendService: k8sdemo-backend-service
k8sdemoDatabaseService: &k8sdemoDatabaseService k8sdemo-database-service
mysqlUserName: dbuser
mysqlUserPassword: dbuser
mysqlRootPassword: root
mysqlPort: 3306
mysqlHost: *k8sdemoDatabaseService
mysqlDatabase: service_config
如果父chart和子chart有重復的全域常量,這時父chart("k8sdemo")的全域常量值就會覆寫子chart的全域常量,
它的使用原則就是如果只是子chart獨有的常量就在子chart的"values.yaml"中定義,如果是共享的常量就在父chart中定義,但如果采用的是依賴匯入方式,由于子chart也要單獨除錯,這時你在子chart里也要定義這些全域常量,這樣在進行chart總除錯時,就會使用父chart的中的值,
詳情請參見 Subcharts and Global Values,
除錯“k8sdemo-backend”
“k8sdemo-backend”的chart需要取(與“k8ssdemo”)不同的名字,
創建:
helm create k8sdemo-backend

上面就是“k8sdemo-backend”的目錄圖,由于它需要建持久卷,因此這里增加了兩個檔案“persistentvolume.yaml”和“persistentvolumeclaim.yaml” ( 不是自動生成的),
值得一提的是k8s物件的命名,一般情況下,如果不需要對其進行參考,用chart的全名就行了,例如部署的名稱,如下所示,
name: {{ include "k8sdemo.fullname" . }}
如果是服務名(Service Name),它需要在應用程式和k8s之間共享,也需要在父chart和子chart之間共享,這時最好單獨定義一個全域共享常量,
在“values.yaml”中定義:
global:
k8sdemoBackendService: k8sdemo-backend-service
在“service.yaml”中參考:
name: {{.Values.global.k8sdemoBackendService}}
除錯“k8sdemo-database”
它的除錯方式與“k8sdemo-backend”大同小異,就不詳細講解了,
聯合除錯:
上面各個chart都單獨除錯成功之后,就要把它們合在一起進行聯合除錯,
在“k8sdemo”(父chart)中加入依賴關系(Chart.yaml),
dependencies:
- name: k8sdemo-backend
repository: file://../k8sdemo-backend
version: 0.1.0
- name: k8sdemo-database
repository: file://../k8sdemo-database
version: 0.1.0
這里為了簡單起見,沒有用到chart庫(Chart Repository),使用了本地目錄,這里的“file://”是針對chart的根的相對路徑,“file://..”就是“k8sdemo”的上級目錄,
詳情請參見How to refer to a helm chart in the same repository,
修改全域常量("values.yaml"):
global:
k8sdemoBackendService: k8sdemo-backend-service
k8sdemoDatabaseService: &k8sdemoDatabaseService k8sdemo-database-service
mysqlUserName: dbuser
mysqlUserPassword: dbuser
mysqlRootPassword: root
mysqlPort: 3306
mysqlHost: *k8sdemoDatabaseService
mysqlDatabase: service_config
只有需要在chart之間共享的常量才需要在父chart里的"values.yaml"定義,其余的在各自子chart里的"values.yaml"定義就可以了,
鍵入如下命令“helm dependency update k8sdemo”,更新依賴關系
~ # vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ helm dependency update k8sdemo
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ?Happy Helming!?
Saving 2 charts
Deleting outdated charts
完成之后,生成的圖如下所示,這時在“charts”目錄下就匯入了新的依賴關系“k8sdemo-backend”和“k8sdemo-database”的chart,

有一點需要注意的是,單獨除錯和聯合除錯時,生成的k8s組態檔大部分都是一樣的,但有一個地方不同
下面是聯合除錯時“k8sdemo-database”的部署檔案,最后一行“app.kubernetes.io/instance: ”的值是“k8sdemo”,
# Source: k8sdemo/charts/k8sdemo-database/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8sdemo-database
labels:
helm.sh/chart: k8sdemo-database-0.1.0
app.kubernetes.io/name: k8sdemo-database
app.kubernetes.io/instance: k8sdemo
,,,
下面是單獨除錯時“k8sdemo-database”的部署檔案,最后一行“app.kubernetes.io/instance: ”的值是“”k8sdemo-database”,
# Source: k8sdemo/charts/k8sdemo-database/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8sdemo-database
labels:
helm.sh/chart: k8sdemo-database-0.1.0
app.kubernetes.io/name: k8sdemo-database
app.kubernetes.io/instance: k8sdemo-database
,,,
因為“instance”的名字是“{{ .Release.Name }}”,而單獨除錯和聯合除錯時給的“release”名字不同,而其他的值都是由組態檔決定的,因此不會有意外,
安裝k8sdemo:
vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ helm upgrade k8sdemo ./k8sdemo
Release "k8sdemo" has been upgraded. Happy Helming!
NAME: k8sdemo
LAST DEPLOYED: Fri Nov 29 01:28:55 2019
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services k8sdemo)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
獲取Pod名稱:
vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ kubectl get pod
NAME READY STATUS RESTARTS AGE
k8sdemo-74cb7b997c-pgcj4 1/1 Running 0 33s
k8sdemo-backend-5cd9d79856-dqlmz 1/1 Running 0 33s
k8sdemo-database-85855485c6-jtksb 1/1 Running 0 33s
k8sdemo-jenkins-deployment-675dd574cb-r57sb 1/1 Running 3 23d
運行程式進行測設:
vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ kubectl exec -ti k8sdemo-backend-5cd9d79856-dqlmz -- /bin/sh
~ # ./main.exe
time="2019-11-27T07:03:03Z" level=debug msg="connect to database "
time="2019-11-27T07:03:03Z" level=debug msg="dataSourceName:dbuser:dbuser@tcp(k8sdemo-database-service:3306)/service_config?charset=utf8"
time="2019-11-27T07:03:03Z" level=debug msg="FindAll()"
time="2019-11-27T07:03:03Z" level=debug msg="created=2019-10-21"
time="2019-11-27T07:03:03Z" level=debug msg="find user:{1 Tony IT 2019-10-21}"
time="2019-11-27T07:03:03Z" level=debug msg="find user list:[{1 Tony IT 2019-10-21}]"
time="2019-11-27T07:03:03Z" level=debug msg="user lst:[{1 Tony IT 2019-10-21}]"
~ #
其他問題:
由于篇幅有限,本文不可能把所有的問題都講清楚,還有兩個比較重要的問題,這里簡單的提一下,
1.Secret:
本文用的都是明碼,如果需要加密的話有兩種方式,一種是 helm-secrets,另一種是Vault,請閱讀相關檔案,
2.為不同環境設定不同的常量:
本文只創建了針對一種環境的檔案 ,如果你需要針對不同環境(例如DEV,QA,PROD)配置不同的引數的話,你可以在“k8sdemo”的chart里給不同的環境創建不同的"values.yaml",例如“values-dev.yaml”給DEV環境,但在子chart里,就不能這樣做,因為系統要求"values.yaml",這時,你可以在父chart的“values-dev.yaml”里為不同的子chart創建常量,這樣這些常量就能覆寫子chart里定義的常量,
在“values-dev.yaml”加入下面代碼,
k8sdemo-backend:
replicaCount: 2
k8sdemo-database:
replicaCount: 2
鍵入如下命令試運行:
vagrant@ubuntu-xenial:~$ cd /home/vagrant/jfeng45/k8sdemo/script/kubernetes/chart
vagrant@ubuntu-xenial:~/jfeng45/k8sdemo/script/kubernetes/chart$ helm install --dry-run --values ./k8sdemo/values-dev.yaml --debug k8sdemo ./k8sdemo
查看結果,子chart中的相應引數已被覆寫,
詳情請參閱How to set environment related values.yaml in Helm subcharts?
常見錯誤:
在除錯程序中還是遇到了不少問題,但大多數都是與語法有關的問題,因為Helm和k8s都用的是YAML檔案,而它對檔案格式有著嚴格的要求,如果不滿足要求就會報錯,幸好它報錯時包含了錯誤代碼行號,這樣查找起來比較容易,
- Pod的狀態是CrashLoopBackOff
它的癥狀是在用“helm install --dry-run --debug”除錯時沒有問題,但正式運行時出了問題,用下面命令檢查,Pod的狀態是“CrashLoopBackOff”,
vagrant@ubuntu-xenial:~$ kubectl get pod
NAME READY STATUS RESTARTS AGE
k8sdemo-74cb7b997c-gn5v2 1/1 Running 1 47h
k8sdemo-backend-6cdbb96964-tb2xd 0/1 CrashLoopBackOff 129 9h
k8sdemo-database-deployment-578fc88c88-mm6x8 1/1 Running 12 37d
k8sdemo-jenkins-deployment-675dd574cb-r57sb 1/1 Running 3 19d
這個問題我以前除錯k8s時也碰到過,主要是與Docker鏡像有關,但這次明明鏡像是 好的,試了很多組合,最后終于發現是自動生成的代碼出了問題,
在“deployment.yaml”里有下面代碼,這是Helm自動生成用來測驗部署的,
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
把它去掉之后就沒有問題了,而且它只在特定的chart(“k8sedemo-backend”)里會出錯,在“k8sdemo”里就沒有問題,我現在也不是特別清楚問題在哪,只是把它暫時洗掉掉了,
- 持久卷未能系結到持久卷申請
它的癥狀是宿主機的持久卷未能系結到持久卷申請,導致持久卷申請又另外創建了一個持久卷,你用“kubectl get pv”就能看到新創建的持久卷,但實際上它是不必要的,只要把持久卷申請系結到已有的PV上就行了,這個錯誤并不是每次都發生,而是隨機的,大部分時間系結正確,少數時候系結錯誤,我開始想是不是因為執行k8s檔案的順序問題,但k8s檔案是按照檔案類別(kind)來執行的,按理來說順序應該是正確的,再有一個可能就是時間延遲,因為創建持久卷需要時間,而如果持久卷申請沒有檢測到這個持久卷,那么它就會另外創建一個,如果真是這樣的話,就要在創建時設定一個延遲,但它暫時來講對我影響不大,因此就偷了一下懶,以后有時間再來除錯,
原始碼庫
完整原始碼的github鏈接:
k8sdemo
索引:
- CHANGES SINCE HELM 2
- Charts
- YAML
- Use placeholders in yaml
- Use YAML with variables
- 把應用程式遷移到k8s需要修改什么?
- Subcharts and Global Values
- How to refer to a helm chart in the same repository
- helm-secrets
- Vault
- How to set environment related values.yaml in Helm subcharts?
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/35264.html
標籤:架構設計
