Helm可以帮助我们管理kubernetes应用程序-Helm Charts可以定义、安装和升级复杂的kubernetes应用程序,Charts包很容易创建、版本管理、分享和分布。Helm对于kubernetes来说就相当于yum对于centos来说,如果没有yum的话,在centos下安装一些应用程序就极度麻烦,同样的对于越复杂的kubernetes应用程序来说,如果单纯依靠我们手动维护应用程序的YAML资源清单来说,成本也是巨大的。

安装

首先需要一个k8s集群,然后在使用Helm的节点上配置好可以通过kubectl访问集群,因为Helm其实就是读取kubeconfig文件来访问集群的。

由于Helm V2版本必须在k8s集群中安装一个Tiller服务进行通信,这样大大降低了其安全性和可用性,所以在V3版本中移除了服务端,采用了通用的Kubernetes CRD资源来进行管理,这样就只需要连接上k8s即可。软件包下载地址:https://github.com/helm/helm/releases,我们可以根据自己的节点选择合适的包。

下载到本地解压后,将 helm 二进制包文件移动到任意的 PATH 路径下即可:

  1. $ helm version
  2. version.BuildInfo{Version:"v3.4.2", GitCommit:"23dd3af5e19a02d4f4baa5b2f242645a1a3af629", GitTreeState:"clean", GoVersion:"go1.14.13"}

一旦Helm客户端准备成功后,就可以添加一个chart仓库,最常用的就是官方的Helm stable charts仓库,但是官方仓库地址需要科学上网,所以使用微软的charts仓库代替:

$ helm repo add stable http://mirror.azure.cn/kubernetes/charts/
$ helm repo list
NAME            URL
stable          http://mirror.azure.cn/kubernetes/charts/

安装完成后可以用search命令来搜索可以安装的chart包:

$ helm search repo stable
NAME                                    CHART VERSION   APP VERSION                     DESCRIPTION
stable/acs-engine-autoscaler            2.2.2           2.1.1                           DEPRECATED Scales worker nodes within agent pools
stable/aerospike                        0.3.1           v4.5.0.5                        A Helm chart for Aerospike in Kubernetes
stable/airflow                          5.2.1           1.10.4                          Airflow is a platform to programmatically autho...
stable/ambassador                       5.1.0           0.85.0                          A Helm chart for Datawire Ambassador
stable/anchore-engine                   1.3.7           0.5.2                           Anchore container analysis and policy evaluatio...
stable/apm-server                       2.1.5           7.0.0                           The server receives data from the Elastic APM a...
......

示例

为了安装一个chart包,我们可以使用helm install命令,Helm有多种方法来找到和安装chart包,但是最简单的方法是使用官方的stable这个仓库直接安装:

首先从仓库中将可用的charts信息同步到本地,可以确保我们获取到最新的charts列表:

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈

比如现在安装一个mysql应用:

$ helm install stable/mysql --generate-name
NAME: mysql-1575619811
LAST DEPLOYED: Fri Dec  6 16:10:14 2019
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
mysql-1575619811.default.svc.cluster.local
......

可以看到stable/mysql这个chart已经安装成功了,我们将安装成功的这个应用叫做一个release,由于在安装的时候指定了--generate-name参数,所以生成的release名称是随即生成的,名为mysql-1575619811,用下面的命令来查看release安装以后对应的k8s资源的状态:

$ kubectl get all -l release=mysql-1575619811
NAME                                    READY   STATUS    RESTARTS   AGE
pod/mysql-1575619811-8479b5b796-dgggz   0/1     Pending   0          27m

NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/mysql-1575619811   ClusterIP   10.106.141.228   <none>        3306/TCP   27m

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql-1575619811   0/1     1            0           27m

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/mysql-1575619811-8479b5b796   1         1         0       27m

使用helm show chart命令来了解Mysql这个chart包的一些特性:

$ helm show chart stable/mysql
......

使用helm show all查看更多信息:

$ helm show all stable/mysql
......

需要注意的是无论什么时候安装chart,都会创建一个新的release,所以一个chart包是可以多次安装到同一个集群中的,每次都可以独立管理和升级。

同样也可以使用Helm查看到已经安装的release:

$ helm ls
NAME                NAMESPACE   REVISION    UPDATED                                 STATUS      CHART       APP VERSION
mysql-1575619811    default     1           2019-12-06 16:10:14.682302 +0800 CST    deployed    mysql-1.5.0 5.7.27

如果需要删除这个release使用helm uninstall命令即可:

$ helm uninstall mysql-1575619811
release "mysql-1575619811" uninstalled
$ kubectl get all -l release=mysql-1575619811
No resources found.
$ helm status mysql-1575619811
Error: release: not found

