Helm简介
很多人都使用过Ubuntu下的ap-get或者CentOS下的yum, 这两者都是Linux系统下的包管理工具。采用apt-get/yum,应用开发者可以管理应用包之间的依赖关系,发布应用;用户则可以以简单的方式查找、安装、升级、卸载应用程序。
我们可以将Helm看作Kubernetes下的apt-get/yum。Helm是Deis (https://deis.com/) 开发的一个用于kubernetes的包管理器。每个包称为一个Chart,一个Chart是一个目录(一般情况下会将目录进行打包压缩,形成name-version.tgz格式的单一文件,方便传输和存储)。
对于应用发布者而言,可以通过Helm打包应用,管理应用依赖关系,管理应用版本并发布应用到软件仓库。
对于使用者而言,使用Helm后不用需要了解Kubernetes的Yaml语法并编写应用部署文件,可以通过Helm下载并在kubernetes上安装需要的应用。
除此以外,Helm还提供了kubernetes上的软件部署,删除,升级,回滚应用的强大功能。
官方网站:https://helm.sh/
GitHub:https://github.com/helm/helm
Helm 组件及相关术语
Helm
Helm 是一个命令行下的客户端工具。主要用于 Kubernetes 应用程序 Chart 的创建、打包、发布以及创建和管理本地和远程的 Chart 仓库。
Tiller
Tiller 是 Helm 的服务端,部署在 Kubernetes 集群中。Tiller 用于接收 Helm 的请求,并根据 Chart 生成 Kubernetes 的部署文件( Helm 称为 Release ),然后提交给 Kubernetes 创建应用。Tiller 还提供了 Release 的升级、删除、回滚等一系列功能。
Chart
Helm 的软件包,采用 TAR 格式。类似于 APT 的 DEB 包或者 YUM 的 RPM 包,其包含了一组定义 Kubernetes 资源相关的 YAML 文件。
Repoistory
Helm 的软件仓库,Repository 本质上是一个 Web 服务器,该服务器保存了一系列的 Chart 软件包以供用户下载,并且提供了一个该 Repository 的 Chart 包的清单文件以供查询。Helm 可以同时管理多个不同的 Repository。
Release
使用 helm install
命令在 Kubernetes 集群中部署的 Chart 称为 Release。
注:需要注意的是:Helm 中提到的 Release 和我们通常概念中的版本有所不同,这里的 Release 可以理解为 Helm 使用 Chart 包部署的一个应用实例。
Helm工作原理
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
Helm部署
Helm 客户端安装
Helm 的安装方式很多,这里采用二进制的方式安装。更多安装方法可以参考 Helm 的官方帮助文档。
方式一:使用官方提供的脚本一键安装
1 | curl https://raw.githubusercontent.com/helm/helm/master/scripts/get > get_helm.sh |
方式二:手动下载安装(推荐)
1 | #从官网下载最新版本的二进制安装包到本地:https://github.com/kubernetes/helm/releases |
Helm 服务端安装Tiller
注意:先在 K8S 集群上每个节点安装 socat 软件(yum install -y socat ),不然会报如下错误:
1 | E0522 22:22:15.492436 24409 portforward.go:331] an error occurred forwarding 38398 -> 44134: error forwarding port 44134 to pod dc6da4ab99ad9c497c0cef1776b9dd18e0a612d507e2746ed63d36ef40f30174, uid : unable to do port forwarding: socat not found. |
Tiller 是以 Deployment 方式部署在 Kubernetes 集群中的,只需使用以下指令便可简单的完成安装。
1 | $ helm init |
由于 Helm 默认会去 storage.googleapis.com 拉取镜像,如果你当前执行的机器不能访问该域名的话可以使用以下命令来安装:
1 | helm init --client-only --stable-repo-url https://aliacs-app-catalog.oss-cn-hangzhou.aliyuncs.com/charts/ |
1 | # 创建服务端 |
在 Kubernetes 中安装 Tiller 服务,因为官方的镜像因为某些原因无法拉取,使用-i
指定自己的镜像,可选镜像:registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.9.1(阿里云),该镜像的版本与helm客户端的版本相同,使用helm version
可查看helm客户端版本。
如果在用helm init安装tiller server时一直部署不成功,检查deployment,根据描述解决问题。
给 Tiller 授权
因为 Helm 的服务端 Tiller 是一个部署在 Kubernetes 中 Kube-System Namespace 下 的 Deployment,它会去连接 Kube-Api 在 Kubernetes 里创建和删除应用。
而从 Kubernetes 1.6 版本开始,API Server 启用了 RBAC 授权。目前的 Tiller 部署时默认没有定义授权的 ServiceAccount,这会导致访问 API Server 时被拒绝。所以我们需要明确为 Tiller 部署添加授权。
创建 Kubernetes 的服务帐号和绑定角色
1 | $ kubectl create serviceaccount --namespace kube-system tiller |
为 Tiller 设置帐号
1 | # 使用 kubectl patch 更新 API 对象 |
查看是否授权成功
1 | $ kubectl get deploy --namespace kube-system tiller-deploy --output yaml|grep serviceAccount |
验证 Tiller 是否安装成功
1 | $ kubectl -n kube-system get pods|grep tiller |
卸载 Helm 服务器端 Tiller
如果你需要在 Kubernetes 中卸载已部署的 Tiller,可使用以下命令完成卸载。
1 | $ helm reset 或 |
Helm Chart
Chart 目录结构
1 | wordpress/ |
Chart.yaml 文件
Chart.yaml
文件是chart所必需的。它包含以下字段:
1 | apiVersion: The chart API version, always "v1" (required) |
Charts和版本控制
每个chart都必须有一个版本号。版本必须遵循SemVer 2标准。与Helm Class 格式不同,Kubernetes Helm使用版本号作为发布标记。存储库中的软件包由名称加版本识别。
例如,nginx
version字段设置为1.2.3将被命名为:
1 | nginx-1.2.3.tgz |
更复杂的SemVer 2命名也是支持的,例如 version: 1.2.3-alpha.1+ef365。但非SemVer命名是明确禁止的。
注意:虽然Helm Classic和Deployment Manager在chart方面都非常适合GitHub,但Kubernetes Helm并不依赖或需要GitHub甚至Git。因此,它不使用Git SHA进行版本控制。
许多Helm工具都使用Chart.yaml
的version
字段,其中包括CLI和Tiller服务。在生成包时,helm package命令将使用它在Chart.yaml中的版本名作为包名。系统假定chart包名称中的版本号与Chart.yaml
中的版本号相匹配。不符合这个情况会导致错误。
appVersion字段
请注意,appVersion
字段与version
字段无关。这是一种指定应用程序版本的方法。例如,drupal
chart可能有一个appVersion: 8.2.1
,表示chart中包含的Drupal版本(默认情况下)是8.2.1
。该字段是信息标识,对chart版本没有影响。
Chart许可证文件,自述文件和说明文件
chart还可以包含描述chart的安装,配置,使用和许可证的文件。chart的自述文件应Markdown(README.md)语法格式化,并且通常应包含:
- chart提供的应用程序或服务的描述
- 运行chart的任何前提条件或要求
- 选项
values.yaml
和默认值的说明 - 任何其他可能与安装或配置chart相关的信息
chart还可以包含一个简短的纯文本templates/NOTES.txt
文件,在安装后以及查看版本状态时将打印出来。此文件将作为模板template进行评估 ,并可用于显示使用说明,后续步骤或任何其他与发布chart相关的信息。例如,可以提供用于连接到数据库或访问Web UI的指令。由于运行时,该文件被打印到标准输出 helm install
或helm status
,建议保持内容简短并把更多细节指向自述文件。
Chart依赖关系
在Helm中,一个chart可能依赖于任何数量的其他chart。这些依赖关系可以通过requirements.yaml 文件动态链接或引入charts/
目录并手动管理。
Chart支持两种方式表示依赖关系,可以使用requirements.yaml或者直接将依赖的Chart放置到charts目录中。
虽然有一些团队需要手动管理依赖关系的优势,但声明依赖关系的首选方法是使用 chart 内部的requirements.yaml
文件。
注意: 传统Helm 的Chart.yaml dependencies:
部分字段已被完全删除弃用。
用requirements.yaml
来管理依赖关系
requirements.yaml
文件是列出chart的依赖关系的简单文件
1 | dependencies: |
- 该name字段是chart的名称。
- version字段是chart的版本。
- repository字段是chart repo的完整URL。请注意,还必须使用helm repo add添加该repo到本地才能使用。
有了依赖关系文件,你可以通过运行helm dependency update
,它会使用你的依赖关系文件将所有指定的chart下载到你的charts/
目录中。
1 | $ helm dep up foochart |
当helm dependency update
检索chart时,它会将它们作为chart存档存储在charts/
目录中。因此,对于上面的示例,可以在chart目录中看到以下文件:
1 | charts/ |
通过requirements.yaml
管理chart是一种轻松更新chart的好方法,还可以在整个团队中共享requirements信息。
requirements.yaml中的alias
字段
除上述其他字段外,每个requirement条目可能包含可选字段alias
。
为依赖的chart添加别名会将chart放入依赖关系中,并使用别名作为新依赖关系的名称。
如果需要使用其他名称访问chart,可以使用alias
。
1 | # parentchart/requirements.yaml |
在上面的例子中,我们将得到parentchart的3个依赖关系
1 | subchart |
实现这一目的的手动方法是charts/
中用不同名称多次复制/粘贴目录中的同一chart 。
requirements.yaml中的tags
和condition
字段
除上述其他字段外,每个需求条目可能包含可选字段tags
和condition
。
所有charts都会默认加载。如果存在tags
或condition
字段,将对它们进行评估并用于控制应用的chart的加载。
Condition – condition 字段包含一个或多个YAML路径(用逗号分隔)。如果此路径存在于顶级父级的值中并且解析为布尔值,则将根据该布尔值启用或禁用chart。只有在列表中找到的第一个有效路径才被评估,如果没有路径存在,那么该条件不起作用。
Tags – 标签字段是与此chart关联的YAML标签列表。在顶级父级的值中,可以通过指定标签和布尔值来启用或禁用所有带有标签的chart。
1 | # parentchart/requirements.yaml |
1 | # parentchart/values.yaml |
在上面的示例中,所有带有标签的front-end的
charts都将被禁用,但由于 subchart1.enabled
的值在父项值中为“真”,因此条件将覆盖该 front-end
标签,subchart1
会启用。
由于subchart2
被标记back-end
和标签的计算结果为true
,subchart2
将被启用。还要注意的是,虽然subchart2
有一个在requirements.yaml
中指定的条件,但父项的值中没有对应的路径和值,因此条件无效。
使用命令行时带有tag和conditions
--set
参数可使用来更改tag和conditions值。
1 | helm install --set tags.front-end=true --set subchart2.enabled=false |
tags
和conditions
解析
- Conditions (设置 values) 会覆盖tags配置.。第一个存在的condition路径生效,后续该chart的condition路径将被忽略。
- 如果chart的某tag的任一tag的值为true,那么该tag的值为true,并启用这个chart。
- Tags 和 conditions值必须在顶级父级的值中进行设置。
tags:
值中的关键字必须是顶级关键字。目前不支持全局和嵌套tags:
表格。
通过requirements.yaml导入子值
在某些情况下,希望允许子chart的值传到父chart并作为通用默认值共享。使用这种exports格式的另一个好处是它可以使未来的工具能够考虑用户可设置的值。
要导入的值的键可以在父chart文件中requirements.yaml
使用YAML list指定。list中的每个项目都是从子chart exports
字段导入的key。
要导入不包含在exports key中的值,请使用子父级child-parent格式。下面描述了两种格式的例子。
- 使用exports格式
如果子chart的values.yaml文件exports在根目录中包含一个字段,则可以通过指定要导入的关键字将其内容直接导入到父项的值中,如下例所示:
1 | # parent's requirements.yaml file |
1 | # child's values.yaml file |
由于我们在导入列表中指定了data
键,因此Helm会在exports子图的字段中查找data键并导入其内容。
最终的父值将包含我们的导出字段:
1 | # parent's values file |
请注意,父键data不包含在父chart的最终值中。如果需要指定父键,请使用’child-parent’格式。
- 使用child-parent格式
要访问未包含在子chart键值exports
的中的值,需要指定要导入的值的源键(child
)和父chart值(parent
)中的目标路径。
下面的例子中的import-values
告诉Helm去拿在child:
路径发现的任何值,并将其复制到父值parent:
指定的路径
1 | # parent's requirements.yaml file |
在上面的例子中,在subchart1default.data
的值中找到的值将被导入到父chart值中myimports
的键值,详细如下:
1 | # parent's values.yaml file |
1 | # subchart1's values.yaml file |
父chart的结果值为:
1 | # parent's final values |
父chart的最终值现在包含从subchart1导入的myint
和mybool
字段。
通过charts/
目录手动管理依赖性
如果需要更多的控制依赖关系,可以通过将依赖的charts复制到charts/
目录中来明确表达这些依赖关系 。
依赖关系可以是chart归档(foo-1.2.3.tgz
)或解压缩的chart目录。但它的名字不能从_
或.
开始。这些文件被chart加载器忽略。
例如,如果WordPress chart依赖于Apache chart,则在WordPress chart的charts/
目录中提供(正确版本的)Apache chart:
1 | wordpress: |
上面的示例显示了WordPress chart如何通过在其`charts/“目录中包含这些charts来表示它对Apache和MySQL的依赖关系。
提示: 将依赖项放入charts/目录,请使用helm fetch
命令
使用依赖关系的操作方面影响
上面的部分解释了如何指定chart依赖关系,但是这会如何影响使用helm install
和helm upgrade
的chart安装?
假设名为“A”的chart创建以下Kubernetes对象
- namespace “A-Namespace”
- statefulset “A-StatefulSet”
- service “A-Service”
此外,A依赖于创建对象的chart B.
- namespace “B-Namespace”
- replicaset “B-ReplicaSet”
- service “B-Service”
安装/升级chart A后,会创建/修改单个Helm版本。该版本将按以下顺序创建/更新所有上述Kubernetes对象:
- A-Namespace
- B-Namespace
- A-StatefulSet
- B-ReplicaSet
- A-Service
- B-Service
这是因为当Helm安装/升级charts时,charts中的Kubernetes对象及其所有依赖项都是如下
- 聚合成一个单一的集合; 然后
- 按类型排序,然后按名称排序; 接着
- 按该顺序创建/更新。
因此,单个release是使用charts及其依赖关系创建的所有对象。
Kubernetes类型的安装顺序由kind_sorter.go中的枚举InstallOrder给出(the Helm source file))。
模板Templates和值Values
Helm chart模板是用Go模板语言Go template language编写的 ,其中添加了来自Sprig库from the Sprig library的50个左右的附加模板函数以及一些其他专用函数specialized functions。
所有模板文件都存储在chart的templates/文件夹中。当Helm渲染charts时,它将通过模板引擎传递该目录中的每个文件。
模板的值有两种提供方法:
- chart开发人员可能会在chart内部提供一个values.yaml文件。该文件可以包含默认值。
- chart用户可能会提供一个包含值的YAML文件。这可以通过命令行提供
helm install -f
。
当用户提供自定义值时,这些值将覆盖chart中values.yaml
文件中的值。
模板文件
模板文件遵循用于编写Go模板的标准约定(请参阅文the text/template Go package documentation 以了解详细信息)。示例模板文件可能如下所示:
1 | # db.yaml |
上面的示例基于此网址,是Kubernetes replication controller的模板。它可以使用以下四个模板值(通常在values.yaml文件中定义 ):
- imageRegistry:Docker镜像的源。
- dockerTag:docker镜像的标签。
- pullPolicy:Kubernetes镜像拉取策略。
- storage:存储后端,其默认设置为
"minio"
所有这些值都由模板作者定义。Helm不需要或指定参数。
要查更多charts,请查看Kubernetes charts项目。https://github.com/helm/charts
模板语法
模版语法扩展了 golang/text/template的语法:
1 | # 这种方式定义的模版,会去除test模版尾部所有的空行 |
用于yaml文件前置空格的语法:
1 | # 这种方式定义的模版,会去除test模版头部和尾部所有的空行 |
提供的一些声明和使用命名模板段的操作:
1 | define在模板中声明一个新的命名模板 |
首先,模板名称是全局的。如果声明两个具有相同名称的模板,则最后加载一个模板是起作用的模板。由于子chart中的模板与顶级模板一起编译,因此注意小心地使用特定chart的名称来命名模板。
通用的命名方式是,以chart名称作为前缀,
1 | eg: {{ define "mychart.labels" }} |
用define和template声明,使用模板
示例:
1 | {{/* Generate basic labels */}} |
当模板引擎读取该文件时,它将存储引用mychart.labels直到template “mychart.labels”被调用。然后它将在文件内渲染该模板。结果:
1 | # Source: mychart/templates/configmap.yaml |
按照惯例,define函数会有一个简单的文档块如下来描述自己
1 | ({{/* ... */}}) |
Helm chart通常将这些模板放入partials文件中,通常是_helpers.tpl。 定义和引用的方式不变。
如果这样定义一个模板
1 | {{/* Generate basic labels */}} |
还是这样引用:
1 | {{- template "mychart.labels" }} |
则 version 的值为空,因为模板需要一个上下文:
1 | {{- template "mychart.labels" . }} |
include
这是一个引用模板的函数:
假设我们定义了一个这样的模板:
1 | {{- define "mychart.app" -}} |
并且正常引用:
1 | apiVersion: v1 |
结果会有缩进错误:
1 | # Source: mychart/templates/configmap.yaml |
因为template的数据只是内嵌插入,是一个‘动作’,而非‘函数’,即不能通过管道传递给其他函数,来进行格式化。
include 配合 indent 可以解决这个问题。
1 | {{ include "mychart.app" . | indent 4 }} |
上面的示例可以改为
1 | apiVersion: v1 |
文件访问
Helm通过.Files对象提供对文件的访问,例如Files.Get是一个按名称获取文件的函数(.Files.Get config.ini)。下面是几个要注意的点:
1 | 向Helm chart添加额外的文件是可以的。这些文件将被捆绑并发送给Tiller。不过要注意,由于Kubernetes对象的存储限制,chart必须小于1M。 |
示例:
首先创建三个文件
1 | config1.toml: |
然后,用一个range函数来遍历它们并将它们的内容注入到ConfigMap中。
1 | apiVersion: v1 |
其结果如下:
1 | # Source: mychart/templates/configmap.yaml |
Glob 函数
Glob是一个可以一次获取多个文件的函数。
1 | 假设这样的一个目录结构: |
则可以这样引用文件:
1 | {{ $root := . }} |
或者这样:
1 | {{ range $path, $bytes := .Files.Glob "foo/*" }} |
有时候想要将文件内容放到configmap里,则可以用Glob ,ConfigMap和Secrets配合实现:
1 | apiVersion: v1 |
按行获取文件:
1 | data: |
预定义值
通过values.yaml
文件(或通过--set
标志)提供的值可以从.Values
模板中的对象访问。可以在模板中访问其他预定义的数据片段。
以下值是预定义的,可用于每个模板,并且不能被覆盖。与所有值一样,名称区分大小写。
Release.Name
:release的名称(不是chart的)Release.Time
:chart版本上次更新的时间。这将匹配Last Released
发布对象上的时间。Release.Namespace
:chart release发布的namespace。Release.Service
:处理release的服务。通常是Tiller。Release.IsUpgrade
:如果当前操作是升级或回滚,则设置为true。Release.IsInstall
:如果当前操作是安装,则设置为true。Release.Revision
:版本号。它从1开始,并随着每个helm upgrade
增加。Chart
:Chart.yaml
的内容。chart版本可以从Chart.Version
和维护人员Chart.Maintainers
一起获得。Files
:包含chart中所有非特殊文件的map-like对象。不会允许你访问模板,但会让你访问存在的其他文件(除非它们被排除使用.helmignore
)。可以使用index .Files “file.name”或使用.Files.Get name或 .Files.GetString name功能来访问文件。也可以使用.Files.GetBytes访问该文件的内容[byte]
- Capabilities:包含有关Kubernetes版本信息的map-like对象(.Capabilities.KubeVersion),Tiller(.Capabilities.TillerVersion)和支持的Kubernetes API版本(.Capabilities.APIVersions.Has “batch/v1″)
注意: 任何未知的Chart.yaml字段将被删除。它们不会在chart对象内部被访问。因此,Chart.yaml不能用于将任意结构化的数据传递到模板中。values文件可以用于传递。
值values文件
考虑到上一节中的模板values.yaml
,提供了如下必要值的信息:
1 | imageRegistry: "quay.io/deis" |
values文件是YAML格式的。chart可能包含一个默认 values.yaml文件。Helm install命令允许用户通过提供额外的YAML值来覆盖值:
1 | $ helm install --values=myvals.yaml wordpress |
当以这种方式传递值时,它们将被合并到默认values文件中。例如,考虑一个如下所示的myvals.yaml文件:
1 | storage: "gcs" |
当它与chart中values.yaml的内容合并时,生成的内容将为:
1 | imageRegistry: "quay.io/deis" |
注意只有最后一个字段被覆盖了,其他的不变。
注:包含在chart内的默认values文件必须命名 values.yaml
。但是在命令行上指定的文件可以被命名为任何名称。
注:如果在helm install或helm upgrade使用--set
,则这些值仅在客户端转换为YAML。
注意:如果values文件中存在任何必需的条目,则可以使用’required’函数在chart模板中声明它们
然后可以在模板内部访问任何这些.Values
对象值 :
1 | apiVersion: v1 |
范围Scope,依赖Dependencies
values文件可以声明顶级chart的值,也可以为chart的charts/目录中包含的任何chart声明值。或者,用不同的方式来描述它,values文件可以为chart及其任何依赖项提供值。例如,上面的演示WordPresschart具有mysql和apache依赖性。values文件可以为所有这些组件提供值:
1 | title: "My WordPress Site" # Sent to the WordPress template |
更高级别的chart可以访问下面定义的所有变量。所以WordPresschart可以访问MySQL密码 .Values.mysql.password
。但较低级别的chart无法访问父chart中的内容,因此MySQL将无法访问该title
属性。同样的,也不能访问apache.port
。
值是命名空间限制的,但命名空间已被修剪。因此对于WordPresschart来说,它可以访问MySQL密码字段.Values.mysql.password
。但是对于MySQL chart来说,这些值的范围已经减小了,并且删除了名namespace前缀,所以它会将密码字段简单地视为 .Values.password
。
全局值
从2.0.0-Alpha.2开始,Helm支持特殊的“全局”值。考虑前面例子的这个修改版本:
1 | title: "My WordPress Site" # Sent to the WordPress template |
上面添加了一个global区块,值app: MyWordPress
。此值可供所有chart使用.Values.global.app
。
比如,该mysql模板可以访问app
如.Values.global.app,apache chart也同样的。上面的values文件是这样高效重新生成的:
1 | title: "My WordPress Site" # Sent to the WordPress template |
这提供了一种与所有子chart共享一个顶级变量的方法,这对设置metadata中像标签这样的属性很有用。
如果子chart声明了一个全局变量,则该全局将向下传递 (到子chart的子chart),但不向上传递到父chart。子chart无法影响父chart的值。
此外,父chart的全局变量优先于子chart中的全局变量。
参考
当涉及到编写模板和values文件时,有几个标准参考可以帮助你。
使用Helm管理chart
该helm工具有几个用于处理chart的命令。
它可以为你创建一个新的chart:
1 | $ helm create mychart |
编辑完chart后,helm
可以将其打包到chart压缩包中:
1 | $ helm package mychart |
可以用helm
来帮助查找chart格式或信息的问题:
1 | $ helm lint mychart |
删除release
1 | $ helm delete mychart |
导出helm的template模板yaml文件
1 | helm template --name mychart --namespace test --output-dir ./test . |
Chart repo库
chart repo库是容纳一个或多个封装的chart的HTTP服务器。虽然helm可用于管理本地chart目录,但在共享chart时,首选机制是chart repo库。
任何可以提供YAML文件和tar文件并可以回答GET请求的HTTP服务器都可以用作repo库服务器。
Helm附带用于开发人员测试的内置服务器(helm serve
)。Helm团队测试了其他服务器,包括启用了网站模式的Google Cloud Storage以及启用了网站模式的S3。
repo库的主要特征是存在一个名为的特殊文件index.yaml
,它具有repo库提供的所有软件包的列表以及允许检索和验证这些软件包的元数据。
在客户端,repo库使用helm repo
命令进行管理。但是,Helm不提供将chart上传到远程存储服务器的工具。这是因为这样做会增加部署服务器的需求,从而增加配置repo库的难度。
本地仓库
假设我们已经打包了 Chart 并发布到了 Helm 的本地目录中,但通过 helm search
命令查找,并不能找不到刚才生成的 mychart包。
1 | $ helm search mychart |
这是因为 Repository 目录中的 Chart 包还没有被 Helm 管理。通过 helm repo list
命令可以看到目前 Helm 中已配置的 Repository 的信息。
1 | $ helm repo list |
注:新版本中执行 helm init 命令后默认会配置一个名为 local 的本地仓库。
我们可以在本地启动一个 Repository Server,并将其加入到 Helm Repo 列表中。Helm Repository 必须以 Web 服务的方式提供,这里我们就使用 helm serve
命令启动一个 Repository Server,该 Server 缺省使用 $HOME/.helm/repository/local
目录作为 Chart 存储,并在 8879 端口上提供服务。
1 | $ helm serve & |
默认情况下该服务只监听 127.0.0.1,如果你要绑定到其它网络接口,可使用以下命令:
1 | $ helm serve --address 192.168.100.211:8879 & |
如果你想使用指定目录来做为 Helm Repository 的存储目录,可以加上 --repo-path
参数:
1 | $ helm serve --address 192.168.100.211:8879 --repo-path /data/helm/repository/ --url http://192.168.100.211:8879/charts/ |
通过 helm repo index
命令将 Chart 的 Metadata 记录更新在 index.yaml 文件中:
1 | # 更新 Helm Repository 的索引文件 |
完成启动本地 Helm Repository Server 后,就可以将本地 Repository 加入 Helm 的 Repo 列表。
1 | $ helm repo add local http://127.0.0.1:8879 |
现在再次查找 mychart 包,就可以搜索到了。
1 | $ helm repo update |
外部仓库
随着 Helm 越来越普及,除了使用预置官方存储库,三方仓库也越来越多了(前提是网络是可达的)。你可以使用如下命令格式添加三方 Chart 存储库。
1 | $ helm repo add 存储库名 存储库URL |
一些三方存储库资源:
1 | # Prometheus Operator |
创建自己的Chart
我们创建一个名为mongodb
的chart,看一看chart的文件结构。
1 | $ helm create mongodb |
模板
我们查看下deployment.yaml
文件的内容。
1 | apiVersion: extensions/v1beta1 |
这是该应用的Deployment的yaml配置文件,其中的双大括号包扩起来的部分是Go template,其中的Values是在values.yaml
文件中定义的:
1 | # Default values for mychart. |
比如在Deployment.yaml
中定义的容器镜像
1 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" |
其中的:
.Values.image.repository
就是nginx.Values.image.tag
就是stable
以上两个变量值是在create chart的时候自动生成的默认值。
我们将默认的镜像地址和tag改成我们自己的镜像harbor-001.jimmysong.io/library/nginx:1.9
。
检查配置和模板是否有效
1 | $ helm lint . |
当使用kubernetes部署应用的时候实际上讲templates渲染成最终的kubernetes能够识别的yaml格式。
使用helm install --dry-run --debug <chart_dir>
命令来验证chart配置。该输出中包含了模板的变量配置与最终渲染的yaml文件。
1 |
|
我们可以看到Deployment和Service的名字前半截由两个随机的单词组成,最后才是我们在values.yaml
中配置的值。
部署到kubernetes
在mychart
目录下执行下面的命令将nginx部署到kubernetes集群上。
1 | helm install . |
现在nginx已经部署到kubernetes集群上,本地执行提示中的命令在本地主机上访问到nginx实例。
1 | export POD_NAME=$(kubectl get pods --namespace default -l "app=eating-hound-mychart" -o jsonpath="{.items[0].metadata.name}") |
在本地访问http://127.0.0.1:8080
即可访问到nginx。
查看部署的relaese
1 | $ helm list |
删除部署的release
1 | $ helm delete eating-hound |
打包分享
我们可以修改Chart.yaml
中的helm chart配置信息,然后使用下列命令将chart打包成一个压缩文件。
1 | helm package . |
打包出mychart-0.1.0.tgz
文件。
Helm升级和回退一个应用
从上面 helm list
输出的结果中我们可以看到有一个 Revision(更改历史)字段,该字段用于表示某一个 Release 被更新的次数,我们可以用该特性对已部署的 Release 进行回滚。
- 修改 Chart.yaml 文件
将版本号从 0.1.0 修改为 0.2.0, 然后使用 helm package
命令打包并发布到本地仓库。
1 |
|
- 查询本地仓库中的 Chart 信息
我们可以看到在本地仓库中 mychart 有两个版本。
1 | $ helm search mychart -l |
升级一个应用
现在用 helm upgrade
命令将已部署的 mike-test 升级到新版本。你可以通过 --version
参数指定需要升级的版本号,如果没有指定版本号,则缺省使用最新版本。
1 | $ helm upgrade mike-test local/mychart |
完成后,可以看到已部署的 mike-test 被升级到 0.2.0 版本。
1 | $ helm list |
回退一个应用
如果更新后的程序由于某些原因运行有问题,需要回退到旧版本的应用。首先我们可以使用 helm history
命令查看一个 Release 的所有变更记录。
1 | $ helm history mike-test |
其次,我们可以使用下面的命令对指定的应用进行回退。
1 | $ helm rollback mike-test 1 |
注:其中的参数 1 是 helm history 查看到 Release 的历史记录中 REVISION 对应的值。
最后,我们使用 helm list
和 helm history
命令都可以看到 mychart 的版本已经回退到 0.1.0 版本。
1 | $ helm list |
删除一个应用
如果需要删除一个已部署的 Release,可以利用 helm delete
命令来完成删除。
1 | $ helm delete mike-test |
确认应用是否删除,该应用已被标记为 DELETED 状态。
1 | $ helm ls -a mike-test |
也可以使用 --deleted
参数来列出已经删除的 Release
1 | $ helm ls --deleted |
从上面的结果也可以看出,默认情况下已经删除的 Release 只是将状态标识为 DELETED 了 ,但该 Release 的历史信息还是继续被保存的。
1 | $ helm hist mike-test |
如果要移除指定 Release 所有相关的 Kubernetes 资源和 Release 的历史记录,可以用如下命令:
1 | $ helm delete --purge mike-test |
再次查看已删除的 Release,已经无法找到相关信息。
1 | $ helm hist mike-test |
Helm 其它使用技巧
- 如何设置 helm 命令自动补全?
为了方便 helm
命令的使用,Helm 提供了自动补全功能,如果使用 ZSH 请执行:
1 | $ source <(helm completion zsh) |
如果使用 BASH 请执行:
1 | $ source <(helm completion bash) |
- Helm 如何结合 CI/CD ?
采用 Helm 可以把零散的 Kubernetes 应用配置文件作为一个 Chart 管理,Chart 源码可以和源代码一起放到 Git 库中管理。通过把 Chart 参数化,可以在测试环境和生产环境采用不同的 Chart 参数配置。
下图是采用了 Helm 的一个 CI/CD 流程
- Helm 如何管理多环境下 (Test、Staging、Production) 的业务配置?
Chart 是支持参数替换的,可以把业务配置相关的参数设置为模板变量。使用 helm install
命令部署的时候指定一个参数值文件,这样就可以把业务参数从 Chart 中剥离了。例如: helm install --values=values-production.yaml wordpress
。
- Helm 如何解决服务依赖?
在 Chart 里可以通过 requirements.yaml 声明对其它 Chart 的依赖关系。如下面声明表明 Chart 依赖 Apache 和 MySQL 这两个第三方 Chart。
1 | dependencies: |
- 如何让 Helm 连接到指定 Kubernetes 集群?
Helm 默认使用和 kubectl 命令相同的配置访问 Kubernetes 集群,其配置默认在 ~/.kube/config
中。
- 如何在部署时指定命名空间?
helm install
默认情况下是部署在 default 这个命名空间的。如果想部署到指定的命令空间,可以加上 --namespace
参数,比如:
1 | $ helm install local/mychart --name mike-test --namespace mynamespace |
- 如何查看已部署应用的详细信息?
1 | $ helm get wordpress-test |
默认情况下会显示最新的版本的相关信息,如果想要查看指定发布版本的信息可加上 --revision
参数。
1 | $ helm get --revision 1 wordpress-test |
Helm优秀实例
GitHub: https://github.com/helm/charts
Harbor-helm: https://github.com/gongzhao1/harbor-helm
Redis-helm: https://www.kubernetes.org.cn/3974.html
elk-helm: https://github.com/gongzhao1/elk(这是我个人写的部署elk集群的helm)