Helm的高级功能

1. 模板和试运行

当Helm安装一个发行版时,程序会经历几个阶段。它加载chart,解析传递给程序的值,读取chart元数据,等等。大约在这个过程的中间,Helm编译chart中的所有模板(一次完成),然后通过传递值来呈现它们(就像我们在上一章中看到的那样)。

在这个中间部分,它执行所有的模板指令。一旦模板被呈现到YAML中,Helm通过将其解析为Kubernetes对象来验证YAML的结构。最后,Helm序列化这些对象并将它们发送到kubernetes API服务器。

过程如下:

  1. 加载整个chart,包括其依赖项。

  2. 解析值。

  3. 执行模板,生成YAML。

  4. 将YAML解析为Kubernetes对象以验证数据。

  5. 将它发送给Kubernetes。

1.1 –dry-run标志

helm install和helm upgrade等命令提供了一个名为–dry-run的标志。当在命令行中添加此标志时,将导致Helm逐步完成前四个阶段(加载chart、确定值、渲染模板、格式化为YAML)。

但是当第四阶段结束时,Helm会将大量信息转储到标准输出,包括所有渲染的模板。然后它将退出,而不将对象发送给Kubernetes,也不创建任何发布记录。

例如,这里是以前的Drupal安装的一个版本,附加了–dry run标志:

$ helm install mysite bitnami/drupal --values values.yaml --set drupalEmail="hujinali@oschin.cn" --dry-run

在输出的最前面,它将打印有关此发布版本的信息:

NAME: mysite
LAST DEPLOYED: Sat May  7 02:14:28 2022
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:

接下来,在信息块之后,所有YAML格式的Kubernetes清单的模板都进行了渲染然后被转储到标准输出。

在试运行输出的最后,Helm打印面向用户的发行版本说明:

CHART NAME: drupal
CHART VERSION: 12.0.1
APP VERSION: 9.3.12** Please be patient while the chart is being deployed **

1. Get the Drupal URL:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w mysite-drupal'
....

1.2 helm template命令

虽然–dry-run是为调试而设计的,但helm template是为了将Helm的模板渲染过程与安装或升级逻辑隔离开来。

$ helm template mysite bitnami/drupal --values values.yaml --set drupalEmail="hujinali@oschin.cn"

前面是一个大大简化了的输出版本,只显示了命令、开始数据和结束数据的示例。

不过,需要重点注意的是,默认情况下只打印YAML格式的Kubernetes清单。

因为Helm在helm template运行期间不联系Kubernetes集群,所以它不会对输出进行完全验证。在这种情况下,Helm可能不会发现一些错误。

如果你想要这种行为,可以选择使用–validate标志,但是在这种情况下,Helm需要一个有效的kubeconfig文件,其中包含集群的凭据。

helm template命令有大量的标志,这些标志对应于helm install中的标志。因此,在许多情况下,你可以像执行helm install一样执行helm template命令,随后捕获YAML并将其与其他工具一起使用。

使用后期渲染而不是Helm模板

有时你需要截取YAML,用自己的工具修改它,然后将其加载到Kubernetes中。Helm提供了一种执行这个外部工具的方法,而不必使用helm template。install、upgrade、rollback和template上的–post-renderer标记会导致Helm将YAML数据发送到命令,然后将结果读回Helm。这是使用Kustomize等工具的好方法。

总而言之,helm template是一个用于将Helm chart渲染到YAML中的工具,–dry-run标志是一个用于调试安装和升级命令,而无须将数据加载到Kubernetes中的工具。

2. 了解发布版本信息

2.1 发布记录

每次升级mysite安装时,都会创建一个新的Secret来跟踪每个版本。换句话说,发布记录跟踪安装的每个修订版:

$ kubectl get secret

2.2 列出发布版本

$ helm ls
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
mysite  default         2               2022-05-07 02:23:59.050699352 -0400 EDT deployed        drupal-12.0.1   9.3.12

REVISION的值为2。

2.3 使用helm get查找发布的详细信息

虽然helm list提供了安装的摘要视图,但helm get命令集提供了有关特定发布版本的更深入的信息。

helm get有5个子命令(hooks、manifests、notes、values和all)。每个子命令都会检索某个版本的Helm跟踪信息的某些部分。

1.使用helm get notes

$ helm get notes mysite
NOTES:
CHART NAME: drupal
CHART VERSION: 12.0.1
APP VERSION: 9.3.12** Please be patient while the chart is being deployed **

1. Get the Drupal URL:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w mysite-drupal'

  export SERVICE_IP=$(kubectl get svc --namespace default mysite-drupal --template "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}")
  echo "Drupal URL: http://$SERVICE_IP/"

2. Get your Drupal login credentials by running:

  echo Username: admin
  echo Password: $(kubectl get secret --namespace default mysite-drupal -o jsonpath="{.data.drupal-password}" | base64 --decode)