unistall命令会从k8s中删除release,也会删除与release相关的所有的k8s资源以及release历史记录。也可以在删除的时候使用—keep-history参数,则会保留release的历史记录,可以获取该release的状态就是UNINSTALLED,而不是找不到release了:

$ helm uninstall mysql-1575619811 --keep-history
release "mysql-1575619811" uninstalled
$ helm status mysql-1575619811
helm status mysql-1575619811
NAME: mysql-1575619811
LAST DEPLOYED: Fri Dec  6 16:47:14 2019
NAMESPACE: default
STATUS: uninstalled
...
$ helm ls -a
NAME                NAMESPACE   REVISION    UPDATED                                 STATUS      CHART       APP VERSION
mysql-1575619811    default     1           2019-12-06 16:47:14.415214 +0800 CST    uninstalled mysql-1.5.0 5.7.27

因为Helm会在删除release后跟踪你的release,所以你可以审查历史甚至取消删除release(使用helm rollback命令)。

定制

上面都是直接使用helm命令安装的chart包,这种情况下只会使用chart的默认配置选项,但是更多的时候,是各种各样的需求,所以希望能根据自己的需求来定制chart包的配置参数。

使用helm show values命令来查看一个chart包的所有的可配置的参数选项:

$ helm show values stable/mysql
## mysql image version
## ref: https://hub.docker.com/r/library/mysql/tags/
##
image: "mysql"
imageTag: "5.7.14"

busybox:
  image: "busybox"
  tag: "1.29.3"

testFramework:
  enabled: true
  image: "dduportal/bats"
  tag: "0.4.0"

## Specify password for root user
##
## Default: random 10 character string
# mysqlRootPassword: testing

## Create a database user
##
# mysqlUser:
## Default: random 10 character string
# mysqlPassword:

## Allow unauthenticated access, uncomment to enable
##
# mysqlAllowEmptyPassword: true

## Create a database
##
# mysqlDatabase:

## Specify an imagePullPolicy (Required)
## It's recommended to change this to 'Always' if the image tag is 'latest'
## ref: http://kubernetes.io/docs/user-guide/images/#updating-images
##
imagePullPolicy: IfNotPresent
......

上面看到的所有参数都是可以用自己的数据来覆盖的,可以在安装的时候通过YAML格式的文件来传递这些参数:

$ cat config.yaml
mysqlUser:
  user0
mysqlPassword: user0pwd
mysqlDatabase: user0db
persistence:
  enabled: false
$ helm install -f config.yaml stable/mysql
helm install -f config.yaml mysql stable/mysql
NAME: mysql
LAST DEPLOYED: Fri Dec  6 17:46:56 2019
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
mysql.default.svc.cluster.local
......

release安装成功后,可以查看对应的Pod信息:

$ kubectl get pod -l release=mysql
NAME                    READY   STATUS            RESTARTS   AGE
mysql-ddd798f48-gnrzd   0/1     PodInitializing   0          119s
$ kubectl describe pod  mysql-ddd798f48-gnrzd
......
Environment:
      MYSQL_ROOT_PASSWORD:  <set to the key 'mysql-root-password' in secret 'mysql'>  Optional: false
      MYSQL_PASSWORD:       <set to the key 'mysql-password' in secret 'mysql'>       Optional: false
      MYSQL_USER:           user0
      MYSQL_DATABASE:       user0db
......

可以看到环境变量MYSQL_USER=user0, MYSQL_DATABASE=user0db的值和上面配置的值是一致的。在安装过程中,有两种方法可以传递配置数据:

  • --values(或者-f):指定一个YAML文件来覆盖values值,可以指定多个值,最后边的文件优先
  • --set:在命令行上指定覆盖的配置

如果同时使用这两个参数,--values(-f)将被合并到具有更高优先级的--set,使用--set指定的值将持久化在ConfigMap中,对于给定的release,可以使用helm get values <release name>来查看已经设置的值,已设置的值也可以通过允许helm upgrade并指定--reset值来清除。

—set选项接收零个或多个name/value对,最简单的用法就是--set name=value,相当于YAML文件中的:

name: value

多个值之间的字符串”,”隔开,用法就是--set a=b,c=d,相当于YAML文件中的:

a: b
c: d

也支持更加复杂的表达式,例如--set outer.inner=value,相当于YAML文件中的:

outer:
  inner: value

对于列表数组可以用{}来包裹,比如--set name={a, b, c},相当于YAML文件中的:

name:
  - a
  - b
  - c

从Helm2.5.0开始,就可以使用数组索引语法来访问列表中某个项,比如--set servers[0].port=80,相当于YAML文件中的:

