kubernetes之helm详解

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工作原理

image

Chart Install 过程:

  1. Helm从指定的目录或者tgz文件中解析出Chart结构信息
  2. Helm将指定的Chart结构和Values信息通过gRPC传递给Tiller
  3. Tiller根据Chart和Values生成一个Release
  4. Tiller将Release发送给Kubernetes用于生成Release

Chart Update过程:

  1. Helm从指定的目录或者tgz文件中解析出Chart结构信息
  2. Helm将要更新的Release的名称和Chart结构,Values信息传递给Tiller
  3. Tiller生成Release并更新指定名称的Release的History
  4. Tiller将Release发送给Kubernetes用于更新Release

Chart Rollback过程:

  1. Helm将要回滚的Release的名称传递给Tiller
  2. Tiller根据Release的名称查找History
  3. Tiller从History中获取上一个Release
  4. Tiller将上一个Release发送给Kubernetes用于替换当前Release

Helm部署

Helm 客户端安装

Helm 的安装方式很多,这里采用二进制的方式安装。更多安装方法可以参考 Helm 的官方帮助文档。

方式一:使用官方提供的脚本一键安装

1
2
3
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get > get_helm.sh
$ chmod 700 get_helm.sh
$ ./get_helm.sh

方式二:手动下载安装(推荐)

1
2
3
4
5
#从官网下载最新版本的二进制安装包到本地:https://github.com/kubernetes/helm/releases
tar -zxvf helm-2.9.0.tar.gz # 解压压缩包
# 把 helm 指令放到bin目录下
mv helm-2.9.0/helm /usr/local/bin/helm
helm help # 验证

Helm 服务端安装Tiller

注意:先在 K8S 集群上每个节点安装 socat 软件(yum install -y socat ),不然会报如下错误:

1
2
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.
Error: cannot connect to Tiller

Tiller 是以 Deployment 方式部署在 Kubernetes 集群中的,只需使用以下指令便可简单的完成安装。

1
$ helm init

由于 Helm 默认会去 storage.googleapis.com 拉取镜像,如果你当前执行的机器不能访问该域名的话可以使用以下命令来安装:

1
2
3
4
5
helm init --client-only --stable-repo-url https://aliacs-app-catalog.oss-cn-hangzhou.aliyuncs.com/charts/

helm repo add incubator https://aliacs-app-catalog.oss-cn-hangzhou.aliyuncs.com/charts-incubator/

helm repo update
1
2
3
4
5
6
# 创建服务端
helm init --service-account tiller --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.9.1 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

# 创建TLS认证服务端,参考地址:https://github.com/gjmzj/kubeasz/blob/master/docs/guide/helm.md

helm init --service-account tiller --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.9.1 --tiller-tls-cert /etc/kubernetes/ssl/tiller001.pem --tiller-tls-key /etc/kubernetes/ssl/tiller001-key.pem --tls-ca-cert /etc/kubernetes/ssl/ca.pem --tiller-namespace kube-system --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

在 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
2
$ kubectl create serviceaccount --namespace kube-system tiller
$ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller

为 Tiller 设置帐号

1
2
3
# 使用 kubectl patch 更新 API 对象
$ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
deployment.extensions "tiller-deploy" patched

查看是否授权成功

1
2
3
$ kubectl get deploy --namespace kube-system   tiller-deploy  --output yaml|grep  serviceAccount
serviceAccount: tiller
serviceAccountName: tiller

验证 Tiller 是否安装成功

1
2
3
4
5
$ kubectl -n kube-system get pods|grep tiller
tiller-deploy-6d68f5c78f-nql2z 1/1 Running 0 5m
$ helm version
Client: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}

卸载 Helm 服务器端 Tiller

如果你需要在 Kubernetes 中卸载已部署的 Tiller,可使用以下命令完成卸载。

1
2
$ helm reset 或
$helm reset --force

Helm Chart

Chart 目录结构

