概述
参考:Helm教程
简介
Helm 是 k8s 的包管理工具,类似 Linux 系统常用的 apt、yum 等包管理工具。使用 helm 可以简化 k8s 应用部署。
每个包称为一个 Chart,一个 Chart 是一个目录(一般情况下会将目录进行打包压缩,形成 name-version.tgz 格式的单一文件,方便传输和存储)。
对于应用发布者而言,可以通过 Helm 打包应用,管理应用依赖关系,管理应用版本并发布应用到软件仓库。
对于使用者而言,使用 Helm 后不用需要了解 Kubernetes 的 Yaml 语法并编写应用部署文件,可以通过 Helm 下载并在kubernetes上安装需要的应用。
除此以外,Helm 还提供了kubernetes上的软件部署,删除,升级,回滚应用的强大功能。
<br/>
组件及相关术语
Helm
Helm 是一个命令行下的客户端工具。主要用于 Kubernetes 应用程序 Chart 的创建、打包、发布以及创建和管理本地和远程的 Chart 仓库。
Tiller
Tiller 是 Helm 的服务端,部署在 Kubernetes 集群中。Tiller 用于接收 Helm 的请求,并根据 Chart 生成 Kubernetes 的部署文件( Helm 称为 Release ),然后提交给 Kubernetes 创建应用。Tiller 还提供了 Release 的升级、删除、回滚等一系列功能。
Chart
Helm 的软件包,采用 TAR 格式。其中包含了运行一个应用所需要的镜像、依赖和资源定义(YAML )等,还可能包含 Kubernetes 集群中的服务定义。类似 APT 的 DEB 包或者 YUM 的 RPM 包。
Repoistory
Helm 的软件仓库,Repository 本质上是一个 Web 服务器,该服务器保存了一系列的 Chart 软件包以供用户下载,并且提供了一个该 Repository 的 Chart 包的清单文件以供查询。Helm 可以同时管理多个不同的 Repository。首次安装 Helm 时,它已预配置为使用官方 Kubernetes chart 存储库 repo。该 repo 包含许多精心设计和维护的 charts。此 charts repo 默认以 stable 命名。
Release
使用 helm install
命令在 Kubernetes 集群中部署的 Chart 的一个实例称为 Release。在同一个集群上,一个 Chart 可以安装很多次。每次安装都会创建一个新的 release。例如一个 MySQL Chart,如果想在服务器上运行两个数据库,就可以把这个 Chart 安装两次。每次安装都会生成自己的 Release,会有自己的 Release 名称。
注:需要注意的是:Helm 中提到的 Release 和通常概念中的版本有所不同,这里的 Release 可以理解为 Helm 使用 Chart 包部署的一个应用实例。
<br/>
工作原理
Chart Install 过程:
- Helm 从指定的目录或者 tgz 文件中解析出 Chart 结构信息
- Helm 将指定的 Chart 结构和 Values 信息通过 gRPC 传递给 Tiller
- Tiller 根据 Chart 和 Values 生成一个 Release
- Tiller 将 Release 发送给 Kubernetes 用于生成 Release
Chart Update 过程:
- Helm 从指定的目录或者 tgz 文件中解析出 Chart 结构信息
- Helm 将要更新的 Release 的名称和 Chart 结构,Values 信息传递给 Tiller
- Tiller 生成 Release 并更新指定名称的 Release 的 History
- Tiller 将 Release 发送给 Kubernetes 用于更新 Release
Chart Rollback 过程:
- Helm 将要回滚的 Release 的名称传递给 Tiller
- Tiller 根据 Release 的名称查找 History
- Tiller 从 History 中获取上一个 Release
- Tiller 将上一个 Release 发送给 Kubernetes 用于替换当前 Release
<br/>
模版语法
表达式
- 模版表达式: {{ 模版表达式 }}
- 模版表达式: {{- 模版表达式 -}} , 表示去掉表达式输出结果前面和后面的空格。去掉前面空格可以这么写{{- 模版表达式 }},去掉后面空格 {{ 模版表达式 -}}
<br/>
变量
默认情况,点( . ) 代表全局作用域,用于引用全局对象。
例子:
# 这里引用了全局作用域下的Values对象中的key属性。
{{ .Values.key }}
<br/>
helm 全局作用域中有两个重要的全局对象:Values 和 Release
Values 代表的就是values.yaml定义的参数,通过 .Values 可以引用任意参数。
例子:
{{ .Values.replicaCount }}
# 引用嵌套对象例子,跟引用json嵌套对象类似
{{ .Values.image.repository }}
Release 代表一次应用发布,下面是Release对象包含的属性字段:
- Release.Name :release的名字,一般通过Chart.yaml定义,或者通过helm命令在安装应用的时候指定。
- Release.Time :release安装时间
- Release.Namespace :k8s名字空间
- Release.Revision :release版本号,是一个递增值,每次更新都会加一
- Release.IsUpgrade :true代表,当前release是一次更新
- Release.IsInstall :true代表,当前release是一次安装
例子:
{{ .Release.Name }}
<br/>
除了系统自带的变量,也可以自定义模版变量。
\# 变量名以 $ 开始命名, 赋值运算符是 := (冒号+等号)
{{- $relname := .Release.Name -}}
引用自定义变量:
# 不需要 . 引用
{{ $relname }}
<br/>
函数&管道运算符
(1)调用函数的语法:{{ functionName arg1 arg2... }}
例子:
# 调用quote函数:将结果用“”引号包括起来。
{{ quote .Values.favorite.food }}
<br/>
(2)管道(pipelines)运算符 |
类似linux shell命令,通过管道 | 将多个命令串起来,处理模版输出的内容。
例子:
# 将.Values.favorite.food传递给quote函数处理,然后在输出结果。
{{ .Values.favorite.food | quote }}
# 先将.Values.favorite.food的值传递给upper函数将字符转换成大写,然后专递给quote加上引号包括起来。
{{ .Values.favorite.food | upper | quote }}
# 如果.Values.favorite.food为空,则使用default定义的默认值
{{ .Values.favorite.food | default "默认值" }}
# 将.Values.favorite.food输出5次
{{ .Values.favorite.food | repeat 5 }}
# 对输出结果缩进2个空格
{{ .Values.favorite.food | nindent 2 }}
(3)常用的关系运算符>、 >=、 <、!=、与或非在helm模版中都以函数的形式实现。
关系运算函数定义:
eq 相当于 =
ne 相当于 !=
lt 相当于 <=
gt 相当于 >=
and 相当于 &&
or 相当于 ||
not 相当于 !
例子:
# 相当于 if (.Values.fooString && (.Values.fooString == "foo"))
{{ if and .Values.fooString (eq .Values.fooString "foo") }}
{{ ... }}
{{ end }}
流程控制语句:IF/ELSE、with、range
(1)IF/ELSE
语法:
{{ if 条件表达式 }}
Do something
{{ else if 条件表达式 }}
Do something else
{{ else }}
Default case
{{ 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}}
<br/>
(2)with
with 主要就是用来修改 . 作用域的,默认 . 代表全局作用域,with 语句可以修改.的含义.
语法:
{{ with 引用的对象 }}
这里可以使用 . (点), 直接引用with指定的对象
{{ end }}
例子:
# .Values.favorite是一个object类型
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }} #相当于.Values.favorite.drink
food: {{ .food | upper | quote }}
{{- end }}
ps:不能在with作用域内使用 . 引用全局对象, 如果非要在with里面引用全局对象,可以先在with外面将全局对象复制给一个变量,然后在with内部使用这个变量引用全局对象。
例子:
{{- $release:= .Release.Name -}} #先将值保存起来
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }} #相当于.Values.favorite.drink
food: {{ .food | upper | quote }}
release: {{ $release }} #间接引用全局对象的值
{{- end }}
<br/>
(3)range
range 主要用于循环遍历数组类型。
语法1:
# 遍历map类型,用于遍历键值对象
# 变量key代表对象的属性名,val代表属性值
{{- range key,val := 键值对象 }}
{{ $key }}: {{ $val | quote }}
{{- end}}
语法2:
{{- range 数组 }}
{{ . | title | quote }} # . (点),引用数组元素值。
{{- end }}
例子:
# values.yaml定义
# map类型
favorite:
drink: coffee
food: pizza
# 数组类型
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
# map类型遍历例子:
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end}}
# 数组类型遍历例子:
{{- range .Values.pizzaToppings}}
{{ . | quote }}
{{- end}}
子模版定义
可以在 _(下划线) 开头的文件中定义子模版,方便后续复用。
helm create 默认创建了 _helpers.tpl 公共库定义文件,可以直接在里面定义子模版,也可以新建一个,只要以下划线开头命名即可。
子模版语法:
# 定义模版
{{ define "模版名字" }}
模版内容
{{ end }}
# 引用模版
{{ include "模版名字" 作用域}}
例子:
# 模版定义
{{- define "mychart.app" -}}
app_name: {{ .Chart.Name }}
app_version: "{{ .Chart.Version }}+{{ .Release.Time.Seconds }}"
{{- end -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ include "mychart.app" . | nindent 4 }} #引用mychart.app模版内容,并对输出结果缩进4个空格
data:
myvalue: "Hello World"
调试
编写好 chart 包的模版之后,我们可以给helm命令加上--debug
--dry-run
两个参数,让 helm 输出模版结果,但是不把模版输出结果交给k8s处理。
例子:
# helm install命令类似,加上--debug --dry-run两个参数即可
$ helm upgrade --debug --dry-run -i set replicas=2 --set host=www.xxxx.com myapp ./myapp
<br/>
常用命令
多用可选参数-h
或--help
,查看命令详解
chart 实例管理
chart 实例的查看、创建、删除
# 查看chart实例列表
$ helm list
# 查看全部的chart实例(包括删除的)
helm list -a
# 列出已经删除的Release
helm ls --deleted
# 查看指定的chart实例信息
$ helm status RELEASE_NAME [flags]
# 创建chart实例部署到k8s
$ helm install chart包 [flags]
# 常用可选参数:
--name str # 指定helm实例名称
--namespace str # 指定安装的namespace。不指定则默认命名空间
--version str # 指定charts版本
-f values.yaml # 从文件读取自定义属性集合
--set "key=value" # 通过命令方式注入自定义参数,用于覆盖values.yaml定义的值
# 对象类型数据可以用 . (点)分割属性名。示例: --set apiApp.requests.cpu=1
# 可以使用多个 --set 指定多个参数
# 示例
helm install --name test --namespace test ./helm-chart
# 删除chart实例(注意:若不加purge参数,则并没有彻底删除)
$ helm delete RELEASE_NAME [flags]
# 选项:
--purge # 彻底删除实例,并释放端口
# 示例:
helm delete --purge RELEASE_NAME
<br/>
chart 实例的更新、回滚
# 更新chart实例。默认情况下,如果chart实例名不存在,则upgrade会失败
$ helm upgrade [选项] 实例名称 [chart包目录] [flags]
# 选项:
-i # 实例名存在则更新,不存在时则安装(合并了install和uprade命令功能)
--set "key=value" # 通过命令方式注入自定义参数
# 示例:根据chart包更新chart实例
helm upgrade myapp ./myapp
helm upgrade -i myapp ./myapp
# 示例:使用–set参数更新chart实例
helm upgrade --set replicas=2 --set host=www.xxxx.com myapp
# 查看chart实例的版本信息
$ helm history HELM_NAME [flags]
# 回滚chart实例的指定版本
$ helm rollback HELM_NAME [REVISION] [flags]
<br/>
charts 包管理
charts 包的搜索、展示、下载
# 在Artifact Hub或自己的hub实例中搜索Helm charts
$ helm search hub [KEYWORD] [flags]
# 搜索系统上配置的所有仓库,并查找匹配
$ helm search repo [keyword] [flags]
# 说明:
[KEYWORD] # 参数接受关键字字符串或者带引号的查询字符串
# 显示指定chart包(目录、文件或URL)中的Charts.yaml文件内容
$ helm show chart [CHART] [flags]
# 显示指定chart(目录、文件或URL)中的README文内容
$ helm show readme [CHART] [flags]
# 显示指定chart(目录、文件或URL)包中的values.yaml文件内容
$ helm show values [CHART] [flags]
# 显示指定chart(目录、文件或URL)中的所有的内容(values.yaml, Charts.yaml, README)
$ helm show all [CHART] [flags]
# 从包仓库中检索包并下载到本地
$ helm pull [chart URL | repo/chartname] [...] [flags]
# 下载charts到本地
$ helm fetch redis
<br/>
自定义 charts 包
# 创建charts包
$ helm create NAME [flags]
# 选项:
-p, --starter string # 名称或绝对路径。
# 如果给定目录路径不存在,Helm会自动创建。
# 如果给定目录存在且非空,冲突文件会被覆盖,其他文件会被保留。
# 检查chart语法正确性
$ helm lint myapp
# 打包成一个chart版本包文件。
$ helm package [CHART_PATH] [...] [flags]
# 查看生成的yaml文件
$ helm template myapp-1.tgz
<br/>
helm 仓库管理:helm repo
仓库的列表、添加、删除、更新和索引
语法:
$ helm repo COMMAND [flags]
从父命令继承的可选参数:
--debug 启用详细输出
--kube-apiserver string Kubernetes-API服务器的地址和端口
--kube-as-group stringArray Kubernetes操作的组,可以重复此标志以指定多个组。
--kube-as-user string Kubernetes操作的用户名
--kube-ca-file string Kubernetes-API服务器连接的认证文件
--kube-context string kubeconfig context的名称
--kube-token string 用于身份验证的字符串令牌
--kubeconfig string kubeconfig文件的路径
-n, --namespace string 该请求的作用域的命名空间名称
--registry-config string 注册表配置文件的路径 (default "~/.config/helm/registry.json")
--repository-cache string 包含缓存库索引的文件的路径 (default "~/.cache/helm/repository")
--repository-config string 包含仓库名称和url的文件的路径 (default "~/.config/helm/repositories.yaml")
常用命令
# 查看chart仓库列表
$ helm repo list [flags]
# 选项:
-o, --output format :打印指定格式的输出。支持的格式:table, json, yaml (default table)
# 从chart仓库中更新本地可用chart的信息
$ helm repo update [flags]
# 读取当前目录,并根据找到的chart为chart仓库生成索引文件(index.yaml)。
$ helm repo index
# 选项
--merge string # 合并生成的索引到已经存在的索引文件
--url string # chart仓库的绝对URL
# 添加chart仓库
$ helm repo add [NAME] [URL] [flags]
$ helm repo add myharbor https://harbor.qing.cn/chartrepo/charts --username admin --password password
# 删除一个或多个仓库
$ helm repo remove [REPO1 [REPO2 ...]] [flags]
<br/>
其他命令
helm dependency:管理chart依赖
# 列举所有的chart中声明的依赖
helm dependency list
# 列举指定chart的依赖
helm dependency list CHART [flags]
# 查看helm版本
$ helm version
# 打印所有Helm使用的客户端环境信息
$ helm env [flags]
<br/>
基本使用
这里以制作一个简单的网站应用chart包为例子介绍helm的基本用法。
ps: 这里跳过docker镜像制作过程,镜像制作可以参考:Docker基础教程
<br/>
1.创建chart包
通过 helm create 命令创建一个新的 chart 包
例子:
# 在当前目录创建一个myapp chart包
$ helm create myapp
创建完成后,得到的目录结构如下:
myapp - chart 包目录名
├── charts - 依赖的子包目录,里面可以包含多个依赖的chart包
├── Chart.yaml - chart定义,可以定义chart的名字,版本号信息
├── templates - k8s配置模版目录,编写的k8s配置都在这个目录
│ │ 除了NOTES.txt和下划线开头命名的文件,其他文件可以随意命名
│ ├── deployment.yaml
│ ├── _helpers.tpl - 下划线开头的文件,helm视为公共库定义文件,主要用于定义通用的子模版、函数等
│ │ helm不会将这些公共库文件的渲染结果提交给k8s处理
│ ├── ingress.yaml
│ ├── NOTES.txt - chart包的帮助信息文件,执行helm install命令安装成功后会输出这个文件的内容
│ └── service.yaml
└── values.yaml - chart包的参数配置文件,模版可以引用这里参数
要在k8s中部署一个网站应用,需要编写 deployment、service、ingress 三个配置文件,刚才通过 helm create 命令已经创建好了。
<br/>
2.编写k8s应用部署配置文件
为了演示chart包模版的用法,先把deployment、service、ingress 三个配置文件的内容清空,重新编写k8s部署文件。
deployment.yaml 配置文件定义如下:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: myapp #deployment应用名
labels:
app: myapp #deployment应用标签定义
spec:
replicas: 1 #pod副本数
selector:
matchLabels:
app: myapp #pod选择器标签
template:
metadata:
labels:
app: myapp #pod标签定义
spec:
containers:
- name: myapp #容器名
image: xxxxxx:1.7.9 #镜像地址
ports:
- name: http
containerPort: 80
protocol: TCP
service.yaml 定义如下:
apiVersion: v1
kind: Service
metadata:
name: myapp-svc #服务名
spec:
selector: #pod选择器定义
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
ingress.yaml 定义如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myapp-ingress #ingress应用名
spec:
rules:
- host: www.xxxxx.com #域名
http:
paths:
- path: /
backend:
serviceName: myapp-svc #服务名
servicePort: 80
3.提取 k8s 应用部署配置文件中的参数,作为 chart 包参数。
定义的 k8s 配置文件还不能称之为模版,都是固定的配置。(这里所说的模版就类似大家平时做前端开发的时候用的模版技术是一个概念)
通过提取配置中的参数,注入模版变量,模版表达式将配置文件转化为模版文件,helm在运行的时候根据参数动态的将模版文件渲染成最终的配置文件。
下面将 deployment、service、ingress 三个配置文件转换成模版文件。
deployment.yaml 配置模版如下:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ .Release.Name }} #deployment应用名
labels:
app: {{ .Release.Name }} #deployment应用标签定义
spec:
replicas: {{ .Values.replicas}} #pod副本数
selector:
matchLabels:
app: {{ .Release.Name }} #pod选择器标签
template:
metadata:
labels:
app: {{ .Release.Name }} #pod标签定义
spec:
containers:
- name: {{ .Release.Name }} #容器名
image: {{ .Values.image }}:{{ .Values.imageTag }} #镜像地址
ports:
- name: http
containerPort: 80
protocol: TCP
service.yaml 定义如下:
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-svc #服务名
spec:
selector: #pod选择器定义
app: {{ .Release.Name }}
ports:
- protocol: TCP
port: 80
targetPort: 80
ingress.yaml 定义如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ .Release.Name }}-ingress #ingress应用名
spec:
rules:
- host: {{ .Values.host }} #域名
http:
paths:
- path: /
backend:
serviceName: {{ .Release.Name }}-svc #服务名
servicePort: 80
values.yaml chart 包参数定义:
#域名
host: www.XXX.com
#镜像参数
image: XXXXXXXXXXXXXXXXXX
imageTag: 1.7.9
#pod 副本数
replicas:1
4.通过helm命令安装/更新应用
安装应用:
$ helm install ./myapp
通过命令注入参数
$ helm install --set replicas=2 --set host=www.xxxx.com ./myapp
更新应用:
# 命令格式: helm upgrade release名字 chart包目录
$ helm upgrade myapp ./myapp
# 也可以指定–set参数
$ helm upgrade --set replicas=2 --set host=www.xxxx.com myapp ./myapp
# 默认情况下,如果release名字不存在,upgrade会失败
# 可以加上-i 参数当release不存在的时候则安装,存在则更新,将install和uprade命令合并
$ helm upgrade -i --set replicas=2 --set host=www.xxxx.com myapp ./myapp