您好,登錄后才能下訂單哦!
helm 類似于Linux系統下的包管理器,如yum/apt等,可以方便快捷的將之前打包好的yaml文件快速部署進kubernetes內,方便管理維護。
簡單來說:
cdn.xitu.io/2019/8/20/16cada288ee25884?w=1778&h=1094&f=png&s=802665">
Tiller 在處理 Chart 時,直接將 Chart 以及其依賴的所有 Charts 合并為一個 Release,同時傳遞給 Kubernetes。因此 Tiller 并不負責管理依賴之間的啟動順序。Chart 中的應用需要能夠自行處理依賴關系。
# 在helm客戶端主機上,一般為master主機
wget https://get.helm.sh/helm-v2.14.2-linux-amd64.tar.gz
tar xf helm-v2.14.2-linux-amd64.tar.gz
mv helm /usr/local/bin/
helm version
初始化tiller會自動讀取~/.kube
目錄,所以需要確保config文件存在并認證成功
# 在:https://github.com/helm/helm/blob/master/docs/rbac.md 可以找到rbac-config.yaml
cat > rbac-config.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
EOF
kubectl apply -f rbac-config.yaml
docker pull jessestuart/tiller:v2.14.2
yum install socat
# yum install socat
docker tag jessestuart/tiller:v2.14.2 gcr.io/kubernetes-helm/tiller:v2.14.2
helm init -i gcr.io/kubernetes-helm/tiller:v2.9.0
# 需要注意點參數
–client-only:也就是不安裝服務端應用,這在 CI&CD 中可能需要,因為通常你已經在 k8s 集群中安裝好應用了,這時只需初始化 helm 客戶端即可;
–history-max:最大歷史,當你用 helm 安裝應用的時候,helm 會在所在的 namespace 中創建一份安裝記錄,隨著更新次數增加,這份記錄會越來越多;
–tiller-namespace:默認是 kube-system,你也可以設置為其它 namespace;
# 由于gfw原因,可以利用此鏡像https://hub.docker.com/r/jessestuart/tiller/tags
kubectl edit deployment -n kube-system tiller-deploy
image: jessestuart/tiller:v2.14.0
Error: Looks like "https://kubernetes-charts.storage.googleapis.com" is not a valid chart repository or cannot be reached: Get https://kubernetes-charts.storage.googleapis.com/index.yaml: read tcp 10.2.8.44:49020->216.58.220.208:443: read: connection reset by peer
解決方案:更換源:helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
然后在helm init
注意:tiller可能運行在node節點,將tiller鏡像下載到node節點并修改tag
[root@master ~]# helm version
Client: &version.Version{SemVer:"v2.14.2", GitCommit:"a8b13cc5ab6a7dbef0a58f5061bcc7c0c61598e7", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.2+unreleased", GitCommit:"d953c6875cfd4b351a1e8205081ea8aabad7e7d4", GitTreeState:"dirty"}
由于國外很多鏡像網站國內無法訪問,例如gcr.io ,建議使用阿里源,https://developer.aliyun.com/hub。
AppHub 是一個托管在國內公有云上、全公益性的 Helm Hub “中國站”,它的后端由阿里云容器平臺團隊的三位工程師利用 20% 時間開發完成。
而這個站點的一個重要職責,就是把所有 Helm 官方 Hub 托管的應用自動同步到國內;同時,自動將 Charts 文件中的 gcr.io 等所有有網絡訪問問題的 URL 替換成為穩定的國內鏡像 URL。
目前helm3已經不依賴于tiller,Release 名稱可在不同 ns 間重用。
Helm3 不需要安裝tiller,下載到 Helm 二進制文件直接解壓到 $PATH 下就可以使用了。
cd /opt && wget https://cloudnativeapphub.oss-cn-hangzhou.aliyuncs.com/helm-v3.0.0-alpha.1-linux-amd64.tar.gz
tar -xvf helm-v3.0.0-alpha.1-linux-amd64.tar.gz
mv linux-amd64 helm3
mv helm3/helm helm3/helm3
chown root.root helm3 -R
cat > /etc/profile.d/helm3.sh << EOF
export PATH=$PATH:/opt/helm3
EOF
source /etc/profile.d/helm3.sh
[root@master helm3]# helm3 version
version.BuildInfo{Version:"v3.0.0-alpha.1", GitCommit:"b9a54967f838723fe241172a6b94d18caf8bcdca", GitTreeState:"clean"}
helm repo add apphub https://apphub.aliyuncs.com
helm search guestbook
helm install guestbook apphub/guestbook
http://hub.kubeapps.com/
completion # 為指定的shell生成自動完成腳本(bash或zsh)
create # 創建一個具有給定名稱的新 chart
delete # 從 Kubernetes 刪除指定名稱的 release
dependency # 管理 chart 的依賴關系
fetch # 從存儲庫下載 chart 并(可選)將其解壓縮到本地目錄中
get # 下載一個命名 release
help # 列出所有幫助信息
history # 獲取 release 歷史
home # 顯示 HELM_HOME 的位置
init # 在客戶端和服務器上初始化Helm
inspect # 檢查 chart 詳細信息
install # 安裝 chart 存檔
lint # 對 chart 進行語法檢查
list # releases 列表
package # 將 chart 目錄打包成 chart 檔案
plugin # 添加列表或刪除 helm 插件
repo # 添加列表刪除更新和索引 chart 存儲庫
reset # 從集群中卸載 Tiller
rollback # 將版本回滾到以前的版本
search # 在 chart 存儲庫中搜索關鍵字
serve # 啟動本地http網絡服務器
status # 顯示指定 release 的狀態
template # 本地渲染模板
test # 測試一個 release
upgrade # 升級一個 release
verify # 驗證給定路徑上的 chart 是否已簽名且有效
version # 打印客戶端/服務器版本信息
dep # 分析 Chart 并下載依賴
helm install --name els1 -f values.yaml stable/elasticsearch
helm upgrade --set mysqlRootPassword=passwd db-mysql stable/mysql
helm upgrade go2cloud-api-doc go2cloud-api-doc/
helm rollback db-mysql 1
helm delete --purge db-mysql
helm install/upgrade xxx --dry-run --debug
myapp/ # Chart 目錄
├── charts # 這個 charts 依賴的其他 charts,始終被安裝
├── Chart.yaml # 描述這個 Chart 的相關信息、包括名字、描述信息、版本等
├── templates # 模板目錄
│ ├── deployment.yaml # deployment 控制器的 Go 模板文件
│ ├── _helpers.tpl # 以 _ 開頭的文件不會部署到 k8s 上,可用于定制通用信息
│ ├── ingress.yaml # ingress 的模板文件
│ ├── NOTES.txt # Chart 部署到集群后的一些信息,例如:如何使用、列出缺省值
│ ├── service.yaml # service 的 Go 模板文件
│ └── tests
│ └── test-connection.yaml
└── values.yaml # 模板的值文件,這些值會在安裝時應用到 GO 模板生成部署文件
[root@master mychart]# helm create mychart
Creating mychart
[root@master mychart]# ls
mychart
[root@master mychart]# tree mychart/
mychart/
├── charts
├── Chart.yaml
├── templates
│?? ├── deployment.yaml # 部署相關資源
│?? ├── _helpers.tpl # 模版助手
│?? ├── ingress.yaml # ingress資源
│?? ├── NOTES.txt # chart的幫助文本,運行helm install展示給用戶
│?? ├── service.yaml # service端點
│?? └── tests
│?? └── test-connection.yaml
└── values.yaml
3 directories, 8 files
rm -rf mychart/templates/*
# 我們首先創建一個名為 mychart/templates/configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
由于創建的yaml文件在template下,tiller讀取此文件,會將其發送給kubernetes。
[root@master mychart]# helm install ./mychart/
NAME: enervated-dolphin
LAST DEPLOYED: Sun Jul 21 09:29:13 2019
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
mychart-configmap 1 0s
[root@master mychart]# kubectl get cm mychart-configmap
NAME DATA AGE
mychart-configmap 1 2m6s
[root@master mychart]# kubectl describe cm mychart-configmap
Name: mychart-configmap
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
myvalue:
----
this is my chart configmap
Events: <none>
[root@master mychart]# helm get manifest enervated-dolphin
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "this is my chart configmap"
該 helm get manifest
命令獲取 release 名稱(enervated-dolphin)并打印出上傳到服務器的所有 Kubernetes 資源。每個文件都以 ---
開始作為 YAML 文檔的開始,然后是一個自動生成的注釋行,告訴我們該模板文件生成的這個 YAML 文檔。
從那里開始,我們可以看到 YAML 數據正是我們在我們的 configmap.yaml
文件中所設計的 。
現在我們可以刪除我們的 release:helm delete enervated-dolphin
。
[root@master mychart]# helm delete enervated-dolphin
release "enervated-dolphin" deleted
硬編碼 name:
成資源通常被認為是不好的做法。名稱應該是唯一的一個版本。所以我們可能希望通過插入 release 名稱來生成一個名稱字段。
提示: name: 由于 DNS 系統的限制,該字段限制為 63 個字符。因此,release 名稱限制為 53 個字符。Kubernetes 1.3 及更早版本僅限于 24 個字符(即 14 個字符名稱)。
修改下之前的configmap為如下內容
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
name:
現在這個值發生了變化成了 {{.Release.Name}}-configmap
。
模板指令包含在 {{
和 }}
塊中。
模板指令 {{.Release.Name}}
將 release 名稱注入模板。傳遞給模板的值可以認為是 namespace 對象,其中 dot(.)分隔每個 namespace 元素。
Release 前面的前一個小圓點表示我們從這個范圍的最上面的 namespace 開始(我們將稍微談一下 scope)。所以我們可以這樣理解 .Release.Name:
"從頂層命名空間開始,找到 Release 對象,然后在里面查找名為 Name
的對象"。
該 Release 對象是 Helm 的內置對象之一,稍后我們將更深入地介紹它。但就目前而言,這足以說明這會顯示 Tiller 分配給我們發布的 release 名稱。
現在,當我們安裝我們的資源時,我們會立即看到使用這個模板指令的結果:
[root@master mychart]# helm install ./mychart/
NAME: famous-peahen
LAST DEPLOYED: Sun Jul 21 09:42:05 2019
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
famous-peahen-confgmap 1 0s
[root@master mychart]# helm get manifest famous-peahen
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: famous-peahen-confgmap
data:
myvalue: "this is my chart configmap"
我們看過了基礎的模板:YAML 文件嵌入了模板指令,通過 。在下一部分中,我們將深入研究模板。但在繼續之前,有一個快速技巧可以使構建模板更快:當您想測試模板渲染,但實際上沒有安裝任何東西時,可以使用 helm install --debug --dry-run ./mychart
。這會將 chart 發送到 Tiller 服務器,它將渲染模板。但不是安裝 chart,它會將渲染模板返回,以便可以看到輸出:
helm內部變量
對象從模板引擎傳遞到模板中。你的代碼可以傳遞對象(我們將在說明 with
和 range
語句時看到示例)。甚至有幾種方法在模板中創建新對象,就像我們稍后會看的 tuple
函數一樣。
對象可以很簡單,只有一個值。或者他們可以包含其他對象或函數。例如,Release
對象包含多個對象(如 Release.Name
)并且 Files
對象具有一些函數。
在上一節中,我們使用 {{.Release.Name}}
將 release 的名稱插入到模板中。Release
是可以在模板中訪問的頂級對象之一。
Release
:這個對象描述了 release 本身。它里面有幾個對象:Release.Name
:release 名稱Release.Time
:release 的時間Release.Namespace
:release 的 namespace(如果清單未覆蓋)Release.Service
:release 服務的名稱(始終是 Tiller
)。Release.Revision
:此 release 的修訂版本號。它從 1 開始,每 helm upgrade
一次增加一個。Release.IsUpgrade
:如果當前操作是升級或回滾,則將其設置為 true
。Release.IsInstall
:如果當前操作是安裝,則設置為 true
。Values
:從 values.yaml
文件和用戶提供的文件傳入模板的值。默認情況下,Values 是空的。Chart
:Chart.yaml
文件的內容。任何數據 Chart.yaml 將在這里訪問。例如 {{.Chart.Name}}-{{.Chart.Version}} 將打印出來 mychart-0.1.0。chart 指南中 Charts Guide 列出了可用字段Files
:這提供對 chart 中所有非特殊文件的訪問。雖然無法使用它來訪問模板,但可以使用它來訪問 chart 中的其他文件。請參閱 "訪問文件" 部分。Files.Get
是一個按名稱獲取文件的函數(.Files.Get config.ini
)Files.GetBytes
是將文件內容作為字節數組而不是字符串獲取的函數。這對于像圖片這樣的東西很有用。Capabilities
:這提供了關于 Kubernetes 集群支持的功能的信息。Capabilities.APIVersions
是一組版本信息。Capabilities.APIVersions.Has $version
指示是否在群集上啟用版本(batch/v1
)。Capabilities.KubeVersion
提供了查找 Kubernetes 版本的方法。它具有以下值:Major,Minor,GitVersion,GitCommit,GitTreeState,BuildDate,GoVersion,Compiler,和 Platform。Capabilities.TillerVersion
提供了查找 Tiller 版本的方法。它具有以下值:SemVer,GitCommit,和 GitTreeState。Template
:包含有關正在執行的當前模板的信息Name
:到當前模板的 namespace 文件路徑(例如 mychart/templates/mytemplate.yaml
)BasePath
:當前 chart 模板目錄的 namespace 路徑(例如 mychart/templates)。這些值可用于任何頂級模板。我們稍后會看到,這并不意味著它們將在任何地方都要有。
內置值始終以大寫字母開頭。這符合Go的命名約定。當你創建自己的名字時,你可以自由地使用適合你的團隊的慣例。一些團隊,如Kubernetes chart團隊,選擇僅使用首字母小寫字母來區分本地名稱與內置名稱。在本指南中,我們遵循該約定。
在上一節中,我們看了 Helm 模板提供的內置對象。四個內置對象之一是 Values。該對象提供對傳入 chart 的值的訪問。其內容來自四個來源:
values.yaml
文件values.yaml
文件helm install -f myvals.yaml ./mychart
)--set
(例如 helm install --set foo=bar ./mychart
)上面的列表按照特定的順序排列:values.yaml 在默認情況下,父級 chart 的可以覆蓋該默認級別,而該 chart values.yaml 又可以被用戶提供的 values 文件覆蓋,而該文件又可以被 --set 參數覆蓋。
值文件是純 YAML 文件。我們編輯 mychart/values.yaml
,然后來編輯我們的 ConfigMap
模板。
刪除默認帶的 values.yaml,我們只設置一個參數:
# 編輯values.yaml
domain: anchnet.com
# 在模版中引用
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
domain: {{.Values.domain}}
注意我們在最后一行 {{ .Values.domain}} 獲取 domain` 的值。
[root@master mychart]# helm install --dry-run --debug ./mychart
'''
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: exciting-manta-confgmap
data:
myvalue: "this is my chart configmap"
domain: anchnet.com
由于 domain
在默認 values.yaml
文件中設置為 anchnet.com
,這就是模板中顯示的值。我們可以輕松地在我們的 helm install 命令中通過加一個 --set
添標志來覆蓋:
helm install --dry-run --debug --set domain=51idc.com ./mychart
'''
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: foppish-mule-confgmap
data:
myvalue: "this is my chart configmap"
domain: 51idc.com
由于 --set
比默認 values.yaml
文件具有更高的優先級
如果您需要從默認值中刪除一個鍵,可以覆蓋該鍵的值為 null,在這種情況下,Helm 將從覆蓋值合并中刪除該鍵。
helm install stable/drupal --set image=my-registry/drupal:0.1.0 --set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt] --set livenessProbe.httpGet=null
目前為止,我們已經知道如何將信息放入模板中。但是這些信息未經修改就被放入模板中。有時我們想要轉換這些數據,使得他們對我們來說更有用。
讓我們從一個最佳實踐開始:當從. Values 對象注入字符串到模板中時,我們引用這些字符串。我們可以通過調用 quote 模板指令中的函數來實現:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{quote .Values.favorite.drink}}
food: {{quote .Values.favorite.food}}
模板函數遵循語法 functionName arg1 arg2...
。在上面的代碼片段中,quote .Values.favorite.drink
調用 quote 函數并將一個參數傳遞給它。
Helm 擁有超過 60 種可用函數。其中一些是由 Go 模板語言 Go template language 本身定義的。其他大多數都是 Sprig 模板庫 Sprig template library 的一部分。在我們講解例子進行的過程中,我們會看到很多。
雖然我們將 Helm 模板語言視為 Helm 特有的,但它實際上是 Go 模板語言,一些額外函數和各種包裝器的組合,以將某些對象暴露給模板。Go 模板上的許多資源在了解模板時可能會有所幫助。
模板語言的強大功能之一是其管道概念。利用 UNIX 的一個概念,管道是一個鏈接在一起的一系列模板命令的工具,以緊湊地表達一系列轉換。換句話說,管道是按順序完成幾件事情的有效方式。我們用管道重寫上面的例子。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{.Values.favorite.drink | quote}}
food: {{.Values.favorite.food | quote}}
在這個例子中,沒有調用 quote ARGUMENT
,我們調換了順序。我們使用管道(|)將 “參數” 發送給函數:.Values.favorite.drink | quote
。使用管道,我們可以將幾個功能鏈接在一起:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{.Values.favorite.drink | quote}}
food: {{.Values.favorite.food | upper | quote}}
反轉順序是模板中的常見做法。你會看到.
val | quote
比quote .val
更常見。練習也是。
當評估時,該模板將產生如下結果:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: trendsetting-p-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
請注意,我們的原來 pizza
現在已經轉換為 "PIZZA"
。
當有像這樣管道參數時,第一個評估(.Values.favorite.drink
)的結果將作為函數的最后一個參數發送。我們可以修改上面的飲料示例來說明一個帶有兩個參數的函數 repeat COUNT STRING
:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{.Values.favorite.drink | repeat 5 | quote}}
food: {{.Values.favorite.food | upper | quote}}
該 repeat 函數將回送給定的字符串和給定的次數,所以我們將得到這個輸出:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: melting-porcup-configmap
data:
myvalue: "Hello World"
drink: "coffeecoffeecoffeecoffeecoffee"
food: "PIZZA"
經常使用的一個函數是 default
:default DEFAULT_VALUE GIVEN_VALUE
。該功能允許在模板內部指定默認值,以防該值被省略。讓我們用它來修改上面的飲料示例:
drink: {{.Values.favorite.drink | default "tea" | quote}}
如果我們像往常一樣運行,我們會得到我們的 coffee:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: virtuous-mink-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
現在,我們將從以下位置刪除喜歡的飲料設置 values.yaml:
favorite:
#drink: coffee
food: pizza
現在重新運行 helm install --dry-run --debug ./mychart
會產生這個 YAML:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: fair-worm-configmap
data:
myvalue: "Hello World"
drink: "tea"
food: "PIZZA"
在實際的 chart 中,所有靜態默認值應該存在于 values.yaml 中,不應該使用該 default 命令重復(否則它們將是重復多余的)。但是,default 命令對于計算的值是合適的,因為計算值不能在 values.yaml 中聲明。例如:
drink: {{.Values.favorite.drink | default (printf "%s-tea" (include "fullname" .)) }}
在一些地方,一個 if
條件可能比這 default
更適合。我們將在下一節中看到這些。
模板函數和管道是轉換信息并將其插入到 YAML 中的強大方法。但有時候需要添加一些比插入字符串更復雜一些的模板邏輯。在下一節中,我們將看看模板語言提供的控制結構。
對于模板,運算符(eq,ne,lt,gt,and,or 等等)都是已實現的功能。在管道中,運算符可以用圓括號((
和 )
)分組。
將運算符放到聲明的前面,后面跟著它的參數,就像使用函數一樣。要多個運算符一起使用,將每個函數通過圓括號分隔。
{{/* include the body of this if statement when the variable .Values.fooString xists and is set to "foo" */}}
{{if and .Values.fooString (eq .Values.fooString "foo") }}
{{...}}
{{end}}
{{/* do not include the body of this if statement because unset variables evaluate o false and .Values.setVariable was negated with the not function. */}}
{{if or .Values.anUnsetVariable (not .Values.aSetVariable) }}
{{...}}
{{end}}
現在我們可以從函數和管道轉向流控制,條件,循環和范圍修飾符。
控制結構(模板說法中稱為 “動作”)為模板作者提供了控制模板生成流程的能力。Helm 的模板語言提供了以下控制結構:
if/else
用于創建條件塊with
指定范圍range
,它提供了一個 “for each” 風格的循環除此之外,它還提供了一些聲明和使用命名模板段的操作:
define
在模板中聲明一個新的命名模板template
導入一個命名模板block
聲明了一種特殊的可填寫模板區域在本節中,我們將談論 if
,with
和 range
。其他內容在本指南后面的 “命名模板” 一節中介紹。
我們要看的第一個控制結構是用于在模板中有條件地包含文本塊。這就是 if/else 塊。
條件的基本結構如下所示:
{{if PIPELINE}}
# Do something
{{else if OTHER PIPELINE}}
# Do something else
{{else}}
# Default case
{{end}}
注意,我們現在討論的是管道而不是值。其原因是要明確控制結構可以執行整個管道,而不僅僅是評估一個值。
如果值為如下情況,則管道評估為 false。
nil
(空或 null)map
,slice
,tuple
,dict
,array
)在其他情況下, 條件值為 true 此管道被執行。
我們為 ConfigMap 添加一個簡單的條件。如果飲料被設置為咖啡,我們將添加另一個設置:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{.Values.favorite.drink | default "tea" | quote}}
food: {{.Values.favorite.food | upper | quote}}
{{if and .Values.favorite.drink (eq .Values.favorite.drink "coffee") }}mug: true{{ end }}
注意 .Values.favorite.drink
必須已定義,否則在將它與 “coffee” 進行比較時會拋出錯誤。由于我們在上一個例子中注釋掉了 drink:coffee
,因此輸出不應該包含 mug:true
標志。但是如果我們將該行添加回 values.yaml
文件中,輸出應該如下所示:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: eyewitness-elk-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
在查看條件時,我們應該快速查看模板中的空格控制方式。讓我們看一下前面的例子,并將其格式化為更容易閱讀的格式:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{.Values.favorite.drink | default "tea" | quote}}
food: {{.Values.favorite.food | upper | quote}}
{{if eq .Values.favorite.drink "coffee"}}
mug: true
{{end}}
最初,這看起來不錯。但是如果我們通過模板引擎運行它,我們會得到一個錯誤的結果:
$ helm install --dry-run --debug ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/k8s.io/helm/_scratch/mychart
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key
發生了什么?由于上面的空格,我們生成了不正確的 YAML。
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: eyewitness-elk-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
mug 不正確地縮進。讓我們簡單地縮進那行,然后重新運行:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{.Values.favorite.drink | default "tea" | quote}}
food: {{.Values.favorite.food | upper | quote}}
{{if eq .Values.favorite.drink "coffee"}}
mug: true
{{end}}
當我們發送該信息時,我們會得到有效的 YAML,但仍然看起來有點意思:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: telling-chimp-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
請注意,我們在 YAML 中收到了一些空行。為什么?當模板引擎運行時,它將刪除 {{
和 }}
中的空白內容,但是按原樣保留剩余的空白。
YAML 中的縮進空格是嚴格的,因此管理空格變得非常重要。幸運的是,Helm 模板有幾個工具可以幫助我們。
首先,可以使用特殊字符修改模板聲明的大括號語法,以告訴模板引擎填充空白。{{-
(添加了破折號和空格)表示應該將格左移,而 -}}
意味著應該刪除右空格。注意!換行符也是空格!
確保
-
和其他指令之間有空格。-3
意思是 “刪除左空格并打印 3”,而-3
意思是 “打印 -3”。
使用這個語法,我們可以修改我們的模板來擺脫這些新行:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{.Values.favorite.drink | default "tea" | quote}}
food: {{.Values.favorite.food | upper | quote}}
{{- if eq .Values.favorite.drink "coffee"}}
mug: true
{{- end}}
為了清楚說明這一點,讓我們調整上面的內容,將空格替換為 *
, 按照此規則將每個空格將被刪除。一個在該行的末尾的 *
指示換行符將被移除
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
drink: {{.Values.favorite.drink | default "tea" | quote}}
food: {{.Values.favorite.food | upper | quote}}*
**{{- if eq .Values.favorite.drink "coffee"}}
mug: true*
**{{- end}}
牢記這一點,我們可以通過 Helm 運行我們的模板并查看結果:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: clunky-cat-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
小心使用 chomping 修飾符。這樣很容易引起意外:
food: {{.Values.favorite.food | upper | quote}}
{{- if eq .Values.favorite.drink "coffee" -}}
mug: true
{{- end -}}
這將會產生 food: "PIZZA"mug:true,因為刪除了雙方的換行符。
有關模板中空格控制的詳細信息,請參閱官方 Go 模板文檔 Official Go template documentation
最后,有時候告訴模板系統如何縮進更容易,而不是試圖掌握模板指令的間距。因此,有時可能會發現使用 indent
函數({{indent 2 "mug:true"}}
)會很有用。
下一個要看的控制結構是 with
。它控制著變量作用域。回想一下,.
是對當前范圍的引用。因此,.Values
告訴模板在當前范圍中查找 Values
對象。
其語法 with 類似于一個簡單的 if 語句:
{{with PIPELINE}}
# restricted scope
{{end}}
范圍可以改變。with 可以允許將當前范圍(.
)設置為特定的對象。例如,我們一直在使用的 .Values.favorites
。讓我們重寫我們的 ConfigMap 來改變 .
范圍來指向 .Values.favorites
:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
{{- end}}
注意,現在我們可以引用 .drink
和 .food
無需對其進行限定。這是因為該 with
聲明設置 .
為指向 .Values.favorite
。在 {{end}}
后 .
復位其先前的范圍。
但是請注意!在受限范圍內,此時將無法從父范圍訪問其他對象。例如,下面會報錯:
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{.Release.Name}}
{{- end}}
它會產生一個錯誤,因為 Release.Name 它不在 .
限制范圍內。但是,如果我們交換最后兩行,所有將按預期工作,因為范圍在 之后被重置。
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
{{- end}}
release: {{.Release.Name}}
看下 range
,我們看看模板變量,它提供了一個解決上述范圍問題的方法。
range
動作許多編程語言都支持使用 for
循環,foreach
循環或類似的功能機制進行循環。在 Helm 的模板語言中,遍歷集合的方式是使用 range
操作子。
首先,讓我們在我們的 values.yaml
文件中添加一份披薩配料列表:
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
現在我們有一個列表(模板中稱為 slice)pizzaToppings。我們可以修改我們的模板,將這個列表打印到我們的 ConfigMap 中:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
{{- end}}
toppings: |-
{{- range .Values.pizzaToppings}}
- {{. | title | quote}}
{{- end}}
讓我們仔細看看 toppings
:list。該 range 函數將遍歷 pizzaToppings 列表。但現在發生了一些有趣的事. 就像 with
sets 的范圍 .
,range
操作子也是一樣。每次通過循環時,.
都設置為當前比薩餅頂部。也就是第一次 .
設定 mushrooms。第二個迭代它設置為 cheese
,依此類推。
我們可以直接向管道發送 .
的值,所以當我們這樣做時 {{. | title | quote}}
,它會發送 .
到 title(標題 case 函數),然后發送到 quote
。如果我們運行這個模板,輸出將是:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: edgy-dragonfly-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
toppings: |-
- "Mushrooms"
- "Cheese"
- "Peppers"
- "Onions"
現在,在這個例子中,我們碰到了一些棘手的事情。該 toppings: |-
行聲明了一個多行字符串。所以我們的 toppings list 實際上不是 YAML 清單。這是一個很大的字符串。我們為什么要這樣做?因為 ConfigMaps 中的數據 data
由鍵 / 值對組成,其中鍵和值都是簡單的字符串。要理解這種情況,請查看 Kubernetes ConfigMap 文檔.。但對我們來說,這個細節并不重要。
YAML 中的
|-
標記表示一個多行字符串。這可以是一種有用的技術,用于在清單中嵌入大塊數據,如此處所示。
有時能快速在模板中創建一個列表,然后遍歷該列表是很有用的。Helm 模板有一個功能可以使這個變得簡單:tuple
。在計算機科學中,元組是類固定大小的列表類集合,但是具有任意數據類型。這粗略地表達了 tuple 的使用方式。
sizes: |-
{{- range tuple "small" "medium" "large"}}
- {{.}}
{{- end}}
sizes: |-
- small
- medium
- large
除了list和tuple之外,range
還可以用于遍歷具有鍵和值的集合(如map
或 dict
)。當在下一節我們介紹模板變量時,將看到如何做到這一點。
我們已經了解了函數,管道,對象和控制結構,我們可以在許多編程語言中找到更基本的用法之一:變量。在模板中,它們使用的頻率較低。我們將看到如何使用它們來簡化代碼,并更好地使用 with
和 range
。
在前面的例子中,我們看到這段代碼會失敗:
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{.Release.Name}}
{{- end}}
Release.Name
不在該 with
塊中限制的范圍內。解決范圍問題的一種方法是將對象分配給可以在不考慮當前范圍的情況下訪問的變量。
在 Helm 模板中,變量是對另一個對象的命名引用。它遵循這個形式 $name
。變量被賦予一個特殊的賦值操作符::=
。我們可以使用變量重寫上面的 Release.Name。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
{{- $relname := .Release.Name -}}
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{$relname}}
{{- end}}
注意,在我們開始 with
塊之前,我們賦值 $relname :=
.Release.Name。現在在 with
塊內部,$relname
變量仍然指向發布名稱。
會產生這樣的結果:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: viable-badger-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
release: viable-badger
變量在 range
循環中特別有用。它們可以用于類似列表的對象以同時捕獲索引和值:
toppings: |-
{{- range $index, $topping := .Values.pizzaToppings}}
{{$index}}: {{ $topping }}
{{- end}}
注意,range
首先是變量,然后是賦值運算符,然后是列表。這將分配整數索引(從零開始)給 $index
,值給 $topping
。運行它將產生:
toppings: |-
0: mushrooms
1: cheese
2: peppers
3: onions
對于同時具有鍵和值的數據結構,我們可以使用 range
來獲得兩者。例如,我們可以對 .Values.favorite
像這樣循環:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite}}
{{$key}}: {{ $val | quote }}
{{- end}}
現在在第一次迭代中,$key
是 drink
,$val
是 coffee
,第二次,$key
是 food,$val
會 pizza。運行上面的代碼會生成下面這個:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: eager-rabbit-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
變量通常不是 “全局” 的。它們的范圍是它們所在的塊。之前,我們在模板的頂層賦值 $relname
。該變量將在整個模板的范圍內起作用。但在我們的最后一個例子中,$key
和 $val
只會在該 {{range...}}{{end}}
塊的范圍內起作用。
然而,總有一個變量是全局 $
變量 - 這個變量總是指向根上下文。當你在需要知道 chart 發行名稱的范圍內循環時,這非常有用。
舉例說明:
{{- range .Values.tlsSecrets}}
apiVersion: v1
kind: Secret
metadata:
name: {{.name}}
labels:
# Many helm templates would use `.` below, but that will not work,
# however `$` will work here
app.kubernetes.io/name: {{template "fullname" $}}
# I cannot reference .Chart.Name, but I can do $.Chart.Name
helm.sh/chart: "{{$.Chart.Name}}-{{ $.Chart.Version }}"
app.kubernetes.io/instance: "{{$.Release.Name}}"
app.kubernetes.io/managed-by: "{{$.Release.Service}}"
type: kubernetes.io/tls
data:
tls.crt: {{.certificate}}
tls.key: {{.key}}
---
{{- end}}
到目前為止,我們只查看了一個文件中聲明的一個模板。但是Helm模板語言的強大功能之一是它能夠聲明多個模板并將它們一起使用。我們將在下一節中討論。
現在是開始創建超過一個模板的時候了。在本節中,我們將看到如何在一個文件中定義命名模板,然后在別處使用它們。命名模板(有時稱為部分或子模板)是限定在一個文件內部的模板,并起一個名稱。我們有兩種創建方法,以及幾種不同的使用方法。
在 “流量控制” 部分中,我們介紹了聲明和管理模板三個動作:define
,template
,和 block
。在本節中,我們將介紹這三個動作,并介紹一個 include
函數,與 template
類似功能。
在命名模板時要注意一個重要的細節:模板名稱是全局的。如果聲明兩個具有相同名稱的模板,則最后加載一個模板是起作用的模板。由于子 chart 中的模板與頂級模板一起編譯,因此注意小心地使用特定 chart 的名稱來命名模板。
通用的命名約定是為每個定義的模板添加 chart 名稱:{{define "mychart.labels"}}
。通過使用特定 chart 名稱作為前綴,我們可以避免由于同名模板的兩個不同 chart 而可能出現的任何沖突。
_
文件到目前為止,我們已經使用了一個文件,一個文件包含一個模板。但 Helm 的模板語言允許創建指定的嵌入模板,可以通過名稱訪問。
在我們開始編寫這些模板之前,有一些文件命名約定值得一提:
templates/
被視為包含 Kubernetes manifestsNOTES.txt
是一個例外_
)開頭的文件被假定為沒有內部 manifest。這些文件不會渲染 Kubernetes 對象定義,而是在其他 chart 模板中隨處可用以供調用。這些文件用于存儲 partials 和輔助程序。事實上,當我們第一次創建時 mychart,我們看到一個叫做文件 _helpers.tpl
。該文件是模板 partials 的默認位置。
define
和 template
聲明和使用模板helm create go2cloud-api-doc
[root@master go2cloud-api-doc]# tree
.
├── charts
├── Chart.yaml
├── templates
│?? ├── deployment.yaml
│?? ├── _helpers.tpl
│?? ├── NOTES.txt
│?? ├── service.yaml
│?? └── tests
│?? └── test-connection.yaml
└── values.yaml
3 directories, 8 files
# 配置 deployment
[root@master go2cloud_api_doc_charts]# egrep "^$|^#" -v go2cloud-api-doc/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "go2cloud-api-doc.fullname" . }}
labels:
{{ include "go2cloud-api-doc.labels" . | indent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "go2cloud-api-doc.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "go2cloud-api-doc.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
imagePullSecrets:
- name: {{ .Values.imagePullSecrets }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
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 }}
# 配置service
[root@master go2cloud_api_doc_charts]# egrep "^$|^#" -v go2cloud-api-doc/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "go2cloud-api-doc.fullname" . }}
labels:
{{ include "go2cloud-api-doc.labels" . | indent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
protocol: TCP
name: http
nodePort: {{ .Values.service.nodePort }}
selector:
app.kubernetes.io/name: {{ include "go2cloud-api-doc.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
# 配置values
[root@master go2cloud_api_doc_charts]# egrep "^$|^#|^[[:space:]]+#" -v go2cloud-api-doc/values.yaml
replicaCount: 1
image:
repository: 10.234.2.218/go2cloud/go2cloud-api-doc
tag: latest
pullPolicy: Always
imagePullSecrets: registry-secret
nameOverride: ""
fullnameOverride: ""
service:
type: NodePort
port: 4567
nodePort: 30567
ingress:
enabled: false
annotations: {}
hosts:
- host: chart-example.local
paths: []
tls: []
resources:
requests:
cpu: 1000m
memory: 1280Mi
limits:
cpu: 1000m
memory: 1280Mi
livenessProbe:
tcpSocket:
port: 4567
initialDelaySeconds: 10
failureThreshold: 2
timeoutSeconds: 10
readinessProbe:
httpGet:
path: /#introduction
port: http
initialDelaySeconds: 5
failureThreshold: 2
timeoutSeconds: 30
nodeSelector: {}
tolerations: []
affinity: {}
[root@master go2cloud_api_doc_charts]# egrep "^$|^#|^[[:space:]]+#" -v go2cloud-api-doc/Chart.yaml
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: go2cloud-api-doc
version: 0.1.0
# 部署
[root@master go2cloud_api_doc_charts]# helm install -n go2cloud-api-doc -f go2cloud-api-doc/values.yaml go2cloud-api-doc/
NAME: go2cloud-api-doc
LAST DEPLOYED: Wed Jul 31 14:34:21 2019
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
go2cloud-api-doc 0/1 1 0 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
go2cloud-api-doc-7cfb7bb795-clrz8 0/1 ContainerCreating 0 0s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
go2cloud-api-doc NodePort 10.96.228.251 <none> 4567:30567/TCP 0s
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services go2cloud-api-doc)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
[root@master go2cloud_api_doc_charts]# helm ls go2cloud-api-doc
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
go2cloud-api-doc 1 Wed Jul 31 14:34:21 2019 DEPLOYED go2cloud-api-doc-0.1.0 1.0 default
[root@master go2cloud_api_doc_charts]# kubectl get deployment go2cloud-api-doc
NAME READY UP-TO-DATE AVAILABLE AGE
go2cloud-api-doc 0/1 1 0 10m
[root@master go2cloud_api_doc_charts]# kubectl get pods |grep go2cloud-api-doc
go2cloud-api-doc-7cfb7bb795-clrz8 0/1 CrashLoopBackOff 7 10m
[root@master go2cloud_api_doc_charts]# kubectl get svc go2cloud-api-doc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
go2cloud-api-doc NodePort 10.96.228.251 <none> 4567:30567/TCP 10m
# 打包
[root@master go2cloud_api_doc_charts]# helm package ./go2cloud-api-doc/
Successfully packaged chart and saved it to: /data/go2cloud_api_doc_charts/go2cloud-api-doc-0.1.0.tgz
[root@master go2cloud_api_doc_charts]# tree
.
├── go2cloud-api-doc
│?? ├── charts
│?? ├── Chart.yaml
│?? ├── templates
│?? │?? ├── deployment.yaml
│?? │?? ├── _helpers.tpl
│?? │?? ├── NOTES.txt
│?? │?? ├── service.yaml
│?? │?? └── tests
│?? │?? └── test-connection.yaml
│?? └── values.yaml
└── go2cloud-api-doc-0.1.0.tgz
4 directories, 8 files
# 升級副本數量
helm upgrade go2cloud-api-doc --set replicaCount=2 go2cloud-api-doc/
將制作好的charts存放到minio上,在k8s內部署minior
mkdir minio-chart
helm package redis
cp redis-8.0.5.tgz /root/minio-chart/
helm repo index minio-chart/ --url http://10.234.2.204:31311/minio/common-helm-repo/
mc cp index.yaml minio/common-helm-repo/
mc cp redis-8.0.5.tgz minio/common-helm-repo/
helm repo add monocular https://helm.github.io/monocular
helm install -n monocular monocular/monocular
mc cp go2cloud-api-doc-0.1.0.tgz minio/common-helm-repo
可以在${HOME}/.mc/config.json
中查看ak密鑰信息。
將制作好的charts包可以上傳至helm倉庫,可以放在自己的自建私有倉庫,流入:kubeapps/Monocular/minior等,可以利用helm命令一鍵安裝。
上傳至公有云公共倉庫,例如國內的阿里目前創建的Apphub等,在現今的云原生生態當中,已經有很多成熟的開源軟件被制作成了 Helm Charts,使得用戶可以非常方便地下載和使用,比如 Nginx,Apache、Elasticsearch、Redis 等等。不過,在開放云原生應用中心 App hub(Helm Charts 中國站) 發布之前,國內用戶一直都很難直接下載使用這些 Charts。而現在,AppHub 不僅為國內用戶實時同步了官方 Helm Hub 里的所有應用,還自動替換了這些 Charts 里所有不可訪問的鏡像 URL(比如 gcr.io, quay.io 等),終于使得國內開發者通過 helm install “一鍵安裝”應用成為了可能。
具體提交自己的charts可以參考:https://github.com/cloudnativeapp/charts/pulls?spm=a2c6h.13155457.1383030.1.3347b579urlAo7
此為我上傳的slate chart,Slate helps you create beautiful, intelligent, responsive API documentation.
https://developer.aliyun.com/hub/detail?spm=a2c6h.12873679.0.0.61731107C921or&name=slate&version=v2.3.1#/?_k=ayosl1
歡迎點贊。
helm 手冊
https://github.com/helm/monocular
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。