带认证标志的 k3s 没通过一项一致性测试
目标
在固定了版本的 k3s 上,实际挑选几个 Kubernetes 官方一致性测试来运行,并读取 JUnit 结果,区分通过、失败和超时。 你将能够根据结果说明一致性测试检查了什么,又没有检查什么。
为什么重要
选择发行版时,“Certified Kubernetes”标志看起来是一个很强的信号。但这项认证只是用一个测试集确认了 GA 且必需的 API 和行为与 upstream 一致,而且测试带有“至少两个节点”之类的前提。 性能、可用性、安全配置和可选功能都不在范围内。要正确解读这个标志,就必须亲自看看测试由什么构成, 以及失败是以什么形式记录的。另外,测试二进制文件与服务器的版本不一致时,结果本身就失去意义, 所以要从对齐版本开始。最后,故意破坏 DNS,让同一个测试失败,再在恢复之后重新通过, 你会发现一致性测试也可以用作“恢复确认工具”。
步骤
- 在
/root/conformance/versions.json中写入server(API 服务器的 gitVersion)、server_minor(1.36格式)、e2e_test(e2e.test --version的输出)、ginkgo(仅ginkgo version的版本号,例如2.0.0)、same_minor(服务器与 e2e.test 的次版本是否相同,布尔值)。 - 读取
/usr/local/conformance/conformance.yaml(v1.36.4 标签的列表),在/root/conformance/catalog.json中写入total(条目数)、sig_network(codename 以[sig-network]开头的条目数)、dns_tests(codename 以[sig-network] DNS开头的 codename 排序后的数组)、dns_cluster_release([sig-network] DNS should provide DNS for the cluster [Conformance]的 release 值)。 - 用
--ginkgo.dry-run运行e2e.test两次,在/root/conformance/dryrun.json中写入conformance_will_run(focus 为\[Conformance\]时将运行的 spec 数)、total_specs(spec 总数)、dns_will_run(focus 为\[sig-network\] DNS.*\[Conformance\]时将运行的数量)、matches_catalog(conformance_will_run 是否等于第 2 步的 total,布尔值)。 - 只用
[sig-network] DNS should provide DNS for the cluster [Conformance]作为 focus 运行,把 JUnit 结果保存到/root/conformance/dns-pass/junit_01.xml(使用--report-dir),把标准输出和标准错误保存到/root/conformance/dns-pass/e2e.log。必须通过。 - 运行
[sig-architecture] Conformance Tests should have at least two untainted nodes [Conformance],把结果保存到/root/conformance/two-nodes/junit_01.xml、/root/conformance/two-nodes/e2e.log,并在/root/conformance/two-nodes.json中写入status(JUnit 中该 testcase 的 status)、reason(e2e.log 的[FAILED]行中,不是源码位置(in [It] - ...)而是写有原因的那一行的句子)、schedulable_nodes(当前没有污点的 Ready 节点数,数字)。 - 将 kube-system 中的 coredns Deployment 缩减为 0,确认 Pod 消失之后,用
--ginkgo.timeout=45s运行与第 4 步相同的 DNS 测试,把结果保存到/root/conformance/dns-broken/junit_01.xml、/root/conformance/dns-broken/e2e.log。在/root/conformance/broken.json中写入coredns_replicas(运行前一刻的 spec.replicas)、coredns_pods(运行前一刻的 CoreDNS Pod 数)、status(JUnit 中该 testcase 的 status)。恢复在下一步进行。 - 把 coredns 恢复为 1,使其变为 Available,然后重新运行同一个 DNS 测试,把结果保存到
/root/conformance/dns-restored/junit_01.xml、/root/conformance/dns-restored/e2e.log。必须通过。 - 在
/root/conformance/report.json中写入server(服务器 gitVersion)、catalog_total(第 2 步的 total)、passed(第 4、7 步中通过的 testcase 名称,去掉[It]并去重后排序的数组)、failed_single_node(第 5 步中失败的测试 codename)、timed_out_when_broken(第 6 步的结果是否为超时,布尔值)、submission_files(提交到 CNCF 认证 PR 的四个文件名排序后的数组)、certified_focus(认证运行所要求的 E2E_FOCUS 值,原样写入)、skip_allowed(认证运行中是否可以设置 E2E_SKIP,布尔值)。
参考
- VM 中有一台 k3s v1.36.4+k3s1,同一版本的
e2e.test、ginkgo、conformance.yaml位于/usr/local/conformance。测试镜像已提前下载。 - 基本运行形式:
e2e.test --kubeconfig $KUBECONFIG --provider skeleton --ginkgo.no-color --report-dir <디렉터리> --ginkgo.focus='<정규식>' - 常见错误:没有对 focus 中的方括号做转义。它会被当作正则表达式的字符集,结果选中几百个毫不相干的测试。请先用
--ginkgo.dry-run确认数量。 - 常见错误:在没有设置超时的情况下运行第 6 步。它会等待 DNS 结果 600 秒。
- 本实验不运行完整的一致性测试(446 项)。k3s 的认证提交在双节点配置下耗时约 2 小时 54 分钟。
- 文档:cncf/k8s-conformance · instructions.md · Conformance Testing in Kubernetes
对齐测试二进制文件与服务器的版本
在 /root/conformance/versions.json 中写入 server(API 服务器的 gitVersion)、server_minor(1.36 格式)、e2e_test(e2e.test --version 的输出)、ginkgo(仅 ginkgo version 的版本号,例如 2.0.0)、same_minor(服务器与 e2e.test 的次版本是否相同,布尔值)。
测试二进制文件位于 /usr/local/conformance。k3s 的版本会带有 +k3s1 这样的后缀。一致性测试的列表随版本而不同,因此必须使用与集群版本同一发布分支构建的测试,结果才有意义。
读取一致性测试列表
读取 /usr/local/conformance/conformance.yaml(v1.36.4 标签的列表),在 /root/conformance/catalog.json 中写入 total(条目数)、sig_network(codename 以 [sig-network] 开头的条目数)、dns_tests(codename 以 [sig-network] DNS 开头的 codename 排序后的数组)、dns_cluster_release([sig-network] DNS should provide DNS for the cluster [Conformance] 的 release 值)。
这是 YAML,有些条目的 codename 被折叠成了多行。用 grep 按行统计会出错,请用 python3 的 yaml 模块读取。每个条目都有 testname、codename、description、release、file 这些键。release 是该测试被纳入一致性测试时的版本。
运行之前先统计范围
用 --ginkgo.dry-run 运行 e2e.test 两次,在 /root/conformance/dryrun.json 中写入 conformance_will_run(focus 为 \[Conformance\] 时将运行的 spec 数)、total_specs(spec 总数)、dns_will_run(focus 为 \[sig-network\] DNS.*\[Conformance\] 时将运行的数量)、matches_catalog(conformance_will_run 是否等于第 2 步的 total,布尔值)。
dry-run 不会在集群中创建任何东西,只显示会选中哪些 spec。读取输出中的 Will run N of M specs 这一行。加上 --ginkgo.no-color 可以避免混入颜色代码。
真正运行一个一致性测试
只用 [sig-network] DNS should provide DNS for the cluster [Conformance] 作为 focus 运行,把 JUnit 结果保存到 /root/conformance/dns-pass/junit_01.xml(使用 --report-dir),把标准输出和标准错误保存到 /root/conformance/dns-pass/e2e.log。必须通过。
focus 是正则表达式,所以必须转义方括号。如果只写名称的一部分,名称相近的测试可能会被一起选中,请先用 dry-run 确认只有 1 个。JUnit 中也会把跳过的 spec 全部以 skipped 记录下来。
单节点集群会失败的一致性测试
运行 [sig-architecture] Conformance Tests should have at least two untainted nodes [Conformance],把结果保存到 /root/conformance/two-nodes/junit_01.xml、/root/conformance/two-nodes/e2e.log,并在 /root/conformance/two-nodes.json 中写入 status(JUnit 中该 testcase 的 status)、reason(e2e.log 的 [FAILED] 行中,不是源码位置(in [It] - ...)而是写有原因的那一行的句子)、schedulable_nodes(当前没有污点的 Ready 节点数,数字)。
这个测试失败才是正常的。请与一致性提交中 k3s 使用的测试配置(cncf/k8s-conformance 的 README)做比较。在 JUnit 中同时查看 failure 子元素和 status 属性。
缩减 CoreDNS 并运行同一个测试
将 kube-system 中的 coredns Deployment 缩减为 0,确认 Pod 消失之后,用 --ginkgo.timeout=45s 运行与第 4 步相同的 DNS 测试,把结果保存到 /root/conformance/dns-broken/junit_01.xml、/root/conformance/dns-broken/e2e.log。在 /root/conformance/broken.json 中写入 coredns_replicas(运行前一刻的 spec.replicas)、coredns_pods(运行前一刻的 CoreDNS Pod 数)、status(JUnit 中该 testcase 的 status)。恢复在下一步进行。
这个测试会等待 DNS 查询结果 600 秒,所以不设超时运行会停住 10 分钟。测试套件的超时结束后,ginkgo 记录的不是失败,而是超时。请在 e2e.log 中找一找哪些名称的查询失败了。
恢复之后用同一个测试来证明
把 coredns 恢复为 1,使其变为 Available,然后重新运行同一个 DNS 测试,把结果保存到 /root/conformance/dns-restored/junit_01.xml、/root/conformance/dns-restored/e2e.log。必须通过。
确认恢复最可靠的方法,是让破坏时失败的那个测试重新通过。即使上一次运行的命名空间仍处于 Terminating 状态,测试也会创建新的命名空间。
用一致性的语言解读结果
在 /root/conformance/report.json 中写入 server(服务器 gitVersion)、catalog_total(第 2 步的 total)、passed(第 4、7 步中通过的 testcase 名称,去掉 [It] 并去重后排序的数组)、failed_single_node(第 5 步中失败的测试 codename)、timed_out_when_broken(第 6 步的结果是否为超时,布尔值)、submission_files(提交到 CNCF 认证 PR 的四个文件名排序后的数组)、certified_focus(认证运行所要求的 E2E_FOCUS 值,原样写入)、skip_allowed(认证运行中是否可以设置 E2E_SKIP,布尔值)。
请从前面步骤的 JUnit 文件中重新读取名称和状态。提交文件以及 focus 和 skip 的规则,写在 cncf/k8s-conformance 的 instructions.md 中。