1
2
3
4
5
6
7
8
9
10
wordpress/
Chart.yaml # A YAML file containing information about the chart
LICENSE # OPTIONAL: A plain text file containing the license for the chart
README.md # OPTIONAL: A human-readable README file
requirements.yaml # OPTIONAL: A YAML file listing dependencies for the chart
values.yaml # The default configuration values for this chart
charts/ # A directory containing any charts upon which this chart depends.
templates/ # A directory of templates that, when combined with values,
# will generate valid Kubernetes manifest files.
templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes

Chart.yaml 文件

Chart.yaml文件是chart所必需的。它包含以下字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: The chart API version, always "v1" (required)
name: The name of the chart (required)
version: A SemVer 2 version (required)
kubeVersion: A SemVer range of compatible Kubernetes versions (optional)
description: A single-sentence description of this project (optional)
keywords:
- A list of keywords about this project (optional)
home: The URL of this project's home page (optional)
sources:
- A list of URLs to source code for this project (optional)
maintainers: # (optional)
- name: The maintainer's name (required for each maintainer)
email: The maintainer's email (optional for each maintainer)
url: A URL for the maintainer (optional for each maintainer)
engine: gotpl # The name of the template engine (optional, defaults to gotpl)
icon: A URL to an SVG or PNG image to be used as an icon (optional).
appVersion: The version of the app that this contains (optional). This needn't be SemVer.
deprecated: Whether this chart is deprecated (optional, boolean)
tillerVersion: The version of Tiller that this chart requires. This should be expressed as a SemVer range: ">2.0.0" (optional)

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 installhelm 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
2
3
4
5
6
7
dependencies:
- name: apache
version: 1.2.3
repository: http://example.com/charts
- name: mysql
version: 3.2.1
repository: http://another.example.com/charts
  • 该name字段是chart的名称。
  • version字段是chart的版本。
  • repository字段是chart repo的完整URL。请注意,还必须使用helm repo add添加该repo到本地才能使用。

有了依赖关系文件,你可以通过运行helm dependency update ,它会使用你的依赖关系文件将所有指定的chart下载到你的charts/目录中。

1
2
3
4
5
6
7
8
9
10
$ helm dep up foochart
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "local" chart repository
...Successfully got an update from the "stable" chart repository
...Successfully got an update from the "example" chart repository
...Successfully got an update from the "another" chart repository
Update Complete. Happy Helming!
Saving 2 charts
Downloading apache from repo http://example.com/charts
Downloading mysql from repo http://another.example.com/charts

helm dependency update检索chart时,它会将它们作为chart存档存储在charts/目录中。因此,对于上面的示例,可以在chart目录中看到以下文件:

1
2
3
charts/
apache-1.2.3.tgz
mysql-3.2.1.tgz

通过requirements.yaml管理chart是一种轻松更新chart的好方法,还可以在整个团队中共享requirements信息。

requirements.yaml中的alias字段

除上述其他字段外,每个requirement条目可能包含可选字段alias

为依赖的chart添加别名会将chart放入依赖关系中,并使用别名作为新依赖关系的名称。

如果需要使用其他名称访问chart,可以使用alias

1
2
3
4
5
6
7
8
9
10
11
12
13
# parentchart/requirements.yaml
dependencies:
- name: subchart
repository: http://localhost:10191
version: 0.1.0
alias: new-subchart-1
- name: subchart
repository: http://localhost:10191
version: 0.1.0
alias: new-subchart-2
- name: subchart
repository: http://localhost:10191
version: 0.1.0

在上面的例子中,我们将得到parentchart的3个依赖关系

1
2
3
subchart
new-subchart-1
new-subchart-2

实现这一目的的手动方法是charts/中用不同名称多次复制/粘贴目录中的同一chart 。

requirements.yaml中的tagscondition字段

除上述其他字段外,每个需求条目可能包含可选字段tagscondition

所有charts都会默认加载。如果存在tagscondition字段,将对它们进行评估并用于控制应用的chart的加载。

Condition – condition 字段包含一个或多个YAML路径(用逗号分隔)。如果此路径存在于顶级父级的值中并且解析为布尔值,则将根据该布尔值启用或禁用chart。只有在列表中找到的第一个有效路径才被评估,如果没有路径存在,那么该条件不起作用。

