Files
Deploy-Laboratory/docs/00-05-测试与验证框架.md
jack 231b6713c4 chore: 对齐 00-05 §2 的部署与验证脚本
- 新增 deploy-lab.sh(k3s/longhorn/nginx 铺栈)与 ssh/run-phase2-k3s-on-ylc61-as-jack.sh
- verify.sh:flow/preflight、VERIFY_TEARDOWN 默认、注释与 §2 对应
- 更新 smoke-verify、README、.env.verify.example、根 README 与主要 playbook 头注释
- k3s-delete-lab-stacks 标明重度清场语义

Made-with: Cursor
2026-03-26 07:32:08 +08:00

198 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 00-05-测试与验证框架(设计说明)
> 本页是“测试与验证框架”的设计说明,并与仓库里已落地的 `scripts/verify.sh` + `ansible/playbooks/verify/` 对齐。
## 1. 为什么需要它
仓库里 `docs/00-02-验证矩阵.md` 目前扮演“待验证列表/状态记录”的角色,用来回答:
- 这篇文档(`XX-YY`)是否已经在你的实验环境中从头到尾跑通?
- 如果没跑通,缺口在哪里?
而“自动化执行”和“状态记录”是两件不同的事。测试框架需要把自动化执行能力,拆成可维护的小块,并通过统一的 id/索引把文档与用例关联起来。
## 2. 自动化验证流程(一般步骤)
下面是一条**从操作者视角**的通用流水线;本仓库里对应关系已写在各步括号中。
1. **接入目标环境**
- 用 SSH 登录**控制节点**(或在本机配置好到控制节点的 Ansible `inventory`,由 Ansible 代你 SSH
- 在仓库根(或文档约定目录)准备好代码:`git pull` / `scp` 同步等,与 [`docs/00-04-部署环境说明.md`](00-04-部署环境说明.md) 一致。
- 按需加载验证环境变量:复制并填写 [`scripts/.env.verify.example`](../scripts/.env.verify.example) 为 `scripts/.env.verify`,执行前 `source``verify.sh` 会自动尝试加载)。
2. **环境与前置清理(按验证目标选择深度)**
- **基本检查**`kubectl get nodes`、磁盘/内核版本、防火墙与文档是否一致;必要时对照 `00-04`
- **轻量清理(本仓库 `verify.sh` 的常态)**:默认不卸载整个 K3s每个 `verify/XX-YY.yml`**teardown** 阶段只删除**本篇** apply 过的资源(或 gate 未执行 apply 时跳过删除),避免污染下一用例。
- **重度清理(重装/复现安装文档时)**:若你要从「空机」验证 `01-01` 等**整集群安装**流程,才需要按文档执行 `k3s-uninstall.sh`、删数据目录、清 iptables 等——这与日常「矩阵逐项验收」是**不同场景**,不要默认混进每一次 `run-all`
3. **部署**
- **推荐(本仓库)**:用 Ansible playbook 部署——要么是正式安装/初始化类(如 `k3s-init-and-install.yml`),要么是验证用例里的 `kubectl apply` / `helm install` / `import_playbook`
- **文档中的 bash 一键命令**:仍可按 `docs/` 逐步执行;适合排障或 playbook 尚未覆盖的边角。自动化验收应尽量**收敛进** `ansible/playbooks/verify/*.yml`,避免「文档一套、手敲一套」长期分叉。
4. **按设计目标做断言**
- **集群侧**`kubectl get` / `describe` / `logs``kubectl rollout status`、必要时看事件与 `Endpoints`
- **入口侧**:在控制节点或文档指定的入口上对 `Service`/`Ingress`/`IngressRoute``curl`(本仓库 nginx 矩阵等用响应头 `X-Backend` 或状态码区分路径)。
- **Helm / 存储 / 网络**:按该篇文档的「预期」增查命令(如 `helm list``PVC Bound`、跨节点 curl
- 依赖外部云账号、NFS、ACME 邮箱等时:未满足条件可用 **gate 跳过** apply并在矩阵备注中写明「未配变量未验」。
5. **收尾与记录**
- 默认 **`VERIFY_TEARDOWN=1`**:验证通过后删除临时资源,减少对共享实验集群的干扰;调试时可设 `0` 保留现场。
- 将结论写回 [`docs/00-02-验证矩阵.md`](00-02-验证矩阵.md)(状态与备注),必要时更新对应 `docs/XX-YY-*.md` 中的命令或版本说明。
6. **本仓库一键串联**
- **部署**(步骤 3`./scripts/deploy-lab.sh k3s` 等,见 [`scripts/README.md`](../scripts/README.md)。
- **验证**(步骤 46在仓库根执行 `./scripts/verify.sh run-all`(或 `run <XX-YY>`),按矩阵顺序重复「断言 → teardown」缺 playbook **fail-fast**。跑全量前可 `./scripts/verify.sh preflight``./scripts/verify.sh flow` 可打印与本节对应的步骤摘要。
### 2.1 局限与约定补全(建议在文档与 `verify/XX-YY.yml` 中写死)
下列能力 **不会**`verify.sh` 自动推断;必须在对应 `docs/XX-YY-*.md` 里写清「谁执行、对哪里发请求、怎样算过」,并在 playbook 里逐项实现。**未写进 playbook 的步骤即视为未自动化覆盖**。
| 主题 | 建议约定 |
|------|----------|
| **多节点:在哪台机器 `curl`** | **默认**:在 inventory 的 **`k3s_server`(控制节点)** 上,对 **集群入口** 发 HTTP`nginx_entry_base` / `http://<控制节点或 LB IP>`),与「从集群外经 NodePort/主机网络进 Traefik」一致。**例外**(必须显式写):要验 worker 仅内网、跨节点路径、或「必须从某台 agent 访问」时,在 playbook 里对指定 host 执行 `curl`(或 `delegate_to` / 专用 play并在文档「验证命令」中写明 **执行主机与目标 URL**,避免隐含「任意节点等价」。 |
| **TLS / SNI** | 自签或跳过校验仅用于排障:`curl -k`。**验收**应优先:真实证书路径下用 `curl -v` 看证书链;或用 `curl --resolve <域名>:443:<入口IP> https://<域名>/...`**无 DNS** 时模拟 SNI。需要时用 `openssl s_client -connect host:443 -servername <域名> </dev/null` 看握手。ACME 类用例依赖 **公网 80/443、有效邮箱、DNS/Secret**gate 跳过 apply 时,矩阵应标 **⚠️**,不得记成 ✅。 |
| **仅浏览器可用的 UI** | Traefik Dashboard OAuth、依赖 JS/CSP/WebSocket 的交互、文件上传等,`curl` 往往不够。约定三选一:**(1)** 自动化降级为只断言 `IngressRoute`/Deployment/Service 存在 + HTTP 非 5xx**(2)** 在 `00-02` 备注 **「UI 需手工浏览器验收」****(3)** 另起 CI/脚本用 headless如 Playwright`verify.sh` **并列**,不强行塞进 Ansible。 |
| **Helm 长耗时:超时与重试** | 安装/升级统一带 **`--wait` 与合理 `--timeout`**(大 chart 可 10m20m 量级按实际调。Ansible 侧对「Pod 未就绪」可用 **`until` + `retries` + `delay`** 轮询,避免单次 `kubectl` 瞬断误判。文档写清 **最短等待** 与失败时要看 **`helm status` / `kubectl describe` / 事件**。调试设 `VERIFY_TEARDOWN=0` 保留现场。 |
| **CI 无真集群** | 与实验室 **`verify.sh run-all` 不等价**。可选:**kubeconform** 等对清单做离线 schema有短时 apiserver 时用 **`kubectl apply --dry-run=server`**;或用 **kind/k3d** 起临时集群跑子集用例。应在 CI 配置或 `README` 中写明 **「本流水线只保证 YAML/静态;矩阵级验收仍以控制节点 run-all 为准」**,避免混为一谈。 |
**原则**:每篇文档至少有一句话说明 **验证命令的执行位置**(控制节点 / 指定 worker / 办公机经 VPN**成功判据**状态码、响应头、kubectl 资源相位playbook 与文档冲突时以 **先修 playbook、再改文档** 对齐。
## 3. 执行框架(与仓库一致)
此前设想的「静态层yamllint / kubeconform / ansible-lint→ 运行时 → 追溯」**未纳入**当前落地实现;若日后在 CI 里加格式或 schema 检查,应与 `verify.sh` **并列**,不必塞进同一脚本。
本仓库**实际**验收路径只有下面几条,且都以 **Ansible 为执行引擎**(在控制节点上对集群下发 `kubectl` / `helm` / `curl` 等):
1. **`docs/00-02-验证矩阵.md`**:列出 `XX-YY` 与顺序;`verify.sh run-all` 按文中首次出现的 `XX-YY` 依次执行。
2. **`scripts/verify.sh`**:调用 `ansible-playbook -i <inventory> ansible/playbooks/verify/<doc_id>.yml`;缺对应 playbook 则 **fail-fast**
3. **`ansible/playbooks/verify/<doc_id>.yml`**:单篇用例,通常拆成「部署 → 验证 → 清理」多个 **play**(默认 **`VERIFY_TEARDOWN=1`** 做 teardown
4. **特例**:无集群动作的文档可走 **`verify/_noop-tasks.yml`**(仓库路径/文件存在性);依赖 NFS、ACME、Cloudflare 等外部条件的可用 **gate 跳过** applyteardown 需避免「无清单仍删」类失败(各 playbook 已按此收敛)。
**真源**:可部署清单以 **`ansible/files/`** 为准;`docs/XX-YY-*.md` 与矩阵通过同一 **`doc_id`** 与 playbook 对齐。矩阵里的状态/备注仍建议 **手工** 维护(见 §7
## 4. 文档 id 与用例索引
约定:
- `docs/XX-YY-*.md` 的文档 id 为 `XX-YY`(例如 `02-05`)。
- 自动化用例文件名为 `verify/XX-YY.yml`,与 `doc_id` 一致即可playbook 内不必再写 YAML 字段 `doc_id`,除非你想自检)。
- 框架通过 `doc_id` 把“文档”映射到 `verify/<doc_id>.yml`,从而实现按篇自动执行(`verify.sh`)。
这样你在 `00-02` 里更新状态时,不需要关心脚本内部结构;只要 id 一致就能追溯。
## 5. 用例数据模型(建议)
建议把用例写成“按文档 id 编排的任务集合”。在本仓库里,**用例落在** `ansible/playbooks/verify/<XX-YY>.yml`,不再使用单体 `verify-matrix.yml`(已移除,避免与拆分后的 playbook 双份维护)。
- 文档 id `XX-YY` → 文件 `verify/XX-YY.yml`
- 每个文件内一般拆为三段(多个 play 或顺序 tasks
示例02-05`./scripts/verify.sh run 02-05` 执行 `ansible/playbooks/verify/02-05.yml`(内部 `import_playbook` `nginx-matrix-deploy.yml`,再 HTTP 校验四路径,最后 teardown`02-01``02-04` 另有单路径 playbook便于单独调试。
每个 `verify/XX-YY.yml` 的典型结构为三段:
- **deploy**`kubectl apply` / `helm install`
- **verify**`kubectl rollout status` / `curl` / `assert`
- **teardown**`kubectl delete` / `helm uninstall`(默认执行,可用 `VERIFY_TEARDOWN=0` 关闭)
```yaml
doc_id: "02-05"
case_id: "nginx-matrix-all"
description: "02-05 四条路径均返回 200并区分后端内容"
apply:
paths:
- "ansible/files/02-05-nginx-matrix/"
strategy: "apply-r"
wait:
namespace: "default"
deployments:
- "nginx-m1"
- "nginx-m2"
- "nginx-m3"
- "nginx-m4"
timeout: "180s"
http_check:
entry_base: "http://<入口IP>"
paths:
- path: "/demo-m1/"
expect_status: 200
expect_body_contains: "Backend: M1"
- path: "/demo-m2/"
expect_status: 200
expect_body_contains: "Backend: M2"
```
## 6. 执行器Executor——两类在 Ansible 中落地)
测试框架的执行器应当清晰分成两类,对应两种“被测对象”(机器 vs 集群):
### 6.1 Ansible 远程命令类(普通 Linux / 设备执行命令)
- 目标:在普通 Linux/路由/设备上通过 `ssh` 执行命令,并做断言(例如 `exit_code``stdout_contains/regex``file_exists`)。
- 不强制要求在这类执行器里做 HTTP/curl 校验HTTP/服务可用性校验归到 K3s 类用例。
落地方式Ansible 的 `command/shell` + `assert`inventory 决定 SSH 目标与用户/密钥)。
### 6.2 Ansible K3s 集群类(部署 + 结果校验 + 可选清理)
- 目标:对 K3s 集群做 `apply` / `wait` / `check` / `http_check`(可选),并支持可选 `teardown/delete`
- 执行位置分两种:
- 本机直接 `kubectl`
-`kubectl` 需要通过 SSH 在控制节点执行(复用你现有的 `.env.verify` 变量语义)
落地方式Ansible 在控制节点(如 ylc61执行 `kubectl` / `helm` / `curl`,多个 play 顺序执行。默认策略:验证完成后 **执行 teardown**(清理部署),可通过 `VERIFY_TEARDOWN=0` 关闭。
## 7. 状态记录与写回策略
你已经在 `docs/00-02-验证矩阵.md` 里定义了状态含义(未验证/部分验证/已验证)。
建议未来的写回策略分两步:
- 首先:仍然由你手工更新 `00-02`(减少自动化失败导致的误写)
- 之后:如果要自动写回,则需要明确“失败判定标准、覆盖范围、并发策略”,避免多个执行器同时写同一条状态。
## 8. 与旧自动化的关系
- `docs/00-02-验证矩阵.md` 不承担执行细节,只作待验证列表与状态记录
- 自动化执行以 `scripts/verify.sh``ansible/playbooks/verify/*.yml` 为准;本页描述其约定与扩展方式
## 9. 可选扩展(未落地)
当前「一篇文档 → 一个 `verify/XX-YY.yml`」在规模小时最简单:**入口仍是 `scripts/verify.sh`**,不必为了「架构感」提前建一堆目录。当出现下面任一情况时,再考虑本节里的拆法即可。
### 9.1 何时值得拆
- **重复**:多个 playbook 里出现相同的 `kubectl rollout status``curl` 重试、gate + teardown 模板,改一处要改十处。
- **体积**:单个 `XX-YY.yml` 过长,难以一眼看清「本篇到底验了什么」。
- **复用非 Ansible 逻辑**:例如要在本机做纯文本处理、复杂拼接,再交给 Ansible这类少量逻辑可以放在 shell大量仍建议用 Ansibleinventory、变量、幂等已有约定
### 9.2 Ansible 侧:角色与 `include_tasks`(优先)
与正式部署 playbook 一样,验证逻辑**优先**留在 Ansible 生态里拆:
- **`include_tasks`** 或 **`import_tasks`**:把「等 Deployment」「带重试的 HTTP 检查」「安全 delete」抽成 `ansible/playbooks/verify/_*.yml` 小文件,由各 `XX-YY.yml` 引用。
- **Role**(例如 `ansible/roles/k3s_verify_http/`):当同一套「变量约定 + 多 task」在多篇文档复用时用 role 比复制粘贴更清晰;`verify.sh` **不需要改**,仍只调用 `verify/XX-YY.yml`,由该文件 `roles:``import_role` 即可。
原则:**`verify.sh` 只认 `verify/<doc_id>.yml` 这一层文件名**;底下怎么组织 include/role 是内部重构。
### 9.3 `scripts/lib/`(次要)
适合只放 **bash 层**的薄工具:解析矩阵、拼 `ansible-playbook` 参数、统一日志格式等。若把「怎么 curl」「怎么 kubectl wait」写进大量 shell容易和 inventory、sudo、`KUBECONFIG` 两套路径打架,**一般不如 Ansible task**
### 9.4 单独的 `tests/` 目录(与现框架并列)
若将来引入 **非 Ansible** 的测试运行器(例如用编程语言写契约测试、或只跑静态检查),可以建 `tests/` 存放用例与配置,由 **CI 或另一条脚本** 调用;它与 `verify.sh`**并列流水线**,而不是替换关系:
- **矩阵验收 / 真机集群路径**:仍以 `verify.sh` + `verify/*.yml` 为准。
- **PR 上的快速反馈**:可对 `ansible/files/**/*.yaml` 跑 yamllint、kubeconform、`kubectl apply --dry-run=server`(需集群凭据时再决定挂不挂 CI
这样不会出现「同一篇文档到底以哪套测试为准」的模糊地带:文档级约定验收看矩阵 + verify playbook代码库卫生看 CI。
### 9.5 静态检查(再次强调)
yamllint、ansible-lint、schema 校验等 **不放进 `verify.sh`** 亦可:在 GitHub Actions / 本地 pre-commit 里单独跑即可。与 §3 一致——与运行时验证 **并列**,互不嵌套。