k8s包管理器helm_kubernetes包管理神器-Helm
在我們學習 kubernetes 的過程中,用的最多的是 kubectl 命令行工具,使用 kubectl 工具需要我們編寫好各種部署文件,這在生產中是非常不方便的,因此 Helm 這個 kubernetes 包管理工具就應運而生了。
Helm 包管理工具不僅可以為我們安裝網上已經成熟的部署庫文件,而且可以生產本地部署模板,我們只需要簡單改一改,就可以完成一個應用的部署,不需要我們記住那么多的命令和配置。下面我們就看一下 Helm 的使用。
Helm V2/V3 的對比
組件架構對比:
工作原理對比:
Helm 安裝的 Chart 的元信息記錄到k8s的secret里面,secret名字叫sh.helm.release.v1.${NAME}.v1,另外還有一個serviceaccount,名字叫${NAME}-${CHART名}。helm list命令讀取secret才知道安裝了哪些包。
Helm 主要模塊
安裝 Helm
因為 helm3 只有一個二進制文件,因此安裝非常簡單
# 二進制下載地址頁面: https://github.com/helm/helm/releaseswget https://get.helm.sh/helm-v3.4.1-linux-amd64.tar.gztar zxf helm-v3.4.1-linux-amd64.tar.gzcp linux-amd64/helm /usr/local/bin/helm ?source添加倉庫
命令自動補全,在 /etc/profile 里面增加如下內容:
helm 和 docker 一樣有默認的官方倉庫,也可以添加第三方倉庫和本地倉庫
helm repo add bitnami https://charts.bitnami.com/bitnamihelm repo add stable https://mirror.azure.cn/kubernetes/chartshelm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/chartshelm repo list更新倉庫緩存(helm repo add的時候會獲取一次chart列表并緩存,接下來的helm search都是讀取本地緩存列表,因此我們需要經常更新緩存)
查看添加了哪些倉庫
helm repo update移除倉庫
helm repo remove $倉庫名安裝應用
以安裝 nginx 為例
# 從官方hub搜索helm search hub nginx# 從所有添加的第三方倉庫中搜索,支持模糊匹配helm search repo nginx# 搜索指定倉庫的應用(并沒有原生支持,是因為格式都是"倉庫名/chart名",所以可以通過"倉庫名/"來匹配)helm search repo bitnami/ | grep nginx我們安裝bitnami倉庫的nginx,并指定release名字為myweb
helm install myweb bitnami/nginx如果要指定命名空間,則加上-n參數
helm install myweb bitnami/nginx -n kube-system查看安裝了哪些庫
helm list --all-namespaces自定義參數
helm支持兩種自定義參數的方式
如果兩種同時使用的話,--set的優先級要高于values.yaml,我們可以通過以下命令來查看一個chart支持哪些配置參數
helm show values 倉庫名/應用名helm show values bitnami/nginx- 使用values.yaml自定義參數來安裝
- 使用--set自定義參數來安裝
查看我們在某個chart中自定義了哪些參數
helm get values myweb升級應用
假設要擴容cpu、memory,則修改values.yaml內容,改為
resources: limits: ? cpu: 1000m ? memory: 512Mi requests: ? cpu: 1000m ? memory: 512Mi升級命令
helm upgrade -f values.yaml myweb bitnami/nginx應用回滾
回滾前先查看歷史版本
helm history myweb獲得REVISION號后就可以進行回滾操作
helm rollback myweb 2卸載應用
卸載并保留歷史記錄,加上--keep-history(不影響卸載應用,但會保留記錄)
helm uninstall myweb1 --keep-history查看卸載過哪些應用(只有保留記錄的才能看到)
helm list --uninstalled --all-namespacesChart 目錄結構
如果我們不能聯網,那么也可以通過helm創建一個本地chart
helm create foofoo目錄結構如下:
├── .helmignore ? # 編譯包的時候忽略哪些文件├── Chart.yaml ? # chart信息,包括chart版本、app版本、描述等├── charts ? ? ? # 放置依賴和子chart├── values.yaml ? # 模版的默認參數└── templates ? ? # 存放模版 ? ├── deployment.yaml ? ? # k8s deployment模版 ? ├── _helpers.tpl ? ? ? ? # 定義命名模版(即變量),可在模版里引用,類似編程時候定義一個變量,模版里就可以引用這個變量 ? ├── hpa.yaml ? ? ? ? ? ? # k8s HPA模版 ? ├── ingress.yaml ? ? ? ? # k8s ingress模版 ? ├── NOTES.txt ? ? ? ? ? # 展示在helm install安裝完成后看到的NOTES部分,同樣支持模版語法 ? ├── serviceaccount.yaml ? # k8s serviceaccount模版 ? ├── service.yaml ? ? ? ? # k8s service模版 ? └── tests ? ? ? ? ? ? ? # 用于測試release是否運行成功 ? ? ? └── test-connection.yaml ? # k8s對象,默認是busybox Pod,通過wget測試nginxtemplates目錄里下劃線開頭的不會被渲染,tests用于安裝完成后,執行檢測
測試用例
helm也支持測試用例,例如對于web應用,可以測試http接口是否為200。
那么如何讓helm認為是測試使用:helm會讀取templates下所有yaml,當metadata帶有如下注解時,helm則認為這是測試專用,而不是普通對象。注意,helm不會去認名字為tests的目錄,只會認注解,因此如果tests下放置沒有注解的k8s對象時會被當作普通對象對待
annotations: "helm.sh/hook": testhelm install安裝后不會自動進行測試,需要手工執行helm test命令,此時會創建k8s對象(如pod)進行測試,若pod執行完畢(狀態為Completed,即容器里的程序退出碼為0則表示成功)
helm install myfoo foohelm test myfoo如果Phase顯示Successed表示成功,檢測失敗則為Failed
Chart 的依賴和父子關系
簡介
什么是chart依賴:如果將chart比作rpm包,則chart依賴也相當于rpm包的依賴,當yum install時候會自動安裝依賴包。對于helm來說,chart依賴就是在Chart.yaml里設置依賴dependencies哪些倉庫的哪些chart,在helm intall時候就會自動把依賴的chart下載到charts目錄。也可以手工把依賴包下載下來放到charts目錄里。
什么是父子chart:下載、手工放到charts目錄里的chart就是子chart,根目錄的chart就是父chart。無論是否在Values.yaml里設置了dependencies。
簡單來講:
- 子Chart
- Chart依賴
處理chart依賴的2種方式
- 嵌入式
- 依賴導入式
Chart依賴
我們來測試一下Chart的依賴,首先準備測試環境
mkdir chartcd charthelm create webhelm create backendcd web編輯Chart.yaml,增加如下內容
dependencies:- name: backend repository: file://../backend version: 0.1.0- name: mariadb repository: https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts/ version: 2.1.6file://是使用本地目錄,但是只能用于外部目錄,不能用于當前目錄下的自定義子目錄,比如
file://foo 或 file://charts/foo# 都會提示錯誤處理依賴
helm dependency listhelm dependency update查看charts目錄,應當有2個tgz
另外,除了update,還有build命令
helm dependency buildbuild和update的區別是- update:重新讀取Chart.yaml來獲取依賴包
- build:要先執行過update才能執行build,否則會提示Chart.lock和Chart.yaml不同步,請先update
父子Chart
怎么確定Chart的父子關系,我們看以下的例子:
helm create foocd foocd chartshelm create bar如果我們把子Chart放到外部目錄,然后通過file://../bar或者其他方式引用,那么就成了依賴,而不是父子子Chart如果沒寫到Chart.yaml里面,在查看依賴時候會提示WARNING: "charts/foo" is not in Chart.yaml.,但不影響使用在Chart包foo的子目錄charts下創建新的Chart包bar,foo就是父,bar就是子
Helm模板詳解
模板基本使用
使用模板的含義就是要創建一個通用的Chart。如果不用模版,就需要為每個應用創建獨立的deployment、service等資源對象,那么此時用helm的意義就不大,可以看下面的例子:
helm create mychartcd mychartrm -rf templates/*cd templatesapiVersion: apps/v1kind: Deploymentmetadata: labels: app: mydep name: mydepspec: replicas: 2 selector: matchLabels: app: mydep template: metadata: labels: app: mydep spec: containers: - image: nginx imagePullPolicy: IfNotPresent name: nginxapiVersion: v1kind: Servicemetadata: labels: app: mydep name: mysvcspec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: mydep type: NodePort測試
kubectl apply -f . # 此時與helm無關或helm install myapp ../ ? # 此時雖然放在模版目錄里,但實際上不是模版,因為沒用到任何模版標簽。Helm模版,支持很多特性,使用起來非常靈活,本質是基于golang內置的text/template模塊。如果想在Chart安裝前查看模板渲染后的內容,有2種辦法
helm template release名 chart名/目錄helm install --dry-run release名 chart名/目錄上面自定義參數提到的2種方法,也可以用在helm template
helm template -f values.yaml foohelm template --set 'aa=bb' foohelm template foo上面命令的前提是當前目錄下有一個foo目錄,如果想看倉庫里的,帶上倉庫名即可
helm template bitnami/nginxhelm template查看的是尚未安裝成release的yaml,而不是已經安裝成為release的yaml。如果安裝后查看yaml的命令是
helm get manifest RELEASE名模板標簽
模板標簽:{{}},例如
{{ .Release.Name }}測試
helm create foorm -rf foo/templates/*cat > foo/templates/a.yaml <加上 # 的原因是此時的a.yaml不是合法的k8s資源對象格式
可以看出.Release.Name渲染成了release名,如果想要查看所有的變量/常量
#{{ . }}模板注釋
模板中的注釋有2種
- yaml的注釋
- 模板的注釋
yaml注釋
# This is a commenttype: sprocket模板注釋
單行{{/* a comment */}}多行{{/*This is a comment*/}}或{{- /*This is a comment*/}}內置對象
常用的模版內置對象可查看官方文檔
- Release: 該對象描述了版本發布本身。包含了以下對象:
- Values: Values是從文件和用戶提供的文件傳進模板的。默認為空values.yaml``Values
- Chart:文件內容。 里的任意數據在這里都可以可訪問的。比如 會打印出 Chart.yaml``Chart.yaml``{{ .Chart.Name }}-{{ .Chart.Version }}``mychart-0.1.0Chart 指南 中列出了可用字段
- Files: 在chart中提供訪問所有的非特殊文件。當你不能使用它訪問模板時,你可以訪問其他文件。 請查看這個文件訪問部分了解更多信息Files.Get 通過文件名獲取文件的方法。 .Files.Getconfig.iniFiles.GetBytes 用字節數組代替字符串獲取文件內容的方法。 對圖片之類的文件很有用Files.Glob 用給定的shell glob模式匹配文件名返回文件列表的方法Files.Lines 逐行讀取文件內容的方法。迭代文件中每一行時很有用Files.AsSecrets 使用Base 64編碼字符串返回文件體的方法Files.AsConfig 使用YAML格式返回文件體的方法
- Capabilities: 提供關于Kubernetes集群支持功能的信息Capabilities.APIVersions 是一個版本集合Capabilities.APIVersions.Has $version 說明集群中的版本 (e.g., ) 或是資源 (e.g., ) 是否可用batch/v1``apps/v1/DeploymentCapabilities.KubeVersion 和 是Kubernetes的版本號Capabilities.KubeVersion.VersionCapabilities.KubeVersion.Major Kubernetes的主版本Capabilities.KubeVersion.Minor Kubernetes的次版本
- Template: 包含了已經被執行的當前模板信息Template.Name: 當前模板的命名空間文件路徑 (e.g. mychart/templates/mytemplate.yaml)Template.BasePath: 當前chart模板目錄的路徑 (e.g. mychart/templates)
模板函數
使用函數有2種寫法:函數名前置和管道,效果是相同的,管道主要用于組合多個函數使用
{{ quote .Release.Name }}{{ .Release.Name | quote }}{{ quote .Release.Name | b64enc }}quote:雙引號
helm內置很多模版函數,這里無法一一列舉,因此選取幾個常用來說明
{{ quote .Release.Name }}default:默認值
# 當找不到.Values.hello時默認為world{{ default "world" .Values.hello }}indent:縮進
{{ indent 4 .Values.hello }}# 注意,hello必須是string,如果是數字,則報錯,此時可以結合quote{{ quote .Values.hello | indent 4 }}nindent:先換行,再縮進,并且只能處理字符串,而且不能用#
ReleaseName: {{ indent 2 .Release.Name }}ReleaseNamespace: {{ nindent 2 .Release.Namespace }}replicaCount: {{ quote .Values.replicaCount | nindent 2 }}title:首字母大寫
{{ title .Release.Name }}upper:全部大寫
{{ upper .Release.Name }}b64enc:base64編碼
{{ b64enc .Release.Name }}b64dec:base64解碼
{{ b64dec .Release.Name }}條件判斷if
if/else
{{ if PIPELINE }} ?# Do something{{ else if OTHER PIPELINE }} ?# Do something else{{ else }} ?# Default case{{ end }}if如何判斷條件是否為假
- 布爾值false
- 數字0
- 空字符串""
- 不存在的變量/常量,如.Values.xxx(假設xxx不存在)
- 空集合(map, slice, tuple, dict, array),如values.yaml里有imagePullSecrets: []
除此之外其他條件都為真
示例如下:
{{ if false }}{{ if 0 }}{{ if "" }}{{ if .Values.xxx }}{{ if .Values.imagePullSecrets }}字符串/數字大小 比較
- eq:字符串相同/數字相同
- ne:字符串不同/數字不同
- lt:字符串(根據編碼)前者小于后者/數字前者小于后者
- le:字符串(根據編碼)前者小于等于后者/數字前者小于等于后者
- gt:字符串(根據編碼)前者大于后者/數字前者大于后者
- ge:字符串(根據編碼)前者大于等于后者/數字前者大于等于后者
數字比較,要用float64格式,即帶小數點的
示例如下:
{{ if eq 5 5 }}{{ if eq "5" "5" }}{{ if gt "a" "b" }}{{ if gt .Values.replicaCount 2.0 }}空白符
foo: 123{{ if eq 2 2 }}aa: 11{{ else }}aa: 22{{ end }}bar: 456遍歷with/range
with:用于map結構
假設values.yaml里有這么一段
aa: xx: 123 yy: 456用with省去了.Values
{{- with .Values.aa }}aa: xx: {{ .xx }} yy: {{ .yy }}{{- end }}可以用toYaml函數進一步簡寫
{{- with .Values.aa }}aa: ?{{- toYaml . | nindent 2 }}{{- end }}range
和with很像,更適合數組而不是map(即hash),因為range會自動將map結構中的value獲取出來(忽略key)
data:{{- range .Values.aa }}- {{ . }}{{- end }}渲染為如下,可以看到少了key
data: 123 456因此range更適合數組,假設values.yaml有一段
bb:- 123- 456示例如下:
data:{{- range .Values.bb }}- {{ . }}{{- end }}with里不能用變量
假設values.yaml
aa: xx: 123 yy: 456模板
{{- with .Values.aa }}aa: xx: {{ .Release.Name }} yy: {{ .yy }}{{- end }}會報錯,因為用了with后,.Release.Name變成是從with .Values.aa里找,當然找不到。有2個解決辦法:
變量賦值
{{- $releaseName := .Release.Name }}{{- with .Values.aa }}aa: xx: {{ $releaseName }} yy: {{ .yy }}{{- end }}用$符號:$.Release.Name
{{- with .Values.aa }}aa: xx: {{ $.Release.Name }} yy: {{ .yy }}{{- end }}range獲取鍵值
data:{{- range $k, $v := .Values.aa }}- name: {{ $k }} value: {{ $v | quote }}{{- end }}命名模板
使用define函數定義命名模板,使用template函數引用命名模板
# 定義{{- define "aa" }}...{{- end }}# 引用{{ template "aa" }}可以寫在templates的yaml里也可以寫在_helper.tpl(templates目錄里)作為全局使用
- 直接寫在templates的yaml里
- 寫在_helper.tpl里
上述2種方法輸出結果都是
kind: ConfigMapdata:- name: abc value: 123- name: def value: 456template函數不支持管道
{{- define "aaa" -}}bbb{{- end }}xx: {{ template "aaa" | quote }}會報錯,解決辦法:改用include函數
{{- define "aaa" -}}bbb{{- end }}xx: {{ include "aaa" . | quote }}變量/常量/作用域
變量
_helpers.tpl里的{{- define ... -}}常量
- yaml語法自帶的節點定位(Node Anchor)
- 常量:values.yaml里定義的replicaCount: 1
共享常量
- 子chart和父chart之間的常量不能共享,如果需要共享,就需要共享常量,這定義在父chart中
父chart的values.yaml里加入
子chart名: replicaCount: 2注意必須是子chart名,即charts目錄里存在該名字
接下來,子chart的模板里就可以引用
{{ .Values.replicaCount }}當helm發現節點名是子chart名時,它會自動拷貝這個常量到子chart的values.yaml中
全局常量
- 共享常量只能把常量共享給一個子chart,如果需要多個子chart之間共享,需要全局常量。在父chart的values.yaml里用global標識
父chart的values.yaml里加入
global: hello: world父和子chart的模板里都可以引用
{{ .Values.global.hello }}搭建私有倉庫
安裝push插件
yum install githelm plugin install https://github.com/chartmuseum/helm-push # 比較慢,耐心等# 如果上面覺得比較慢,可以下載離線寶# tar zxf helm-push-v0.9.0-allinone.tgz# helm plugin install helm-pushhelm push --help # 新增的push子命令ChartMuseum
官方提供的私有倉庫,功能較少,適合學習測試使用,類似docker的registry
# https://chartmuseum.com/docs/docker run --rm -tid -p 8080:8080 -v $(pwd)/charts:/charts -e DEBUG=true -e STORAGE=local -e STORAGE_LOCAL_ROOTDIR=/charts chartmuseum/chartmuseum:latestchmod 777 charts上傳chart方法1:chartmuseum專屬方法,不通用
curl --data-binary "@mychart-0.1.0.tgz" http://localhost:8080/api/charts上傳chart方法2:使用push插件(要先添加倉庫)
helm repo add chartmuseum http://localhost:8080helm push foo chartmuseum查詢有哪些chart
curl http://localhost:8080/api/charts # 僅chartmuseum支持curl http://localhost:8080/index.yaml # 通用,helm repo add讀取的是這個文件,helm search repo 是讀取緩存到本地的index.yaml下載chart
helm pull chartmuseum/mychartHarbor
harbor內置集成了chartmuseum
wget https://github.com/goharbor/harbor/releases/download/v2.1.0/harbor-offline-installer-v2.1.0.tgztar zxf harbor-offline-installer-v2.1.0.tgzcd harborcp harbor.yml.tmpl harbor.yml編輯harbor.yml ?1. 將hostname的值改為服務器IP,例如192.168.36.128,如果改成域名,要能解析 ?2. 注釋https部分 ?# 要在/etc/docker/daemon.json里增加insecure-registries ?3. data_volume改為/data/harbormkdir -p /data/harbor./install.sh --with-chartmuseum在harbor上配置
- 創建用戶,假設為user1
- 創建私有項目,假設為helm
- 將user1添加到helm項目里
添加倉庫
helm repo add myharbor http://192.168.36.128/chartrepo/helm --username user1上傳chart并查看
輸入密碼后,成功的話會提示"myharbor" has been added to your repositories
helm push mychart-0.1.0.tgz myharbor# 此時harbor頁面上可以看到新增了mycharthelm repo updatehelm search repo myharbor/下載chart
helm pull myharbor/mycharthelm pull myharbor/mychart --version 0.1.0生產環境最佳實踐
建議1:參數名要統一,尤其在一個團隊里。例如表示deployment副本數,不要有的用replicas,有的用replicaCount
建議2:給參數加注釋。因為chart寫好后很少需要改動,時間長了容易忘。
建議3:針對不同環境(開發/測試/生產),創建不同的values.yaml,如values-dev.yaml、values-production.yaml
建議4:創建values.schema.json來校驗values
其中第4點例子如下,假設values.yaml里有如下內容
image: repository: my-docker-image pullPolicy: IfNotPresent- 要求image參數必須存在,要求image必須存在repository和pullPolicy
- repository類型為字符串,值的格式為小寫字母a-z、數字0-9、橫線-、下劃線_
- pullPolicy類型為字符串,值只能有3種:Always、Never、IfNotPresent
在同級目錄下創建values.schema.json,內容如下
{ "$schema": "http://json-schema.org/schema#", "type": "object", "required": [ ? "image" ], "properties": { ? "image": { ? ? "type": "object", ? ? "required": [ ? ? ? "repository", ? ? ? "pullPolicy" ? ? ], ? ? "properties": { ? ? ? "repository": { ? ? ? ? "type": "string", ? ? ? ? "pattern": "^[a-z0-9-_]+$" ? ? ? }, ? ? ? "pullPolicy": { ? ? ? ? "type": "string", ? ? ? ? "pattern": "^(Always|Never|IfNotPresent)$" ? ? ? } ? ? } ? } }}執行helm install、helm upgrade、helm lint、helm template測試,若不滿足如上3點要求,則應當報錯。
建議5:在chart目錄下放置README.md,將chart的設計思想、注意事項寫清楚,推薦格式如下
# chart名## 一鍵安裝命令(helm repo add、helm intall)## 介紹## 環境要求## 安裝chart## 卸載chart## 參數### global參數### common參數### 父chart參數### 子chart參數### 注意事項## 參考文檔## CHANGELOG建議6:templates里的NOTES.txt是部署完成后看到的內容,針對不同條件設置輸出
建議7:helm默認讀取/root/.kube/config,但這樣權限過大,很不安全,而且helm通常是由開發或CD系統來使用,因此需要提前在K8S的RBAC里創建分配好權限,只允許在指定的namespace里進行部署
建議8:不要把各種微服務集中于一個chart,可以采用父子chart方式,讓每個chart更輕量
總結
以上是生活随笔為你收集整理的k8s包管理器helm_kubernetes包管理神器-Helm的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: stm32气压传感器 带探头的_ST S
- 下一篇: unity人物旋转移动代码_游戏诞生之日