Tags – 标签字段是与此chart关联的YAML标签列表。在顶级父级的值中,可以通过指定标签和布尔值来启用或禁用所有带有标签的chart。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# parentchart/requirements.yaml
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
condition: subchart1.enabled, global.subchart1.enabled
tags:
- front-end
- subchart1

- name: subchart2
repository: http://localhost:10191
version: 0.1.0
condition: subchart2.enabled,global.subchart2.enabled
tags:
- back-end
- subchart2
1
2
3
4
5
6
# parentchart/values.yaml
subchart1:
enabled: true
tags:
front-end: false
back-end: true

在上面的示例中,所有带有标签的front-end的charts都将被禁用,但由于 subchart1.enabled的值在父项值中为“真”,因此条件将覆盖该 front-end标签,subchart1会启用。

由于subchart2被标记back-end和标签的计算结果为truesubchart2将被启用。还要注意的是,虽然subchart2有一个在requirements.yaml中指定的条件,但父项的值中没有对应的路径和值,因此条件无效。

使用命令行时带有tag和conditions

--set参数可使用来更改tag和conditions值。

1
helm install --set tags.front-end=true --set subchart2.enabled=false

tagsconditions解析

  • 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
2
3
4
# parent's requirements.yaml file
...
import-values:
- data
1
2
3
4
5
# child's values.yaml file
...
exports:
data:
myint: 99

由于我们在导入列表中指定了data键,因此Helm会在exports子图的字段中查找data键并导入其内容。

最终的父值将包含我们的导出字段:

1
2
3
# parent's values file
...
myint: 99

请注意,父键data不包含在父chart的最终值中。如果需要指定父键,请使用’child-parent’格式。

  • 使用child-parent格式

要访问未包含在子chart键值exports的中的值,需要指定要导入的值的源键(child)和父chart值(parent)中的目标路径。

下面的例子中的import-values告诉Helm去拿在child:路径发现的任何值,并将其复制到父值parent:指定的路径

1
2
3
4
5
6
7
8
9
# parent's requirements.yaml file
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
...
import-values:
- child: default.data
parent: myimports

在上面的例子中,在subchart1default.data的值中找到的值将被导入到父chart值中myimports的键值,详细如下:

1
2
3
4
5
6
# parent's values.yaml file

myimports:
myint: 0
mybool: false
mystring: "helm rocks!"
1
2
3
4
5
6
# subchart1's values.yaml file

default:
data:
myint: 999
mybool: true

父chart的结果值为:

1
2
3
4
5
6
# parent's final values

myimports:
myint: 999
mybool: true
mystring: "helm rocks!"

父chart的最终值现在包含从subchart1导入的myintmybool字段。

通过charts/目录手动管理依赖性

如果需要更多的控制依赖关系,可以通过将依赖的charts复制到charts/目录中来明确表达这些依赖关系 。

依赖关系可以是chart归档(foo-1.2.3.tgz)或解压缩的chart目录。但它的名字不能从_.开始。这些文件被chart加载器忽略。

例如,如果WordPress chart依赖于Apache chart,则在WordPress chart的charts/目录中提供(正确版本的)Apache chart:

1
2
3
4
5
6
7
8
9
10
11
wordpress:
Chart.yaml
requirements.yaml
# ...
charts/
apache/
Chart.yaml
# ...
mysql/
Chart.yaml
# ...