servers:
  - port: 80

也可以设置多个值,比如--set servers[0].port=80,server[0].host=example,相当于YAML文件中的:

servers:
  - port: 80
    host: example

有时候需要在—set选项中使用特殊字符,这时候可以用反斜杠来转义字符,比如--set name=value1\,value2,相当于YAML文件中的:

name: "value1,value2"

类似的,还可以转义”.”,当chart模板中使用toYaml函数来解析annotations、labels以及node selectors之类的时候,这非常有用,比如--set nodeSelector."kubernetes\.io/role"=master,相当于YAML文件中的:

nodeSelector:
  kubernetes.io/role: master

深度嵌套的数据结构可能很难使用—set表示,所以一般推荐还是使用YAML文件来进行覆盖,在设计chart模板的时候也可以结合考虑到--set这种用法。

更多安装方式

helm install命令可以从多个源进行安装:

  • chart仓库
  • 本地chart压缩包(helm install foo-0.1.1.tgz)
  • 本地解压缩的chart目录(helm install foo path/to/foo)
  • 在线的URL(helm install foo https://example.com/charts/foo-1.2.3.tgz

升级和回滚

当新版本的chart包发布的时候,或者当你要更改release的配置的时候,你可以使用helm upgrade命令来操作。升级需要一个现有的release,并根据提供的信息对其进行升级。因为k8s chart可能很大而且很复杂,helm会尝试以最小的侵入性进行升级,它只会更新自上一版本以来发生的变化:

$ helm upgrade -f panda.yaml mysql stable/mysql
helm upgrade -f panda.yaml mysql stable/mysql
Release "mysql" has been upgraded. Happy Helming!
NAME: mysql
LAST DEPLOYED: Fri Dec  6 21:06:11 2019
NAMESPACE: default
STATUS: deployed
REVISION: 2
...

mysql这个release用相同的chart包进行升级,但是新增了一个配置项:

mysqlRootPassword: passw0rd

使用helm get values来查看新设置是否生效:

$ helm get values mysql
USER-SUPPLIED VALUES:
mysqlDatabase: user0db
mysqlPassword: user0pwd
mysqlRootPassword: passw0rd
mysqlUser: user0
persistence:
  enabled: false

helm get是查看集群中 release 的非常有用的命令,它显示了panda.yaml中的新配置值被部署到了集群中,现在如果某个版本在发布期间没有按计划进行,那么可以使用helm rollback [RELEASE] [REVISION]命令很容易回滚到之前的版本:

$ helm ls
NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART       APP VERSION
mysql   default     2           2019-12-06 21:06:11.36358 +0800 CST     deployed    mysql-1.5.0 5.7.27
$ helm history mysql
REVISION    UPDATED                     STATUS      CHART       APP VERSION DESCRIPTION
1           Fri Dec  6 17:53:03 2019    superseded  mysql-1.5.0 5.7.27      Install complete
2           Fri Dec  6 21:06:11 2019    deployed    mysql-1.5.0 5.7.27      Upgrade complete
$ helm rollback mysql 1
Rollback was a success! Happy Helming!
$ kubectl get pods -l release=mysql
NAME                    READY   STATUS    RESTARTS   AGE
mysql-ddd798f48-gnrzd   1/1     Running   0          3h25m
$ helm get values mysql
USER-SUPPLIED VALUES:
mysqlDatabase: user0db
mysqlPassword: user0pwd
mysqlUser: user0
persistence:
  enabled: false

可以看到values配置已经回滚到之前的版本了。上面的命令回滚到了release的第一个版本,每次进行安装、升级或回滚时,修订号都会加1,第一个修订号始终为1,可以使用helm history [release]查看某个版本的修订号。

除此之外,还可以指定一些有用的选项来制定install/upgrade/rollback的一些行为,要查看完整的参数标志,可以运行helm <command> --help来查看。

  • --timeout:等待k8s命令完成时间,默认是300s
  • --wait:等待所有Pod都处于就绪状态、PVCs已经绑定、Deployment具有处于就绪状态的最小Pod数量(期望值减去maxUnavailable)以及Service有一个IP地址,然后才标记release为成功状态。它将等待与—timeout值一样长的时间,如果达到超时,则release将标记为失败。注意,在Deployment将副本设置为1并且作为滚动更新的一部分,maxUnavailable未设置为0的情况下,—wait将返回就绪状态,因为它已满足就绪状态下的最小Pod数量
  • --no-hooks:将会跳过命令的运行hooks
  • --recreate-pod:仅适用upgrade和rollback,这个标志将导致重新创建所有的Pod。(helm3中启用)