2.使用helm get values

查看使用的values配置

$ helm get values mysite
USER-SUPPLIED VALUES:
affinity: {}
allowEmptyPassword: true
args: []
certificates:
  args: []
  command: []
  customCAs: []
  customCertificate:
    certificateLocation: /etc/ssl/certs/ssl-cert-snakeoil.pem
    certificateSecret: ""
    chainLocation: /etc/ssl/certs/mychain.pem
    chainSecret:
      key: secret-key
      name: secret-name
    keyLocation: /etc/ssl/private/ssl-cert-snakeoil.key
  extraEnvVars: []
  extraEnvVarsCM: ""
.....

查看默认值配置

$ helm inspect values bitnami/drupal|grep -v "#"|grep -v "^$"
global:
  imageRegistry: ""
  imagePullSecrets: []
  storageClass: ""
kubeVersion: ""
nameOverride: ""
fullnameOverride: ""
commonAnnotations: {}
commonLabels: {}
extraDeploy: []
image:
  registry: docker.io
  repository: bitnami/drupal
  tag: 9.3.12-debian-10-r1
  pullPolicy: IfNotPresent
  pullSecrets: []
  debug: false
replicaCount: 1
drupalProfile: standard
drupalSkipInstall: false
drupalUsername: user
drupalPassword: ""
drupalEmail: user@example.com
allowEmptyPasswo
.....

3.使用helm get manifest

此子命令获取Helm使用Chart模板生成的确切YAML清单:

$ helm get manifest mysite
---
# Source: drupal/charts/mariadb/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mysite-mariadb
  namespace: "default"
  labels:
    app.kubernetes.io/name: mariadb
    helm.sh/chart: mariadb-11.0.0
    app.kubernetes.io/instance: mysite
    app.kubernetes.io/managed-by: Helm
  annotations:
automountServiceAccountToken: false
---
# Source: drupal/charts/mariadb/templates/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysite-mariadb
  namespace: "default"
  labels:
    app.kubernetes.io/name: mariadb
    helm.sh/chart: mariadb-11.0.0
    app.kubernetes.io/instance: mysite
    app.kubernetes.io/managed-by: Helm
type: Opaque
data:
  mariadb-root-password: b3NjaGluYQ==
  mariadb-password: b3NjaGluYQ==
---
# Source: drupal/templates/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysite-drupal
  labels:
    app.kubernetes.io/name: drupal
.....

关于这个命令的一个重要细节是,它不会返回所有资源的当前状态。它返回从模板生成的清单。

有了helm get,我们可以仔细检查一个单独的发布版本。

3. 历史记录和回滚

$ helm list
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
mysite  default         2               2022-05-07 02:23:59.050699352 -0400 EDT deployed        drupal-12.0.1   9.3.12

$ helm history mysite
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Sat May  7 02:23:42 2022        superseded      drupal-12.0.1   9.3.12          Install complete
2               Sat May  7 02:23:59 2022        deployed        drupal-12.0.1   9.3.12          Upgrade complete
$ helm upgrade mysite bitnami/drupal --version 11.0.32 --values values.yaml
$ helm history mysite
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Sat May  7 02:23:42 2022        superseded      drupal-12.0.1   9.3.12          Install complete
2               Sat May  7 02:23:59 2022        superseded      drupal-12.0.1   9.3.12          Upgrade complete
3               Sat May  7 02:40:21 2022        deployed        drupal-11.0.32  9.3.11          Upgrade complete
  • superseded(已取代)

  • pending-install(挂起-安装)

  • deployed(已部署)

  • pending-rollback(挂起-回滚)

  • uninstalling(正在卸载)

  • uninstalled(已卸载)

  • failed(失败)

helm rollback的用途:

$ helm rollback mysite 2
Rollback was a success! Happy Helming!

这个命令告诉Helm获取wordpress version 2版本,并将清单重新提交给Kubernetes。回滚不会还原到集群的上一个快照。Helm没有追踪足够的信息来做到这一点。它会重新提交以前的配置,而Kubernetes尝试重置资源以匹配。

$ helm history mysite
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Sat May  7 02:23:42 2022        superseded      drupal-12.0.1   9.3.12          Install complete
2               Sat May  7 02:23:59 2022        superseded      drupal-12.0.1   9.3.12          Upgrade complete
3               Sat May  7 02:40:21 2022        superseded      drupal-11.0.32  9.3.11          Upgrade complete
4               Sat May  7 02:43:17 2022        deployed        drupal-12.0.1   9.3.12          Rollback to 2

回滚操作创建了一个新版本(4)。由于回滚是成功的(并且Kubernetes接受了修改),所以这个版本被标记为deployed。

