chart
Helm使用一種稱爲chart的打包格式。圖表是描述一組相關Kubernetes資源的文件集合。單個chart可以用於部署簡單的東西,如memcached pod,也可以用於部署複雜的東西,如包含HTTP服務器、數據庫、緩存等的完整web應用程序堆棧。chart是以文件的形式創建的,放在特定的目錄樹中,然後可以將它們打包到版本化的歸檔中進行部署。本文檔解釋了chart格式,並提供了使用Helm構建chart的基本指導。
chart 結構:chart被組織爲目錄中的文件集合。目錄名稱是chart的名稱(沒有版本信息)。因此描述WordPress的chart將存儲在wordpress/
目錄中。在這個目錄中,Helm將期望一個與此匹配的結構:
wordpress/
Chart.yaml # Yaml文件,用於描述Chart的基本信息,包括名稱版本等
LICENSE # [可選] 包含圖表許可證的純文本文件
README.md # [可選] 一個人類可讀的自述文件當前Chart的介紹
values.yaml # Chart的默認配置文件
requirements.yaml # [可選] 用於存放當前Chart依賴的其它Chart的說明文件
charts/ # [可選]: 該目錄中放置當前Chart依賴的其它Chart
templates/ # [可選]: 部署文件模版目錄,模版使用的值來自values.yaml和由Tiller提供的值
templates/NOTES.txt # [可選]: 包含簡短用法說明的純文本文件
Helm保留使用 charts/
和 templates/
目錄和列表中文件名稱。其他文件將保持原樣。chart需要一個Chart.yaml
。它包含以下字段:
apiVersion: API 版本, 通常 "v1" (必須)
name: chart名字(必須)
version: Chart的版本號,版本號必須符合 SemVer 2:http://semver.org/ (必須)
description: 簡單對chart的描述 (optional)
keywords:
- 工程的關鍵字列表 (optional)
sources:
- 當前Chart的下載地址列表 (optional)
maintainers: # (optional)
- name: The maintainer's name (required for each maintainer)
email: The maintainer's email (optional for each maintainer)
url: A URL for the maintainer (optional for each maintainer)
deprecated: Whether this chart is deprecated (optional, boolean)
tillerVersion: The version of Tiller that this chart requires. This should be expressed as a SemVer range: ">2.0.0" (optional)
結構中字段:每個chart必須有一個版本號。一個版本必須遵循SemVer 2標準。與Helm Classic不同,Kubernetes Helm使用版本號作爲發佈標誌。倉庫中的包由名稱和版本標識。注:雖然Helm Classic和部署管理器在chart方面都非常面向GitHub,但是Kubernetes Helm並不依賴或需要GitHub,甚至Git。因此,它根本不使用Git SHA進行版本控制。Chart.yaml
中的version
字段被許多Helm工具使用,包括CLI和Tiller服務商。在生成包時,helm package
命令將使用它在 Chart.yaml
中找到的版本作爲包名稱中的標記(token)。系統假設chart包名稱中的版本號與圖Chart.yaml
中的版本號匹配。不符合這一假設將會導致錯誤。appVersion
字段,appVersion
字段與version
字段不相關。它是一種指定應用程序版本的方法。例如,drupal
chart可能有一個appVersion: 8.2.1
,這表示chart中包含的drupal版本
(默認情況下)是8.2.1。此字段是信息性的,對chart版本計算沒有影響。
廢棄chart:在chart倉庫中管理chart時,有時需要廢棄chart。Chart.yaml
中可選的deprecated
字段可用於將chart標記爲已廢棄。如果倉庫中chart的最新版本被標記爲已廢棄,則認爲整個chart已棄用。隨後可以通過發佈未標記爲已棄用的新版本來重用chart名稱。廢棄chart的工作流程如下:1) 更新chart的 Chart.yaml
文件,將chart標記爲已廢棄,碰撞版本。2)在chart倉庫中發佈新的chart版本。3)從源代碼倉庫中刪除chart(例如git)。chart還可以包含描述chart的安裝、配置、使用和許可證的文件。許可證是包含chart許可證的純文本文件。chart可以包含一個許可證,因爲它可能在模板中有編程邏輯,因此不只是配置。如果需要,還可以爲chart安裝的應用程序提供單獨的許可證。圖表的自述應該是Markdown (README.md)格式的,並且通常應該包含:1)chart提供的應用程序或服務的描述;2)運行chart的任何前提條件或要求;3)values.yaml
文件中選項的描述和默認值;4)與chart的安裝或配置相關的任何其他信息。
templates/NOTES.tx:
chart還可以包含一個簡短的純文本 templates/NOTES.txt
文件,該文件將在安裝之後以及查看發佈狀態時打印出來。此文件作爲模板進行計算,可用於顯示使用說明、下一步操作或與chart發佈相關的任何其他信息。例如,可以提供連接數據庫或訪問web UI的指令。由於該文件在運行helm install
或helm status
時被打印爲標準輸出,因此建議保持內容簡短,並指向README以獲得更詳細的信息。
chart依賴: 在Helm中,一個chart可以依賴於任意數量的其他圖表。這些依賴關係可以通過 requirements.yaml
文件動態鏈接或導入到 charts/
目錄並手動管理。儘管手動管理依賴項有一些團隊需要,但優點很少,使用chart中的一個 requirements.yaml
文件是首選方式。注:來自Helm Classic的Chart.yaml
的dependencies:
部分已經被完全移除。使用requirements.yaml
管理依賴,一個requirements.yaml
文件是一個列出依賴項的簡單文件。
dependencies:
- name: apache
version: 1.2.3
repository: http://example.com/charts
condition: subchart1.enabled
tags:
- front-end
- subchart1
- name: mysql
version: 3.2.1
alias: new-subchart-2
repository: http://another.example.com/charts
name
字段是你想要的chart的名稱。version
字段是你想要的chart的版本。repository
字段是chart倉庫的完整URL。請注意,你還必須使用helm repo add
命令在本地添加該倉庫。一旦你有了一個依賴文件,你可以運行 helm dependency update
,它會使用你的依賴文件爲你下載所有指定的chart到你的charts/
目錄中。當helm dependency update
檢索chart時,它將把它們作爲chart歸檔文件存儲在charts/
目錄中。因此,對於上面的示例,可以在charts/
目錄中看到以下文件:charts/ apache-1.2.3.tgz mysql-3.2.1.tgz. 使用 requirements.yaml
可以輕鬆地更新chart,requirements.yaml
中的alias
字段,每個需求條目可能包含可選的alias
字段。爲依賴chart添加alias
會將chart放入依賴項中,並使用別名作爲新依賴項的名稱。除了上面的其他字段外,每個需求條目可能包含可選字段tags
和condition
。所有chart都是默認加載的。如果存在tags
或condition
字段,則將對它們進行計算,並使用它們來控制所應用的chart的加載。條件:condition
字段包含一個或多個YAML路徑(由逗號分隔)。如果此路徑存在於父chart的值中並解析爲布爾值,則將根據該布爾值啓用或禁用chart。只計算列表中找到的第一個有效路徑,如果沒有路徑存在,則條件無效。對於多級依賴項,該條件由到父chart的路徑預先確定。標籤:tags
字段是與此圖表相關聯的標籤的YAML列表。在頂層的父chart值中,通過指定標籤和布爾值,可以啓用或禁用所有帶有標答的chart。
模板與值: Helm Chart模板是用Go模板語言編寫的,從Sprig庫中添加了大約50個附加模板函數和一些其他的專用函數。所有模板文件都存儲在chart的templates/
文件夾中。Go附帶了幾個內置函數,我們還添加了許多其他函數。出於安全考慮,刪除了兩個:env
和expandenv
(這將允許chart作者訪問Tiller環境)。還添加了兩個特殊的模板函數:include
和required
。include
函數允許你引入另一個模板,然後將結果傳遞給其他模板函數。如下模板片段包含一個名爲mytpl
的模板,然後將結果小寫,然後用雙引號括起來。value: {{ include "mytpl" . | lower | quote }};required
函數允許你聲明模板渲染所需的特定值條目。如果該值爲空,模板渲染將失敗,並拋出用戶提交的錯誤消息。下面的示例函數聲明.Values.who
條目是必需的,當該條目不存在時,將打印一個錯誤消息:value: {{ required "A valid .Values.who entry required!" .Values.who }};使用include
函數時,可以使用dict
函數將當前上下文構建的自定義對象樹傳遞給它:{{- include "mytpl" (dict "key1" .Values.originalKey1 "key2" .Values.originalKey2) }};爲字符串添加引號,不要爲整數添加引號,當你在處理字符串數據時,爲字符串添加引號總是比只留下單詞更安全:name: {{ .Values.MyName | quote }};但是在處理整數時,不需要添加引號。在許多情況下,這可能導致Kubernetes內部的解析錯誤。port: {{ .Values.Port }};此備註不適用於字符串環境變量值的情況,即使它們表示整數:
env:
-name: HOST
value: "http://host"
-name: PORT
value: "1234"
使用include
函數,Go提供了一種使用內置的template
指令將一個模板包含到另一個模板中的方法。但是在Go模板管道中不能使用內置指令;爲了能夠包含一個模板,然後對模板的輸出執行一個操作,Helm有一個特殊的include
函數:{{- include "toYaml" $value | nindent 2 }};上面包含一個名爲toYaml
的模板,將$value
傳遞給它,然後將該模板的輸出傳遞給nindent
函數。使用 {{- ... | nindent _n_ }}
模式使在上下文中讀取include
更加容易,因爲它將刪除左邊的空格(包括前面的換行),然後nindent
重新添加換行,並按請求的數量縮進包含的內容。因爲YAML認爲縮進層次和空白很重要,所以這是一種包含代碼片段的好方法,但是要在相關上下文中處理縮進。使用required
函數:Go提供了一種設置模板選項的方法,用於控制在map的鍵不存在時的行爲。通常使用template.Options("missingkey=option")
設置,其中option
可以是default
、zero
或error
。雖然將此選項設置爲error
將停止執行並出現錯誤,但這將適用於map中每個丟失的鍵。在某些情況下,chart開發人員可能希望強制在values.yaml
文件中選擇值。required
函數使開發人員能夠聲明模板渲染所需的值條目。如果條目在values.yaml
中爲空。模板將不會呈現,並將返回由開發人員提供的錯誤消息。如:{{ required "A valid foo is required!" .Values.foo }};上面的代碼將在定義了.Values.foo
時渲染模板。但在未定義.Values.foo
時將無法呈現並退出。使用tpl
函數:tpl
函數允許開發人員在模板中將字符串作爲模板進行計算。這對於將模板字符串作爲值傳遞給chart或渲染外部配置文件非常有用。語法爲:{{ tpl TEMPLATE_STRING VALUES }}
。創建鏡像拉取Secret:鏡像拉取Secret本質上是倉庫、用戶名和密碼的組合。你可能需要在部署的應用程序中使用它們,但是創建它們需要運行多次base64
命令。我們可以編寫一個幫助模板來組成Docker配置文件,作爲Secret的有效負載。
當Helm渲染chart時,它將通過模板引擎傳遞該目錄中的每個文件。模板的值有兩種提供方式:1)chart開發人員可能會在chart中提供一個名爲values.yaml
的文件。這個文件可以包含默認值。2)chart用戶可以提供包含值的YAML文件。這可以在helm install
的命令行中提供。當用戶提供自定義值時,這些值將覆蓋chart的values.yaml
中的值。模板文件:模板文件遵循編寫Go模板的標準約定。一個模板文件的例子可能是這樣的:
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
app.kubernetes.io/managed-by: deis
spec:
replicas: 1
selector:
app.kubernetes.io/name: deis-database
template:
metadata:
labels:
app.kubernetes.io/name: deis-database
spec:
serviceAccount: deis-database
containers:
- name: deis-database
image: {{.Values.imageRegistry}}/postgres:{{.Values.dockerTag}}
imagePullPolicy: {{.Values.pullPolicy}}
ports:
- containerPort: 5432
env:
- name: DATABASE_STORAGE
value: {{default "minio" .Values.storage}}
上面的示例鬆散地基於https://github.com/deis/charts,是Kubernetes副本控制器的模板。它可以使用了以下四個模板值(常在一個values.yaml
中定義):1)imageRegistry
:Docker鏡像的源倉庫,2)dockerTag
:Docker鏡像的標籤(tag),3)pullPolicy
:Kubernetes的鏡像拉取策略,4)storage
:存儲後端,默認設置爲"minio"
所有這些值都是由模板作者定義的。Helm不需要或定義參數。通過values.yaml
或--set
選項提供的值可以從模板中的.Values
對象訪問。但是你可以在模板中訪問其他預定義的數據片段。以下值是預先定義的,每個模板都可以使用,並且不能被覆蓋。與所有值一樣,名稱是區分大小寫的。
Release.Name
:發佈的名稱(不是chart的名稱)Release.Time
:chart發佈最後一次更新的時間。這將匹配發布對象上的Last Released
時間。Release.Namespace
:chart發佈所在的命名空間。Release.Service
:管理髮布的服務。通常爲Tiller
。Release.IsUpgrade
:如果當前操作是升級或回滾,則將其設置爲true
。Release.IsInstall
:如果當前操作是安裝,則將其設置爲true
。Release.Revision
:修訂號。它從1開始,每helm upgrade
一次,其值加1。Chart
:Chart.yaml
的內容,因此,可以通過Chart.Version
獲取chart版本,Chart.Maintainers
獲取維護者。Files
:包含chart中所有非特殊文件的類似於Map的對象。你不能訪問模板,但可以訪問存在的其他文件(除非使用.helmignore
排除它們)。可以使用{{index .Files "file.name"}}
或使用{{.Files.Get name}}
或{{.Files.GetString name}}
函數訪問文件。你也可以使用{{.Files.GetBytes}}
獲取文件內容的字節數據([]byte
)。Capabilities
:一個類似地圖的對象,它包含關於Kubernetes版本({{.Capabilities.KubeVersion}}
)、Tiller版本({{.Capabilities.TillerVersion}}
)和支持的Kubernetes API版本({{.Capabilities.APIVersions.Has "batch/v1"
)信息。
任何未知的Chart.yaml
字段將被刪除。它們在Chart
對象內部不可訪問。因此,Chart.yaml
不能用於將任意結構的數據傳遞到模板中。但是,values.yaml
文件可以用於此目的。values.yaml
文件,一個values.yaml
文件提供必要的值應該是這樣的:
imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
storage: "s3"
values.yaml
文件是YAML格式的。chart可以包含一個提供默認值的values.yaml
文件。helm install
命令允許用戶通過提供額外的YAML值來覆蓋這些值:chart中包含的默認值文件必須命名爲values.yaml
。但是在命令行中指定的文件可以命名爲任何名稱。如果在helm install
或helm upgrade
時使用了--set
選項,那麼這些值將在客戶端被簡單地轉換爲YAML。如果值(values)文件中存在任何必需的條目,可以使用required
函數在chart模板中進行聲明。一個values
文件可以向chart及其任何依賴的chart提供值。更高層次的chart可以訪問下層chart定義的所有變量。但是下層chart不能訪問父chart中的內容。全局值(global: value)從2.0.0-Alpha.2開始,Helm支持特殊的“全局”值。這提供了一種與所有子chart共享一個頂層變量的方法,這對於設置標籤等metadata
屬性非常有用。如果子chart聲明瞭一個全局變量,那麼該全局變量將向下傳遞(傳遞到子chart的子chart),而不是向上傳遞到父chart。子chart無法影響父chart的值。此外,父chart的全局變量優先於子chart的全局變量。
使用Helm管理chart:helm
工具有幾個處理chart的命令。helm create mychart它可以爲你創建一個新的chart:一旦你已經編輯了一個chart,helm
可以爲你把它打包成一個chart歸檔:$ helm package mychart;你也可以使用helm
來幫助你發現chart格式或信息方面的問題:$ helm lint mychart ;chart倉庫:chart倉庫是一個HTTP服務器,其中存放一個或多個打包的chart。雖然helm
可用於管理本地chart目錄,但在共享chart時,首選的機制是chart倉庫。任何能夠提供YAML文件和tar文件並能夠響應GET請求的HTTP服務器都可以作爲倉庫服務器。Helm自帶用於開發人員測試的內置包服務器(helm serve
)。Helm團隊已經測試了其他服務器,包括啓用了網站模式的谷歌雲存儲和啓用了網站模式的S3。倉庫的主要特徵是存在一個稱爲index.yaml
的特殊文件,該文件包含倉庫提供的所有包的列表,以及允許檢索和驗證這些包的元數據。在客戶端,倉庫由helm repo
命令管理。但是,Helm不提供將chart上傳到遠程倉庫服務器的工具。這是因爲這樣做會給實現服務器增加大量的要求,從而增加了設置倉庫的障礙。
helm hooks: Helm提供了一個鉤子機制,允許chart開發人員在發佈生命週期的某些階段進行干預。例如你可以使用鉤子:1) 在安裝過程中,在加載任何其他chart之前加載ConfigMap或Secret。2) 在安裝新chart之前執行備份數據庫作業,然後在升級之後執行第二個作業以恢復數據。3) 在刪除發佈之前運行作業,以便在刪除服務之前優雅地停止作業。鉤子的工作方式與常規模板類似,但是它們有特殊的註解,這導致Helm以不同的方式使用它們。鉤子在清單的元數據部分用註解進行聲明與可用鉤子:
apiVersion: ...
kind: ....
metadata:
annotations:
"helm.sh/hook": "pre-install"
# ...
- pre-install:在模板渲染後執行,但在Kubernetes中創建任何資源之前執行。
- post-install:在所有資源加載到Kubernetes後執行。
- pre-delete:在收到了刪除請求但未從Kubernetes中刪除任何資源之前執行。
- post-delete:在收到了刪除請求並從Kubernetes中刪除所有資源之後執行。
- pre-upgrade:在模板被渲染之後收到了升級請求,但是在任何資源被加載到Kubernetes之前(例如,在Kubernetes
apply
操作之前)執行。 - post-upgrade:在收到了升級請求並升級完所有資源之後執行。
- pre-rollback:在模板被渲染之後收到了回滾請求,但在任何資源被回滾之前執行。
- post-rollback:在收到了回滾請求並回滾完所有資源之後執行。
- crd-install:在添加CRD資源時,運行任何其他檢查之前執行。這僅用於chart中其他清單使用的CRD定義。
- test-success:在運行
helm test
並且pod成功返回(返回碼== 0)時執行。 - test-failure:在運行
helm test
並且pod成功失敗(返回碼!= 0)時執行。
鉤子使chart開發人員有機會在發佈生命週期的某階段執行操作。如一個helm install
的生命週期。默認情況下,生命週期是這樣的:1)用戶運行helm install foo; 2)
chart加載至Tiller; 3) 進行一些校驗後,Tiller渲染foo
模板; 4) Tiller加載結果資源至Kubernetes;5)Tiller返回發佈名稱和其它數據給客戶端;6)客戶端退出。Helm爲install
生命週期定義了兩個鉤子: pre-install
和post-install
。
如果foo
chart的開發者同時實現了這兩個鉤子,那麼它的生命週期就會這樣改變:1)用戶運行helm install foo;2)chart加載至Tiller;
3)進行一些校驗後,Tiller渲染foo
模板;4)Tiller準備執行pre-install
鉤子(加載鉤子資源至Kubernetes);5)Tiller按權重(默認爲0)(具有相同權重則按名稱)對鉤子進行升序排序。6)然後,Tiller首先加載權重最低的鉤子(負數 至 正數);7)Tiller等待鉤子“就緒(Ready)”(除了CRD);8)Tiller將結果資源裝載到Kubernetes中。請注意,如果設置了--wait
選項,Tiller將一直等待,直到所有資源都處於就緒(Ready)狀態,並且在準備就緒之前不會運行post-install
鉤子。9)Tiller運行post-install
鉤子(加載鉤子資源);10)Tiller等待鉤子“就緒(Ready)”;11)Tiller返回發佈名稱和其它數據給客戶端;12)客戶端退出。
等待鉤子就緒是什麼意思?這取決於鉤子中聲明的資源。如果資源是Job
類型,Tiller將等待作業成功運行到完成。如果作業失敗,則發佈失敗。這是一個阻塞操作,所以Helm客戶端將在作業運行時暫停。對於所有其他資源類型,只要Kubernetes將資源標記爲已加載(已添加或已更新),資源就被認爲是“就緒”的。當在一個鉤子中聲明許多資源時,這些資源是串行執行的。如果它們有鉤子權重,則按權重升序順序執行。否則無法保證順序。(在Helm 2.3.0及之後,它們按字母順序排序。不過這種行爲並不具有約束力,將來可能會改變。)添加鉤子權重是一種很好的做法,如果權重不重要,則將其設置爲0
。鉤子資源不是由相應的發佈來管理,鉤子創建的資源不作爲發佈的一部分進行跟蹤或管理。一旦Tiller驗證鉤子已經達到了它的就緒狀態,它就會離開鉤子資源。實際上,這意味着如果你在一個鉤子中創建資源,你不能依靠helm delete
來刪除資源。要銷燬這些資源,你需要編寫代碼在 pre-delete
或 post-delete
的鉤子中執行此操作,或者在鉤子模板文件中添加"helm.sh/hook-delete-policy"
註解。鉤子權重可以是正數或負數,但必須用字符串表示。當Tiller開始執行某種類型的鉤子(例如pre-install
鉤子或post-install
鉤子等)時,它將按升序對這些鉤子進行排序。
使用crd-install
鉤子定義CRD,(CRD)是Kubernetes中的一種特殊類型。它們提供了一種定義其他類型(kind
)的方法。有時,chart需要定義一種類型,然後使用它。這是通過crd-install
鉤子完成的。在安裝過程中,在驗證其餘清單之前,很早就執行了crd-install
鉤子。可以使用這個鉤子對CRD添加註解,以便在引用CRD的任何實例之前安裝它們。這樣當稍後進行驗證時,CRD就可用了。自動刪除鉤子從以前的發佈:當使用鉤子的helm發佈(release)更新時,鉤子資源可能集羣中已經存。此時,默認情況下,Helm將無法安裝鉤子資源,出現 "... already exists"
錯誤。鉤子資源可能已經存在的一個常見原因是,它在以前的安裝或升級中使用後沒有被刪除。實際上,有很好的理由可以解釋爲什麼要保留這個鉤子:例如,爲了在出現問題時幫助手工調試。在這種情況下,確保後續創建鉤子不會失敗的建議方法是定義一個"hook-delete-policy"
來處理: "helm.sh/hook-delete-policy": "before-hook-creation"
。此鉤子註解使在安裝新鉤子之前刪除任何已存在的鉤子。如果想在每次使用後刪除鉤子(而不是在以後的使用中處理它,如上所示),那麼可以使用刪除策略 "helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"
來實現。