大家好,我是张晋涛。
在上一篇 《企业级云原生应用交付及管理系列 - Helm 基础 (一)》 中,我主要介绍了 Helm 的诞生及其发展,包括 Helm 各个版本的情况及社区的发展。
此外,还介绍了 Helm 的架构,概念,插件以及其基本用法。
本节我将默认读者已经有一定的 Helm 和 Kubernetes 基础, 介绍 Helm 的一些高阶特性和用法, 如果有不清楚的概念可以看我的历史文章。
准备
这里我们使用 helm create
命令来创建一个 Helm chart。执行完成后,会在当前目录创建一个新的目录,其中包含了 Helm 预先创建的一个模板。本文中的后续内容均会基于该 Helm chart 完成。
tao@moelove:~$ helm create moelove
Creating moelove
tao@moelove:~$ ls
moelove
tao@moelove:~$ tree
.
└── moelove
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
4 directories, 10 files
Debug
在我们去创建/维护,或者使用 Helm chart 进行应用部署的时候,有时候可能会遇到一些错误。那么如何对 Helm chart 进行 debug 呢?这是很多人都会遇到的一个问题。
Helm chart 是通过 YAML 进行维护的,而 YAML 是缩进/语法敏感的。假如你的缩进或者语法有问题,都将会导致报错。最简单的检查办法是使用 helm lint
进行检查。
比如我们进行如下修改:
代码语言:javascript复制diff --git a/values.yaml b/values.yaml
index 4a8b237..696a77d 100644
--- a/values.yaml
b/values.yaml
@@ -5,7 5,7 @@
replicaCount: 1
image:
- repository: nginx
repository: nginx
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
可以看到,我们将 image.repository
的缩进搞错了。这时进行安装将看到如下报错:
tao@moelove:~$ helm install foo .
Error: INSTALLATION FAILED: cannot load values.yaml: error converting YAML to JSON: yaml: line 9: mapping values are not allowed in this context
我建议你可以使用 helm lint
先进行检查,避免一些低级错误。如下:
tao@moelove:~$ helm lint .
==> Linting .
[INFO] Chart.yaml: icon is recommended
[ERROR] values.yaml: unable to parse YAML: error converting YAML to JSON: yaml: line 9: mapping values are not allowed in this context
[ERROR] templates/: cannot load values.yaml: error converting YAML to JSON: yaml: line 9: mapping values are not allowed in this context
[ERROR] : unable to load chart
cannot load values.yaml: error converting YAML to JSON: yaml: line 9: mapping values are not allowed in this context
Error: 1 chart(s) linted, 1 chart(s) failed
我们将该内容恢复原样,并进行如下变更:
代码语言:javascript复制diff --git a/values.yaml b/values.yaml
index 4a8b237..c86c0be 100644
--- a/values.yaml
b/values.yaml
@@ -2,7 2,7 @@
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
-replicaCount: 1
replicaCount: "this should not be string"
image:
repository: nginx
将 replicaCount
修改成了一段字符串。这时候我们使用 helm lint
是无法检查出来的。
tao@moelove:~$ helm lint .
==> Linting .
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
因为从 YAML 语法上是无法检查出来类型的,并且这也是我们具体的业务逻辑(Kubernetes)限制的。
这时,如果进行安装将得到如下错误:
代码语言:javascript复制tao@moelove:~$ helm install foo .
Error: INSTALLATION FAILED: unable to build kubernetes objects from release manifest: error validating "": error validating data: ValidationError(Deployment.spec.replicas): invalid type for io.k8s.api.apps.v1.DeploymentSpec.replicas: got "string", expected "integer"
可以看到,对于这种类型错误是可以很直接的得到反馈的。
但还有一种情况,就是语法规则,类型均正常,但是不符合业务的实际预期。
比如我们进行如下变更:
代码语言:javascript复制diff --git a/values.yaml b/values.yaml
index 4a8b237..8feedd6 100644
--- a/values.yaml
b/values.yaml
@@ -8,7 8,7 @@ image:
repository: nginx
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
- tag: ""
tag: "1.20"
imagePullSecrets: []
nameOverride: ""
这时,可以安装成功,但可能我们预期想要安装的镜像是 1.20-alpine
。这种场景下,上述两种方式就都没有效果了。
我们可以通过 helm install --dry-run --debug
命令进行调试。当然,如果你想通过 helm template
进行调试也可以。
这两者主要的区别在于,如果增加了 --debug
参数的话,可以输出更加详细的信息, 包括最终使用的 Values 信息等。
这是我比较推荐的做法,适合在你开发/调试 Helm chart 时使用。
Helm 单元测试
谈到 Helm chart 的单元测试,你可能会产生疑问,YAML 也要写单元测试?
是的。如果你是 Helm chart 的维护者的话,写单元测试是个好主意,可以更好的保证大多数内容都是符合预期的。
如果想要为 Helm chart 写单元测试,我有三个工具推荐。
- quintush/helm-unittest 是从 helm-unittest/helm-unittest fork 出来的,但是它更加活跃,并且包含了很多功能和修复,此外,它可以很好的与 Helm 3 配合使用;
- conftest 这是基于 Open Policy Agent (OPA) 的一个工具,通过使用 Rego 编写策略文件来完成配置的校验。我现在在 Apache APISIX Ingress controller 项目中使用它,辅助用户进行升级检查;
- terratest 这是一个使用 Go 开发的通用测试框架,支持多种配置的测试,包括 Helm,AWS/Docker 等;
其中我最喜欢的是 conftest ,因为我更喜欢写 Rego ,对 OPA 感兴趣的小伙伴可以参考我之前的文章 《Open Policy Agent(OPA) 入门实践》 。最简单的则是 helm-unittest 了,它更加专注一些。
这里我们使用 helm-unittest 作为示例。
安装
helm-unittest 可以作为 Helm Plugin 进行安装,执行以下命令即可:
代码语言:javascript复制tao@moelove:~$ helm plugin install https://github.com/quintush/helm-unittest
Support linux-amd64
...
Installed plugin: unittest
测试
只要在 chart 目录下创建一个 tests
目录,在其中编写测试文件即可。
tao@moelove:~$ cat tests/deployment_test.yaml
suite: test deployment
templates:
- deployment.yaml
tests:
- it: should work
set:
image.tag: latest
asserts:
- isKind:
of: Deployment
- matchRegex:
path: metadata.name
pattern: -moelove$
- equal:
path: spec.template.spec.containers[0].image
value: nginx:latest
我可以通过如下方式进行运行,注意,一定要增加 -3
参数,以便可以和 Helm v3 进行兼容。
tao@moelove:~$ helm unittest -3 .
### Chart [ moelove ] .
PASS test deployment tests/deployment_test.yaml
Charts: 1 passed, 1 total
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshot: 0 passed, 0 total
Time: 5.932023ms
我们可以此 case 做些调整,看看如果测试不通过会是什么情况:
代码语言:javascript复制tao@moelove:~$ cat tests/deployment_test.yaml
suite: test deployment
templates:
- deployment.yaml
tests:
- it: should work
set:
image.tag: alpine
asserts:
- isKind:
of: Deployment
- matchRegex:
path: metadata.name
pattern: -moelove$
- equal:
path: spec.template.spec.containers[0].image
value: nginx:latest
这里我们给 image.tag
设置为 alpine
,但是在断言中没有让其匹配,所以执行测试后会看到失败。
tao@moelove:~$ helm unittest -3 .
### Chart [ moelove ] .
FAIL test deployment tests/deployment_test.yaml
- should work
- asserts[2] `equal` fail
Template: moelove/templates/deployment.yaml
DocumentIndex: 0
Path: spec.template.spec.containers[0].image
Expected to equal:
nginx:latest
Actual:
nginx:alpine
Diff:
--- Expected
Actual
@@ -1,2 1,2 @@
-nginx:latest
nginx:alpine
Charts: 1 failed, 0 passed, 1 total
Test Suites: 1 failed, 0 passed, 1 total
Tests: 1 failed, 0 passed, 1 total
Snapshot: 0 passed, 0 total
Time: 5.22252ms
Error: plugin "unittest" exited with error
我们可以很清晰的看到具体失败的原因和位置。
如果你在维护 Helm chart,并且需要保证其能够高质量交付,那么为其增加单元测试是个不错的办法。至于工具的选择,主要看个人喜好。helm-unittest 只需要写 YAML, 而其他两个工具分别是写 Rego 和 Go 。
总结
在本文中,我们主要聚焦到了 Helm chart 的调试和维护这个主题上。介绍了 Helm 内置的对 chart 的一些检查工具,同时也介绍了如何使用 helm-unittest 为 Helm chart 编写 单元测试。
在维护,交付和使用 Helm chart 时,掌握这些内容都是非常有用的。
如果大家对这个主题感兴趣的话,后续我还会更新 Helm 的一些进阶内容,敬请期待!