因为Helm保存了历史记录,所以在回滚到已知的良好配置之后,仍然可以检查失败的版本。

在大多数情况下,helm rollback是从灾难中恢复过来的良好方法。

但是,如果手工编辑由Helm管理的资源,可能会出现一个有趣的问题。回滚有时会导致一些意外的行为,特别是在Kubernetes资源已经被用户手工编辑的情况下。如果这些手工编辑的内容与回滚不冲突,Helm和Kubernetes将尝试保留它们。

从本质上讲,回滚将在资源的当前状态、失败的Helm版本和回滚到的Helm版本之间产生一个三向差异。在某些情况下,生成的差异可能导致回滚手工编辑的内容,而在其他情况下,这些差异将被合并。在最坏的情况下,某些手工编辑的内容可能会被覆盖,而其他相关的编辑内容则会被合并,从而导致配置不一致。这是Helm核心维护人员建议不要手工编辑资源的众多原因之一。

如果所有的编辑都是通过Helm进行的,那么你就可以有效地使用Helm工具,而无须猜测。

3.1 保留历史和回滚

在上一章中,我们看到helm uninstall命令有一个名为–keep-history的标志。通常,删除事件将销毁与该安装相关联的所有发布记录。但是当指定–keep-history时,即使删除了安装,你也可以看到它的历史记录:

$ helm uninstall mysite --keep-history
release "mysite" uninstalled

$ helm history mysite
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Sat May  7 02:23:42 2022        superseded      drupal-12.0.1   9.3.12          Install complete
2               Sat May  7 02:23:59 2022        superseded      drupal-12.0.1   9.3.12          Upgrade complete
3               Sat May  7 02:40:21 2022        superseded      drupal-11.0.32  9.3.11          Upgrade complete
4               Sat May  7 02:43:17 2022        uninstalled     drupal-12.0.1   9.3.12          Uninstallation complete

注意,最后一个版本现在标记为已卸载(uninstalled)。当历史记录被保留时,你可以回滚已删除的安装:

$ helm rollback mysite 4
Rollback was a success! Happy Helming!

现在我们可以看到新部署的版本5:

$ helm history mysite
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Sat May  7 02:23:42 2022        superseded      drupal-12.0.1   9.3.12          Install complete
2               Sat May  7 02:23:59 2022        superseded      drupal-12.0.1   9.3.12          Upgrade complete
3               Sat May  7 02:40:21 2022        superseded      drupal-11.0.32  9.3.11          Upgrade complete
4               Sat May  7 02:43:17 2022        uninstalled     drupal-12.0.1   9.3.12          Uninstallation complete
5               Sat May  7 02:48:21 2022        deployed        drupal-12.0.1   9.3.12          Rollback to 4

如果没有–keep-history标志,这将不起作用。

4.深入了解安装和升级

4.1 –generate-name和–name-template标志

Kubernetes的工作方式有一个与命名有关的微妙危险。Kubernetes假设名称将具有某些唯一性属性。例如,Deployment对象的命名空间中必须具有唯一的名称。也就是说,在命名空间mynamespace中不能有两个名为myapp的Deployment。但可以有一个Deployment和一个Pod,它们都叫myapp。

这使得某些任务变得更加复杂。例如,自动部署内容的CI系统必须确保这些内容的名称在命名空间中是唯一的。处理这个问题的一种方法是Helm提供一个工具来生成唯一的名称。

1.使用默认名称+随机数

Helm为helm install提供–generate name标志:

$ helm install bitnami/drupal --values values.yaml --generate-name
NAME: drupal-1651906366
LAST DEPLOYED: Sat May  7 02:52:50 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: drupal
....

使用–generate name标志,我们不再需要提供名称作为helm install的第一个参数。Helm根据chart名称和时间戳的组合生成名称。在前面的输出中,我们可以看到生成的名称:drupal-1651906366。

2. 使用自定义名称

还有一个额外的标志允许你指定命名模板。–name-template标志允许你执行以下操作:

$ helm install bitnami/drupal --values values.yaml --generate-name --name-template "mysite-{{ randAlpha 9 | lower  }}"
NAME: mysite-lbrmruxpa
LAST DEPLOYED: Sat May  7 03:03:21 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1

在该模板中,我们调用randAlpha函数,从a-z、A-Z字符范围中请求一个9个字符的随机字符串。然后我们通过第二个函数(lower)将结果“管道化”,该函数将所有内容都小写化。

4.2 –create-namespace标志

Helm确实允许你通过显式地声明要创建命名空间来覆盖此考虑:

$ helm install mysite bitnami/drupal --values values.yaml -n first-test --create-namespace
NAME: mysite
LAST DEPLOYED: Sat May  7 03:06:34 2022
NAMESPACE: first-test
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: drupal

$ helm list -n first-test
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
mysite  first-test      1               2022-05-07 03:06:34.978329723 -0400 EDT deployed        drupal-12.0.1   9.3.12

