一、Helm介紹
在Kubernetes中部署容器雲應用(容器或微服務編排)是一項有挑戰性的工作,Helm就是為了簡化在Kubernetes中安裝部署容器雲應用的一個客戶端工具。通過Helm能夠幫助開發者定義、安裝和升級Kubernetes中的容器雲應用。同時,也可以通過Helm進行容器雲應用的分享。
Helm架構圖:
Helm有三個重要概念:
- chart:包含了創建Kubernetes的一個應用實例的必要信息
- config:包含了應用發布配置信息
- release:是一個chart及其配置的一個運行實例
二、Helm client/Tiller server 的安裝
-
Helm 包下載:
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.8.2-linux-amd64.tar.gz
tar xzf helm-v2.8.2-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin
-
Helm 配置:
由於Tiller server需要跟K8S api server通信,所以Tiller需要知道K8S的信息,默認Tiller是在目錄 ~/.kube/或者讀 KUBECONFIG 這個環境變量目錄底下的配置文件來獲取k8s集群信息.
[apps@gd13-001-noah-helm-proxy-api-prod-342295-0 ~]$ cat /apps/conf/helm/kubeconfig
apiVersion: v1
clusters:
- cluster:
server: http://10.199.175.65:8080
name: k8s
contexts:
- context:
cluster: k8s
user: ""
name: k8s
current-context: k8s
kind: Config
preferences: {}
users: []
如果Tiller連接的集群開啟了RBAC,那么連接K8S api server時需要使用Https的方式,請參考以 > https://www.cnblogs.com/ericte/p/13692545.html
[apps@gd13-001-noah-helm-proxy-api-prod-342295-0 logs]$ cat /apps/conf/helm/kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS.....LS0tCg==
server: https://10.199.175.65:6443
name: k8s
contexts:
- context:
cluster: k8s
user: noah-sa
name: k8s
current-context: k8s
kind: Config
preferences: {}
users:
- name: noah-sa
user:
as-user-extra: {}
token: eyJhbG....wg4Pc
-
Tiller啟動:
- Easy In-Cluster Installation
helm init
可選參數:
--kube-context
--tiller-image
--tiller-namespace
--service-account
如果沒有任何的參數指定,那么Helm將會在k8s集群的namespace=kube-system以service的方式創建一個Tiller server容器,鏡像為默認的Tiller鏡像(image: gcr.io/kubernetes-helm/tiller:v2.13.1),由於大多數時候我們是在線拿不到鏡像,原因你懂的,所以這一步很可能會失敗;所以可以提前拿到Tiller image並放在自己的集群上,然后啟動時帶上--tiller-image來指定image文件;亦或者可以采用以下方式啟動Tiller server。
- Running Tiller Locally
在本地啟動一個Tiller 進程,默認Tiller GRPC會監聽在 localhost:44134上,Probes(healthcheck)會監聽在localhost:44135。helm client在不指定--host的情況下按默認方式去找Tiller server(默認方式為連接Tiller server的 service cluster IP),所以用local的方式啟動的話一定要告訴helm client Tiller server的地址,一種是在命令行中用--host的方式指定,另一種就是設置環境變量$HELM_HOME (例如: export HELM_HOME=localhost:44134)。
$ bin/tiller
Tiller running on :44134
常用可選參數:
-listen string
address:port to listen on (default ":44134")
-log_backtrace_at value
when logging hits line file:N, emit a stack trace
-log_dir string
If non-empty, write log files in this directory
-log_file string
If non-empty, use this log file
-logtostderr
log to standard error instead of files
-tls
enable TLS
-tls-ca-cert string
trust certificates signed by this CA (default "ca.crt")
-tls-cert string
path to TLS certificate file (default "tls.crt")
-tls-key string
path to TLS private key file (default "tls.key")
-tls-verify
enable TLS and verify remote certificate
-trace
enable rpc tracing
-v value
log level for V logs
由於是用local方式啟動Tiller,~/.helm目錄是不會被helm主動創建(helm init命令會幫助創建該目錄),於是為了能夠正常使用helm命令,我們必須提前創建好helm的工作目錄。
[apps@gd13-001-noah-helm-proxy-api-prod-342295-0 templates]$ /apps/svr/helm/bin/helm init --client-only
Creating localhost:44134
Creating localhost:44134/repository
Creating localhost:44134/repository/cache
Creating localhost:44134/repository/local
Creating localhost:44134/plugins
Creating localhost:44134/starters
Creating localhost:44134/cache/archive
Creating localhost:44134/repository/repositories.yaml
Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com
但由於網絡是無法連通 https://kubernetes-charts.storage.googleapis.com,這一步會超時失敗,盡管失敗后最后helm的工作目錄還是會創建成功;如果想快速讓這一步通過則需要指定一個stable-repo-url (這一步noah是在moana_extend_start里做的)。
例如: /apps/svr/helm/bin/helm init --client-only --stable-repo-url http://10.199.175.65:8879
Tiller默認是將所有的資源默認是放在configmap(default namespace=kube-system),但如果Tiller是以容器發布且namespace不為kube-system,那么所有數據將存在容器的namespace里的configmap,可以通過環境變量 TILLER_NAMESPACE來更改數據存放namespace。
- 開了RBAC的集群啟動方式
如果k8s集群開通了RBAC,那么必須提前給Tiller給與一個role,所以需要在k8s上提前設置好clusterRole和clusterRoleBinding;並同時還得帶上TLS證書。
在RBAC集群內需要提前配置好serviceAccount並綁定上相應的clusterRole。
ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
ClusterRoleBinding:
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
或者用local方式啟動tiller的話那就指定在KUBECONFIG文件里指定證書文件,tiller會取證書里的O 字段做用戶為role。
openssl x509 -in /apps/conf/ssl/admin.pem -text
C=CN, ST=BeiJing, L=BeiJing, O=system:masters, OU=System, CN=kubernetes-core
在 kubectl get clusterrolebinding --all-namespaces -oyaml | grep system:masters 就能找到該用戶所綁定的role和權限。
- Chart repo啟動:
在沒有設置–repo的時候去做helm install,默認helm會去本地的 ~/.helm/repository/local目錄讀取index.yaml文件並尋找Chart package,從而進行helm install來發布release;但是如果是使用了遠程repo的方式來存儲Chart package的話Helm會先去repo拉取index.html文件和對應的package放在本地目錄/root/.helm/repository/local下。
- 開發方式啟動Chart repo:
Helm serve命令會啟動一個本地的http web server。默認的Chart package目錄為~/.helm/repository/local,
[root@qa-k8s-1-master helm-test]# helm serve --address 10.199.175.65:8879
Regenerating index. This may take a moment.
Now serving you on 10.199.175.65:8879
Options:
--address string address to listen on (default "127.0.0.1:8879")
-h, --help help for serve
--repo-path string local directory path from which to serve charts
--url string external URL of chart repository
- Chart museum:
ChartMuseum為一個開源的用來管理Chart包的Go語言程序,通過后端各種雲存儲來實現對Chart的管理,功能上包括Chart包的上傳,下載,刪除,list,listAll和describe chart
支持的后端雲存儲包括: Google Cloud Storage, Amazon S3, Microsoft Azure Blob Storage, Alibaba Cloud OSS Storage, Openstack Object Storage, Oracle Cloud Infrastructure Object Storage, and Baidu Cloud BOS Storage.
museum啟動:
chartmuseum --debug --port=8080 --storage="amazon" --storage-amazon-bucket="my-s3-bucket" --storage-amazon-prefix="" --storage-amazon-region="us-east-1"
並同時設置雲存儲的Account和Key:
export AWS_ACCESS_KEY_ID=""
export AWS_SECRET_ACCESS_KEY=""
更多雲存儲廠商配置請看:https://github.com/helm/chartmuseum
Museum API:
GET /index.yaml - retrieved when you run helm repo add chartmuseum http://localhost:8080/
GET /charts/mychart-0.1.0.tgz - retrieved when you run helm install chartmuseum/mychart
GET /charts/mychart-0.1.0.tgz.prov - retrieved when you run helm install with the --verify flag
POST /api/charts - upload a new chart version
POST /api/prov - upload a new provenance file
DELETE /api/charts/<name>/<version> - delete a chart version (and corresponding provenance file)
GET /api/charts - list all charts
GET /api/charts/<name> - list all versions of a chart
GET /api/charts/<name>/<version> - describe a chart version
GET / - HTML welcome page
GET /health - returns 200 OK
三、Helm 命令
- helm create
在當前目錄創建一個mychart目錄。
Chart.yaml — Chart名稱、描述和版本號
Values.yaml — Template中各變量的默認值
Template folder — 存放Chart的template文件,Tiller server會根據template里面的文件對里面的變量值進行渲染生成最后供k8s可用的resource yaml文件。
deployment.yaml/service.yaml/ingress.yaml — k8s resouce文件,里面有大量的chart語法
_helpers.tpl — 存放chart語法的變量值
NOTES.txt — 類似README,以供他人了解該chart的用途和介紹,純文本文件,會在helm install時候作為output輸出給用戶看。
[apps@gd13-001-noah-helm-proxy-api-prod-342295-0 ~]$ tree mychart/
mychart/
├── charts
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── ingress.yaml
│ ├── NOTES.txt
│ ├── service.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
3 directories, 8 files
-
helm package
在當前同名目錄生成tgz格式壓縮包,同時將壓縮包放到/root/.helm/repository/local並同時更新index.yaml文件。 -
helm install
利用已有的chart發布一個release
helm install
注意:這里的releaseName和namespace不一定會是最后在k8s上面創建的resource里的名稱和namespace,只有在chart里引用了這里的namespace才行,不然release和k8s的namespace會有不一致的情況。
小技巧:如果加上" --dry-run --debug ", Tiller server會渲染template但是不會發送給k8s創建resource,用這種方法可以檢查chart文件是否正確。
- helm upgrade
升級某個已發布的release,一般是通過--set-string來更新鏡像或更新replicasCount等。
helm upgrade <releaseName> <chartName> --repo <repoName> --namespace <nameSpace> --host <Tiller server> --version <chart Version> --reset-values|--reuse-values --set-string <ValuesStringList>
- helm rollback
回滾release至某個版本。
helm rollback $releaseName $revision --host localhost:44134 --force
- helm delete
刪除某個處於DEPLOYED狀態的release;如果想從release list中徹底清除則需要加上 --purge。
helm delete $releaseName --host localhost:44134
- helm status
查看某個release的狀態,可以查看該release發布的所有k8s resource的狀態。
[apps@gd13-001-noah-helm-proxy-api-prod-342295-0 ~]$ /apps/svr/helm/bin/helm status noah-php-demo
LAST DEPLOYED: Tue Apr 30 18:52:03 2019
NAMESPACE: eric
STATUS: DEPLOYED
RESOURCES:
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
noah-php-demo-helm-test 3/3 3 3 22h
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
noah-php-demo-helm-test-546958457-bb98x 1/1 Running 0 22h
noah-php-demo-helm-test-546958457-bsl9z 1/1 Running 0 22h
noah-php-demo-helm-test-546958457-k65zz 1/1 Running 0 22h
- helm list
list出release列表;可按status,date,chart name分別列出所有的release
helm list --output json --host localhost:44134 --all --offset xxx --max 10
Flags:
-a, --all show all releases, not just the ones marked DEPLOYED
-c, --chart-name sort by chart name
--col-width uint specifies the max column width of output (default 60)
-d, --date sort by release date
--deleted show deleted releases
--deleting show releases that are currently being deleted
--deployed show deployed releases. If no other is specified, this will be automatically enabled
--failed show failed releases
-m, --max int maximum number of releases to fetch (default 256)
--namespace string show releases within a specific namespace
-o, --offset string next release name in the list, used to offset from start value
--output string output the specified format (json or yaml)
--pending show pending releases
-r, --reverse reverse the sort order
- helm lint
檢查chart文件可能存在的問題,跟helm install--name --dry-run --debug效果差不多。
helm lint <chartName>
- helm history
列出某個release所有的歷史版本
/apps/svr/helm/bin/helm history noah-php-demo --output table
[apps@gd13-001-noah-helm-proxy-api-prod-342295-0 ~]$ /apps/svr/helm/bin/helm history noah-php-demo --output table
REVISION UPDATED STATUS CHART DESCRIPTION
1 Tue Apr 30 16:44:15 2019 SUPERSEDED helm-test-0.1.5 Install complete
2 Tue Apr 30 18:00:50 2019 SUPERSEDED helm-test-0.1.5 Upgrade complete
3 Tue Apr 30 18:41:36 2019 SUPERSEDED helm-test-0.1.5 Rollback to 1
4 Tue Apr 30 18:47:38 2019 SUPERSEDED helm-test-0.1.5 Upgrade complete
5 Tue Apr 30 18:49:58 2019 SUPERSEDED helm-test-0.1.5 Upgrade complete
6 Tue Apr 30 18:52:03 2019 DEPLOYED helm-test-0.1.5 Upgrade complete
- helm search
在所有的helm list中找出想找的release,關鍵字一般為release name。
helm search <keyword>
更多Helm命令請查詢Helm官方文檔(https://helm.sh/docs/helm/#helm)。
四、Chart語法
在前面我們已經簡單介紹了Chart的文件結構,包括Chart.yaml,values.yaml,templates/deployment.yaml,templates/_helpers.tpl,templates/NOTES.txt。
大家都知道template文件里會引用很多變量,而這些變量值來自何處,該用何種語法來寫才能達到我們想要的引用效果,下面我們一起來看看如何寫一份template文件。
以下是一份最簡單的configmap文件,里面的configmap的名稱引用了{{ .Release.Name }}-configmap。注意{{ 、}}兩邊的空格和點 " . " 。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
- Build-in 對象
注意所有的build-in對象首字母都必須大寫(Release, Values, Chart等)。- Release對象
從release里拿到release的信息並渲染template文件生成k8s resource文件。
- Release對象
Release.Name: The release name
Release.Time: The time of the release
Release.Namespace: The namespace to be released into (if the manifest doesn’t override)
Release.Service: The name of the releasing service (always Tiller).
Release.Revision: The revision number of this release. It begins at 1 and is incremented for each helm upgrade.
Release.IsUpgrade: This is set to true if the current operation is an upgrade or rollback.
Release.IsInstall: This is set to true if the current operation is an install.
- Values對象
從values.yaml里讀取對應的key並渲染,{{ .Values.replicasCount }} 、 {{ .Values.image.imageName }}
Values.yaml
replicasCount: 1
business_domain: noah-php-demo.vip.vip.com
namespace: eric
name: noah-php-demo-helm-test
image:
imageRepo: vipdocker-f9nub.vclound.com/citest
imageName: 1.0.0_1243_b4a48dd1bf153d5fe62397566bd34e5d1d64fe01
-
Chart對象
從Chart.yaml文件里引用Chart name和Version。 {{ .Chart.name}} \ {{ .Chart.version }} -
Capabilities
獲取k8s cluster info
Capabilities
Capabilities.APIVersions is a set of versions.
Capabilities.APIVersions.Has $version indicates whether a version (batch/v1) is enabled on the cluster.
Capabilities.KubeVersion provides a way to look up the Kubernetes version. It has the following values: Major, Minor, GitVersion, GitCommit, GitTreeState, BuildDate, GoVersion, Compiler, and Platform.
Capabilities.TillerVersion provides a way to look up the Tiller version. It has the following values: SemVer, GitCommit, and GitTreeState.
-
刪除某個key值
只需要在helm install/upgrade 時將某個key值設成null。
helm install stable/drupal --set image=my-registry/drupal:0.1.0 --set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt] --set livenessProbe.httpGet=null
以上命令會更改image,同時將liveness probe由原來的http get改成cat docroot/CHANGELOG.txt來判斷。 -
Function/Pipeline
函數/管道,跟shell命令中的管道是一樣的作用,通過一些命令來實現對輸出進行格式化,比如 {{ .Values.favorite.food | upper | quote }},會將values 文件里的food值pizza用upper函數全部轉成大寫PIZZA。
常用的一些函數/工具有:
quote : 引用,一般不做任何事,直接原樣輸出。
upper : 小寫轉大寫 {{ .Values.favorite.food | upper | quote }}
repeat 5 : 重復5次。{{ .Values.favorite.drink | repeat 5 | quote }}
title: 將首字母大寫
nindent 2:縮進2個字母,用於yaml文件格式化
b64enc:轉換成base-64
now:當前時間
htmlDate: 格式化時間為2016-11-02
default: default函數,設置默認值,{{ .Values.favorite.drink | default "tea" | quote }},如果vaules文件里不存在drink值,將采用默認值 “ tea ”。
- 操作表達式函數
eq,ne,lt,gt,and,or,not,跟shell中的含義差不多,結果返回一個boolean值(true/false)。
eq:相等
ne:不等
lt:小於
gt:大於
and :是否存在,存在則為true,否則為false
or : 不懂啥意思........ (Eric)
not: 非
- Flow control
- if/else
{{ if PIPELINE }}
# Do something
{{ else if OTHER PIPELINE }}
# Do something else
{{ else }}
# Default case
{{ end }}
例子:
{{ if and .Values.favorite.drink (eq .Values.favorite.drink "coffee") }}mug: true{{ end }},表達式含義為當 .Values.favorite.drinkc存在並且等於“coffee時”,在template里加入key值mug: true。
注意: 上面的例子是將一條語句放在一行里處理,如果需要將上面的語句進行格式化顯得更好看,就必須要注意由此而帶來的空格行。
{{if and .Values.favorite.drink (eq .Values.favorite.drink "coffee")}}
mug: true
{{end}}
此時渲染時就會發現報錯並且mug: true前后多出兩個空白行,正確處理方式為在大括號內加入一個 “ - ”,那么渲染時將會跳過該行。
{{- if and .Values.favorite.drink (eq .Values.favorite.drink "coffee")}}
mug: true
{{- end}}
- with
利用with函數來更改范圍,如果我們一直在values.yaml里取值,我們是不是一直要加上 ".Values.favorite"前綴給每一個值,為了能簡化這個步驟我們引入了with來處理相對路徑和絕對路徑。下面的例子就是在前面設置了scope為 .Values.favorite, 那么在 end 之前的左右值都會在 .Values.favorite 里取得所有值。
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
- range
foreach操作,以下例子就是從 Values.pizzaToppings里順序取出所有值並將首字母大寫。" toppings: |- "里的 " |- " 在yaml文件里表示有多行string值。range也可以用於map,dict,list,tuples等。
toppings: |-
{{- range .Values.pizzaToppings }}
- {{ . | title | quote }}
{{- end }}
渲染結果:
toppings: |-
- "Mushrooms"
- "Cheese"
- "Peppers"
- "Onions"
另外一種用法:
sizes: |-
{{- range tuple "small" "medium" "large" }}
- {{ . }}
{{- end }}
渲染結果:
sizes: |-
- small
- medium
- large
- 變量
我們當然也可以在template文件里定義變量供文件后面使用
{{- $relname := .Release.Name -}}
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ $relname }}
{{- end }}
或可以:
toppings: |-
{{- range $index, $topping := .Values.pizzaToppings }}
{{ $index }}: {{ $topping }}
{{- end }}
- Named templates
一般是以下划線 _ 開頭和以tpl為后綴作為我們的文件,類似於_helpers,tpl
我們在_helpers,tpl里定義了一個mychart.labels
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
在template里我們就可以直接引用
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" }}
渲染后的結果:
metadata:
name: running-panda-configmap
labels:
generator: helm
date: 2016-11-02
- 更多高級用法
從其他File中引用,在chart文件里建subchart等功能請見helm官方chart developing文檔(https://helm.sh/docs/chart_template_guide/#the-chart-template-developer-s-guide)。