上面的示例显示了WordPress chart如何通过在其`charts/“目录中包含这些charts来表示它对Apache和MySQL的依赖关系。

提示: 将依赖项放入charts/目录,请使用helm fetch命令

使用依赖关系的操作方面影响

上面的部分解释了如何指定chart依赖关系,但是这会如何影响使用helm installhelm 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# db.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
heritage: deis
spec:
replicas: 1
selector:
app: deis-database
template:
metadata:
labels:
app: deis-database
spec:
serviceAccount: deis-database
containers:
- name: deis-database
image: {{.Values.imageRegistry}}/postgres:{{.Values.dockerTag}}
imagePullPolicy: {{.Values.pullPolicy}}
ports:
- containerPort: 5432
env:
- name: DATABASE_STORAGE
value: {{default "minio" .Values.storage}}

上面的示例基于此网址,是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
2
3
4
5
6
7
# 这种方式定义的模版,会去除test模版尾部所有的空行
{{- define "test"}}
模版内容
{{- end}}

# 去除test模版头部的第一个空行
{{- template "test" }}

用于yaml文件前置空格的语法:

1
2
3
4
5
6
7
# 这种方式定义的模版,会去除test模版头部和尾部所有的空行
{{- define "test" -}}
模版内容
{{- end -}}

# 可以在test模版每一行的头部增加4个空格,用于yaml文件的对齐
{{ include "test" | indent 4}}

提供的一些声明和使用命名模板段的操作:

1
2
3
define在模板中声明一个新的命名模板
template导入一个命名模板
block 声明了一种特殊的可填写模板区域

首先,模板名称是全局的。如果声明两个具有相同名称的模板,则最后加载一个模板是起作用的模板。由于子chart中的模板与顶级模板一起编译,因此注意小心地使用特定chart的名称来命名模板。

通用的命名方式是,以chart名称作为前缀,

1
eg: {{ define "mychart.labels" }}

用define和template声明,使用模板

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}

当模板引擎读取该文件时,它将存储引用mychart.labels直到template “mychart.labels”被调用。然后它将在文件内渲染该模板。结果:

1
2
3
4
5
6
7
8
9
10
11
12
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: running-panda-configmap
labels:
generator: helm
date: 2016-11-02
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"

按照惯例,define函数会有一个简单的文档块如下来描述自己

1
({{/* ... */}})

Helm chart通常将这些模板放入partials文件中,通常是_helpers.tpl。 定义和引用的方式不变。

如果这样定义一个模板

1
2
3
4
5
6
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
version: {{ .Chart.Version }}
{{- end }}

还是这样引用:

1
{{- template "mychart.labels" }}

则 version 的值为空,因为模板需要一个上下文:

1
2
3
{{- template "mychart.labels" . }}

把顶层对象'.'传递给模板,即可引用.Release,.Chaert 等。

include

这是一个引用模板的函数:

假设我们定义了一个这样的模板:

1
2
3
4
{{- define "mychart.app" -}}
app_name: {{ .Chart.Name }}
app_version: "{{ .Chart.Version }}+{{ .Release.Time.Seconds }}"
{{- end -}}

并且正常引用:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ template "mychart.app" .}}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ template "mychart.app" . }}

结果会有缩进错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: measly-whippet-configmap
labels:
app_name: mychart
app_version: "0.1.0+1478129847" #缩进错误
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0+1478129847" #缩进错误

因为template的数据只是内嵌插入,是一个‘动作’,而非‘函数’,即不能通过管道传递给其他函数,来进行格式化。

include 配合 indent 可以解决这个问题。

1
2
{{ include "mychart.app" . | indent 4 }}
引用 mychart.app 且每一行缩进4字符

上面的示例可以改为

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ include "mychart.app" . | indent 4 }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ include "mychart.app" . | indent 2 }}

文件访问

Helm通过.Files对象提供对文件的访问,例如Files.Get是一个按名称获取文件的函数(.Files.Get config.ini)。下面是几个要注意的点:

1
2
3
4
5
向Helm chart添加额外的文件是可以的。这些文件将被捆绑并发送给Tiller。不过要注意,由于Kubernetes对象的存储限制,chart必须小于1M。
通常出于安全原因,某些文件不能通过.Files对象访问。

templates/下的文件。
使用.helmignore排除的文件不能被访问。

示例:

首先创建三个文件

1
2
3
4
5
6
7
8
config1.toml:
message = Hello from config 1

config2.toml:
message = This is config 2

config3.toml:
message = Goodbye from config 3

然后,用一个range函数来遍历它们并将它们的内容注入到ConfigMap中。

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
{{- $files := .Files }}
{{- range tuple "config1.toml" "config2.toml" "config3.toml" }}
{{ . }}: |-
{{ $files.Get . }}
{{- end }}

其结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: quieting-giraf-configmap
data:
config1.toml: |-
message = Hello from config 1

config2.toml: |-
message = This is config 2

config3.toml: |-
message = Goodbye from config 3

Glob 函数

Glob是一个可以一次获取多个文件的函数。

1
2
3
4
5
6
7
8
9
假设这样的一个目录结构:
foo/:
foo.txt
foo.yaml

bar/:
bar.go
bar.conf
baz.yaml

则可以这样引用文件:

1
2
3
4
5
{{ $root := . }}
{{ range $path, $bytes := .Files.Glob "**.yaml" }}
{{ $path }}: |-
{{ $root.Files.Get $path }}
{{ end }}

或者这样:

1
2
3
{{ range $path, $bytes := .Files.Glob "foo/*" }}
{{ $path.base }}: '{{ $root.Files.Get $path | b64enc }}' # b64enc 是base64编码函数。
{{ end }}

有时候想要将文件内容放到configmap里,则可以用Glob ,ConfigMap和Secrets配合实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: ConfigMap
metadata:
name: conf
data:
{{ (.Files.Glob "foo/*").AsConfig | indent 2 }}
---
apiVersion: v1
kind: Secret
metadata:
name: very-secret
type: Opaque
data:
{{ (.Files.Glob "bar/*").AsSecrets | indent 2 }}

按行获取文件:

1
2
3
data:
some-file.txt: {{ range .Files.Lines "foo/bar.txt" }}
{{ . }}{{ end }}

预定义值

通过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增加。
  • ChartChart.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
2
3
4
imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
storage: "s3"

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
2
3
4
imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
storage: "gcs"

注意只有最后一个字段被覆盖了,其他的不变。

注:包含在chart内的默认values文件必须命名 values.yaml。但是在命令行上指定的文件可以被命名为任何名称。

注:如果在helm install或helm upgrade使用--set,则这些值仅在客户端转换为YAML。

注意:如果values文件中存在任何必需的条目,则可以使用’required’函数在chart模板中声明它们

然后可以在模板内部访问任何这些.Values对象值 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
heritage: deis
spec:
replicas: 1
selector:
app: deis-database
template:
metadata:
labels:
app: deis-database
spec:
serviceAccount: deis-database
containers:
- name: deis-database
image: {{.Values.imageRegistry}}/postgres:{{.Values.dockerTag}}
imagePullPolicy: {{.Values.pullPolicy}}
ports:
- containerPort: 5432
env:
- name: DATABASE_STORAGE
value: {{default "minio" .Values.storage}}

范围Scope,依赖Dependencies

values文件可以声明顶级chart的值,也可以为chart的charts/目录中包含的任何chart声明值。或者,用不同的方式来描述它,values文件可以为chart及其任何依赖项提供值。例如,上面的演示WordPresschart具有mysql和apache依赖性。values文件可以为所有这些组件提供值:

1
2
3
4
5
6
7
8
title: "My WordPress Site" # Sent to the WordPress template

mysql:
max_connections: 100 # Sent to MySQL
password: "secret"

apache:
port: 8080 # Passed to Apache

更高级别的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
2
3
4
5
6
7
8
9
10
11
title: "My WordPress Site" # Sent to the WordPress template

global:
app: MyWordPress

mysql:
max_connections: 100 # Sent to MySQL
password: "secret"

apache:
port: 8080 # Passed to Apache

上面添加了一个global区块,值app: MyWordPress。此值可供所有chart使用.Values.global.app

比如,该mysql模板可以访问app如.Values.global.app,apache chart也同样的。上面的values文件是这样高效重新生成的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
title: "My WordPress Site" # Sent to the WordPress template

global:
app: MyWordPress

mysql:
global:
app: MyWordPress
max_connections: 100 # Sent to MySQL
password: "secret"

apache:
global:
app: MyWordPress
port: 8080 # Passed to Apache

这提供了一种与所有子chart共享一个顶级变量的方法,这对设置metadata中像标签这样的属性很有用。

如果子chart声明了一个全局变量,则该全局将向下传递 (到子chart的子chart),但不向上传递到父chart。子chart无法影响父chart的值。

此外,父chart的全局变量优先于子chart中的全局变量。

参考

当涉及到编写模板和values文件时,有几个标准参考可以帮助你。

使用Helm管理chart

该helm工具有几个用于处理chart的命令。

它可以为你创建一个新的chart:

1
2
$ helm create mychart
Created mychart/

编辑完chart后,helm可以将其打包到chart压缩包中:

1
2
$ helm package mychart
Archived mychart-0.1.-.tgz

可以用helm来帮助查找chart格式或信息的问题:

1
2
3
$ helm lint mychart
No issues found
or $ helm test . (TBD)

删除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
2
$ helm search mychart
No results found

这是因为 Repository 目录中的 Chart 包还没有被 Helm 管理。通过 helm repo list 命令可以看到目前 Helm 中已配置的 Repository 的信息。

1
2
3
$ helm repo list
NAME URL
stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

注:新版本中执行 helm init 命令后默认会配置一个名为 local 的本地仓库。

我们可以在本地启动一个 Repository Server,并将其加入到 Helm Repo 列表中。Helm Repository 必须以 Web 服务的方式提供,这里我们就使用 helm serve 命令启动一个 Repository Server,该 Server 缺省使用 $HOME/.helm/repository/local 目录作为 Chart 存储,并在 8879 端口上提供服务。

1
2
$ helm serve &
Now serving you on 127.0.0.1:8879

默认情况下该服务只监听 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
2
3
# 更新 Helm Repository 的索引文件
$ cd /home/k8s/.helm/repository/local
$ helm repo index --url=http://192.168.100.211:8879 .

完成启动本地 Helm Repository Server 后,就可以将本地 Repository 加入 Helm 的 Repo 列表。

1
2
$ helm repo add local http://127.0.0.1:8879
"local" has been added to your repositories

现在再次查找 mychart 包,就可以搜索到了。

1
2
3
4
$ helm repo update
$ helm search mychart
NAME CHART VERSION APP VERSION DESCRIPTION
local/mychart 0.1.0 1.0 A Helm chart for Kubernetes

外部仓库

随着 Helm 越来越普及,除了使用预置官方存储库,三方仓库也越来越多了(前提是网络是可达的)。你可以使用如下命令格式添加三方 Chart 存储库。

1
2
$ helm repo add 存储库名 存储库URL
$ helm repo update

一些三方存储库资源:

1
2
3
4
5
6
7
8
9
10
11
12
# Prometheus Operator
https://github.com/coreos/prometheus-operator/tree/master/helm

# Bitnami Library for Kubernetes
https://github.com/bitnami/charts

# Openstack-Helm
https://github.com/att-comdev/openstack-helm
https://github.com/sapcc/openstack-helm

# Tick-Charts
https://github.com/jackzampolin/tick-charts

创建自己的Chart

我们创建一个名为mongodb的chart,看一看chart的文件结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ helm create mongodb
$ tree mongodb
mongodb
├── Chart.yaml #Chart本身的版本和配置信息
├── charts #依赖的chart
├── templates #配置模板目录
│ ├── NOTES.txt #helm提示信息
│ ├── _helpers.tpl #用于修改kubernetes objcet配置的模板
│ ├── deployment.yaml #kubernetes Deployment object
│ └── service.yaml #kubernetes Serivce
└── values.yaml #kubernetes object configuration

2 directories, 6 files

模板

我们查看下deployment.yaml文件的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ template "fullname" . }}
labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
spec:
replicas: {{ .Values.replicaCount }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.internalPort }}
livenessProbe:
httpGet:
path: /
port: {{ .Values.service.internalPort }}
readinessProbe:
httpGet:
path: /
port: {{ .Values.service.internalPort }}
resources:
{{ toyaml .Values.resources | indent 12 }}

这是该应用的Deployment的yaml配置文件,其中的双大括号包扩起来的部分是Go template,其中的Values是在values.yaml文件中定义的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Default values for mychart.
# This is a yaml-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service:
name: nginx
type: ClusterIP
externalPort: 80
internalPort: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi

比如在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
2
$ helm lint .
No issues found

当使用kubernetes部署应用的时候实际上讲templates渲染成最终的kubernetes能够识别的yaml格式。

使用helm install --dry-run --debug <chart_dir>命令来验证chart配置。该输出中包含了模板的变量配置与最终渲染的yaml文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

$ helm install --dry-run --debug mychart
Created tunnel using local port: '58406'
SERVER: "localhost:58406"
CHART PATH: /Users/jimmy/Workspace/github/bitnami/charts/incubator/mean/charts/mychart
NAME: filled-seahorse
REVISION: 1
RELEASED: Tue Oct 24 18:57:13 2017
CHART: mychart-0.1.0
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
image:
pullPolicy: IfNotPresent
repository: harbor-001.jimmysong.io/library/nginx
tag: 1.9
replicaCount: 1
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
service:
externalPort: 80
internalPort: 80
name: nginx
type: ClusterIP

HOOKS:
MANIFEST:

---
# Source: mychart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: filled-seahorse-mychart
labels:
chart: "mychart-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: filled-seahorse-mychart

---
# Source: mychart/templates/deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: filled-seahorse-mychart
labels:
chart: "mychart-0.1.0"
spec:
replicas: 1
template:
metadata:
labels:
app: filled-seahorse-mychart
spec:
containers:
- name: mychart
image: "harbor-001.jimmysong.io/library/nginx:1.9"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
readinessProbe:
httpGet:
path: /
port: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi

我们可以看到Deployment和Service的名字前半截由两个随机的单词组成,最后才是我们在values.yaml中配置的值。

部署到kubernetes

mychart目录下执行下面的命令将nginx部署到kubernetes集群上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
helm install .
NAME: eating-hound
LAST DEPLOYED: Wed Oct 25 14:58:15 2017
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
eating-hound-mychart 10.254.135.68 <none> 80/TCP 0s

==> extensions/v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
eating-hound-mychart 1 1 1 0 0s


NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app=eating-hound-mychart" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80

现在nginx已经部署到kubernetes集群上,本地执行提示中的命令在本地主机上访问到nginx实例。

1
2
3
export POD_NAME=$(kubectl get pods --namespace default -l "app=eating-hound-mychart" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80

在本地访问http://127.0.0.1:8080即可访问到nginx。

查看部署的relaese

1
2
3
$ helm list
NAME REVISION UPDATED STATUS CHART NAMESPACE
eating-hound 1 Wed Oct 25 14:58:15 2017 DEPLOYED mychart-0.1.0 default

删除部署的release

1
2
$ helm delete eating-hound
release "eating-hound" deleted

打包分享

我们可以修改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
2
3
4
5
6
7
8
9
10

$ cat mychart/Chart.yaml
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: mychart
version: 0.2.0

$ helm package mychart
Successfully packaged chart and saved it to: /home/k8s/mychart-0.2.0.tgz
  • 查询本地仓库中的 Chart 信息

我们可以看到在本地仓库中 mychart 有两个版本。

1
2
3
4
$ helm search mychart -l
NAME CHART VERSION APP VERSION DESCRIPTION
local/mychart 0.2.0 1.0 A Helm chart for Kubernetes
local/mychart 0.1.0 1.0 A Helm chart for Kubernetes

升级一个应用

现在用 helm upgrade 命令将已部署的 mike-test 升级到新版本。你可以通过 --version 参数指定需要升级的版本号,如果没有指定版本号,则缺省使用最新版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ helm upgrade mike-test local/mychart
Release "mike-test" has been upgraded. Happy Helming!
LAST DEPLOYED: Mon Jul 23 10:50:25 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
mike-test-mychart-6d56f8c8c9-d685v 1/1 Running 0 9m

==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mike-test-mychart ClusterIP 10.254.120.177 <none> 80/TCP 9m

==> v1beta2/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
mike-test-mychart 1 1 1 1 9m

NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app=mychart,release=mike-test" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80

完成后,可以看到已部署的 mike-test 被升级到 0.2.0 版本。

1
2
3
$ helm list
NAME REVISION UPDATED STATUS CHART NAMESPACE
mike-test 2 Mon Jul 23 10:50:25 2018 DEPLOYED mychart-0.2.0 default

回退一个应用

如果更新后的程序由于某些原因运行有问题,需要回退到旧版本的应用。首先我们可以使用 helm history 命令查看一个 Release 的所有变更记录。

1
2
3
4
$ helm history mike-test
REVISION UPDATED STATUS CHART DESCRIPTION
1 Mon Jul 23 10:41:20 2018 SUPERSEDED mychart-0.1.0 Install complete
2 Mon Jul 23 10:50:25 2018 DEPLOYED mychart-0.2.0 Upgrade complete

其次,我们可以使用下面的命令对指定的应用进行回退。

1
2
$ helm rollback mike-test 1
Rollback was a success! Happy Helming!

注:其中的参数 1 是 helm history 查看到 Release 的历史记录中 REVISION 对应的值。

最后,我们使用 helm listhelm history 命令都可以看到 mychart 的版本已经回退到 0.1.0 版本。

1
2
3
4
5
6
7
8
9
$ helm list
NAME REVISION UPDATED STATUS CHART NAMESPACE
mike-test 3 Mon Jul 23 10:53:42 2018 DEPLOYED mychart-0.1.0 default

$ helm history mike-test
REVISION UPDATED STATUS CHART DESCRIPTION
1 Mon Jul 23 10:41:20 2018 SUPERSEDED mychart-0.1.0 Install complete
2 Mon Jul 23 10:50:25 2018 SUPERSEDED mychart-0.2.0 Upgrade complete
3 Mon Jul 23 10:53:42 2018 DEPLOYED mychart-0.1.0 Rollback to 1

删除一个应用

如果需要删除一个已部署的 Release,可以利用 helm delete 命令来完成删除。

1
2
$ helm delete mike-test
release "mike-test" deleted

确认应用是否删除,该应用已被标记为 DELETED 状态。

1
2
3
$ helm ls -a mike-test
NAME REVISION UPDATED STATUS CHART NAMESPACE
mike-test 3 Mon Jul 23 10:53:42 2018 DELETED mychart-0.1.0 default

也可以使用 --deleted 参数来列出已经删除的 Release

1
2
3
$ helm ls --deleted
NAME REVISION UPDATED STATUS CHART NAMESPACE
mike-test 3 Mon Jul 23 10:53:42 2018 DELETED mychart-0.1.0 default

从上面的结果也可以看出,默认情况下已经删除的 Release 只是将状态标识为 DELETED 了 ,但该 Release 的历史信息还是继续被保存的。

1
2
3
4
5
$ helm hist mike-test
REVISION UPDATED STATUS CHART DESCRIPTION
1 Mon Jul 23 10:41:20 2018 SUPERSEDED mychart-0.1.0 Install complete
2 Mon Jul 23 10:50:25 2018 SUPERSEDED mychart-0.2.0 Upgrade complete
3 Mon Jul 23 10:53:42 2018 DELETED mychart-0.1.0 Deletion complete

如果要移除指定 Release 所有相关的 Kubernetes 资源和 Release 的历史记录,可以用如下命令:

1
2
$ helm delete --purge mike-test
release "mike-test" deleted

再次查看已删除的 Release,已经无法找到相关信息。

1
2
3
4
5
6
$ helm hist mike-test
Error: release: "mike-test" not found

# helm ls 命令也已均无查询记录。
$ helm ls --deleted
$ helm ls -a 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 流程

image

  • 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
2
3
4
5
6
7
8
9
10
dependencies:
- name: mariadb
version: 2.1.1
repository: https://kubernetes-charts.storage.googleapis.com/
condition: mariadb.enabled
tags:
- wordpress-database
- name: apache
version: 1.4.0
repository: https://kubernetes-charts.storage.googleapis.com/
  • 如何让 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)

--------------------本文结束,感谢您的阅读--------------------

本文标题:kubernetes之helm详解

文章作者:弓昭

发布时间:2019年07月31日 - 23:48

最后更新:2020年04月08日 - 22:20

原始链接:https://gongzhao1.gitee.io/kubernetes之helm详解/

联系邮箱:gongzhao1@foxmail.com