在helm uninstall上没有类似的–delete-namespace。原因在于Helm对全局对象的防御性。创建命名空间后,可以将任意数量的对象放入其中,而它们不一定全都是由Helm管理的。当一个命名空间被删除时,该命名空间内的所有对象也都被删除。所以Helm不会自动删除用–create-namespace创建的命名空间。

要删除命名空间,请使用kubectl delete namespace(当然,在确保该命名空间中不存在重要对象之后再删除)。

$ helm uninstall mysite -n first-test
$ kubectl delete ns first-test

4.3 使用helm upgrade–install

这样的系统通常在无状态平台上运行基本脚本,而无状态平台没有查询Kubernetes的方法。

这类系统的用户要求Helm提供一个特性,允许在一个命令中支持“安装或升级”

为了方便这种行为,Helm维护人员在helm upgrade命令中添加了–install标志。

helm upgrade–install命令将安装一个尚不存在的版本,或者升级一个以该名称命名的版本。在底层,它通过查询Kubernetes以获得具有给定名称的发布版。

如果该版本不存在,它将从升级逻辑切换到安装逻辑。

例如,我们可以使用完全相同的命令依次运行安装和升级:

$ helm upgrade --install  mysite bitnami/drupal --values values.yaml
Release "mysite" does not exist. Installing it now.
NAME: mysite
LAST DEPLOYED: Sat May  7 03:11:18 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: drupal
CHART VERSION: 12.0.1

不过,这个命令确实带来了一些危险。Helm无法确定你提供给helm upgrade–install的安装名称是属于你要升级的发布版本,还是恰好与你要安装的名称相同。不小心使用此命令可能会导致用另一个安装覆盖某个安装。这就是它不是Helm的默认行为的原因。

4.4 –wait和–atomic标志

# 通过设置–wait参数,将等待所有Pod、PVC和Service以及Deployment、StatefulSet和ReplicaSet的最小Pod数都处于就绪状态后,然后才将Release标记为deployed状态,然后install命令行返回成功。等待–timeout时间,–timeout缺省为5m0s。
$ helm install myweb bitnami/tomcat \
  --wait \
  --set service.type=NodePort \
  --set persistence.enabled=false



# 设置–timeout参数,缺省为5m0s。如果超过–timeout还没有就绪,Release状态将被标记为failed,命令行返回值为1,但并不会回退提交给Kubernetes的资源,所以安装不一定失败。如下载镜像时间过长,Release的状态被置为failed,但Kubernetes仍在会继续下载镜像,所以安装最终会成功,但Release不会被重置为deployed。没有找到修改Release状态的命令。


#设置–atomic参数,如果安装失败,会自动清除Chart,相当于如果状态为failed时会回退所有操作,保持安装的原子性。当设置–atomic参数时,–wait参数会自动配置。
$ helm install myweb bitnami/tomcat \
  --atomic --timeout=1m \
  --set service.type=NodePort \
  --set persistence.enabled=false

4.5 使用–force和–cleanup-on-fail升级

我们下面看到的最后两个标志修改了Helm处理升级的细微差别的方式。

–force标志在升级用于管理pod(如Pod、Deployment和StatefulSet)的资源时修改Helm的行为。

通常,当Kubernetes收到修改此类对象的请求时,它会确定是否需要重新启动此资源管理的pod。

例如,某个Deployment可以运行一个pod的五个副本。但是,如果Kubernetes接收到Deployment对象的更新,它只会在某些字段被修改时重新启动这些pod。

不过,有时Helm用户希望确保pod重启。这时就用到了–force标记。它将删除并重新创建Deployment,而不是修改Deployment(或类似对象)。这迫使Kubernetes删除旧pod并创建新pod。

根据设计,使用–force会导致停机(通常只有几秒钟的停机时间)。建议仅在明确需要的情况使用–force,而不是作为默认选项。

例如,核心维护人员不建议在部署到生产环境的CI管道中使用–force。

修改升级行为的另一种方法是使用–cleanup on fail标志。类似于–force,这个标志指示Helm做额外的工作。

考虑这样一种情况:安装一个创建Kubernetes Secret的chart。一个新版本的chart被创建,它创建了第二个Secret。

但在安装过程中,Helm遇到了一个错误,并将发布标记为失败。第二个Secret有可能被挂起。如果使用–wait或–atomic,则更可能出现这种情况,因为在Kubernetes接受清单并创建资源之后,这些操作可能会失败。

–cleanup-on-fail标志将尝试修复此情况。如果失败,它将请求删除升级期间新创建的每个对象。使用它可能会使调试变得更加困难(特别是如果失败是由新创建的对象造成的),但是如果你不想冒险在失败后挂起未使用的对象,那么它是很有用的。