Files
pikasTech-HWLAB/docs/reference/dev-runtime-hotfix-runbook.md
T

142 lines
9.4 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.
# HWLAB DEV Runtime Hotfix Runbook
本文定义 `hwlab-dev` 运行态热修的最低边界、审计字段、只读确认和回滚口径。它只适用于 DEV 能力边界或阻塞排障,不是发布验收手册,也不把运行态覆盖当作源码真相。
本规则承接 [pikasTech/HWLAB#462](https://github.com/pikasTech/HWLAB/issues/462) 和 [pikasTech/HWLAB#465](https://github.com/pikasTech/HWLAB/issues/465),服务 [pikasTech/HWLAB#7](https://github.com/pikasTech/HWLAB/issues/7) / [pikasTech/HWLAB#239](https://github.com/pikasTech/HWLAB/issues/239) 的“用户工作台 + Code Agent 真实可用”主线。它不改变 `DC-DCSN-P0-2026-003` / [pikasTech/HWLAB#78](https://github.com/pikasTech/HWLAB/issues/78) 的 M3 上位约束:hotfix runbook、审计输出、SOURCE、LOCAL、DRY-RUN 或只读观察都不能被包装成 M3 DEV-LIVE 通过。
## 允许条件
DEV runtime hotfix 只能在以下条件同时满足时使用:
- 目标是 `hwlab-dev`,不是 PROD、真实用户生产面或真实硬件生产控制面。
- 目的是打通能力边界、定位阻塞层或恢复用户工作台关键路径;不能为了绕过源码、测试、artifact 或 CD 流程而热修。
- 操作前已经明确该任务不会抢占 M3 虚拟硬件可信闭环主线,也不会把热修证据升级成 M3 验收。
- 操作后必须创建或关联源码化 follow-up。#465 的持久化拆分是固定分工:#460 负责 Code Agent -> PC gateway `shell.exec` 能力路由,#461 负责 hotfix runner 源码化,#462 负责本 runbook 与只读审计,#463 负责 JSON-RPC `serviceId` 结构化诊断,#464 负责 DEV-LIVE smoke/harness。
## D601 k3s 前置
D601 裸 `kubectl` 不可信。所有只读观测、热修、回滚和复核都必须显式指定原生 k3s kubeconfig,并先确认节点:
```sh
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get nodes -o jsonpath='{.items[*].metadata.name}'
```
结果必须包含 `d601`。出现 `docker-desktop``desktop-control-plane``127.0.0.1:11700` 或第二套 `hwlab-dev` 控制面时,停止 hotfix、回滚和验收判断。此边界与 [dev-runtime-boundary.md](dev-runtime-boundary.md) 和 [deployment-publish.md](deployment-publish.md) 保持一致。
## kubectl 热修命令形状
运行面热修应优先使用小补丁、短连接和远端临时文件,避免把大对象穿过 shell argv、CLI 输出截断或 `kubectl apply` 的 last-applied annotation。
推荐的 ConfigMap data 局部覆盖方式是:在本地生成只包含本次 key 的 merge patch,通过 D601 短连接写入远端临时文件,再让 `kubectl` 从真实文件读取:
```sh
node - <<'NODE' | bun scripts/cli.ts ssh D601 argv bash -lc '
set -e
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get nodes -o jsonpath="{.items[*].metadata.name}" | grep -w d601 >/dev/null
patch_file=/tmp/hwlab-hotfix.patch.json
cat > "$patch_file"
kubectl -n hwlab-dev patch configmap <hotfix-configmap> --type merge --patch-file "$patch_file"
rm -f "$patch_file"
kubectl -n hwlab-dev rollout restart deployment/<deployment>
kubectl -n hwlab-dev rollout status deployment/<deployment> --timeout=180s
'
const fs = require("node:fs");
process.stdout.write(JSON.stringify({
metadata: { annotations: { "hwlab.pikastech.com/hotfix-reason": "<reason>" } },
data: { "<key>": fs.readFileSync("<local-file>", "utf8") }
}));
NODE
```
固定避坑规则:
- 不要用 `kubectl patch --patch-file -` 假设 stdin 可用;目标 `kubectl` 版本可能把 `-` 当普通文件名。用 `/tmp/*.patch.json``--patch-file`
- 不要把大 JSON patch 放进 `kubectl patch -p "$patch"` 或 shell argvConfigMap 覆盖源码文件时很容易触发 `Argument list too long`。用 stdin 写远端临时文件。
- 不要对已经很大的 hotfix ConfigMap 使用 `kubectl apply -f -``apply` 会尝试写入 `kubectl.kubernetes.io/last-applied-configuration`,可能超过 Kubernetes annotation 256 KiB 限制。局部更新用 `patch --type merge --patch-file`
- 不要通过会截断 stdout 的控制 CLI 把 `kubectl get configmap -o json` 回读到本地再 `replace`;大 data 可能被日志/截断污染成非法 JSON。只有在确认完整无截断的原生通道中,才允许对完整对象做 `kubectl replace -f -`
- 每次 `rollout restart` 后立即执行 `rollout status`,再用 running pod 做最小只读验证,例如 `node --check``grep` marker、`curl` health 或公开入口 trace/result 轮询。
- 临时补丁文件必须放在远端 `/tmp`,命名包含 hotfix 目标,命令结束后删除;issue 里只记录 ConfigMap 名、key、mountPath、operationId/traceId 和验证方法,不粘贴完整 data。
## 必须记录
每次 DEV hotfix 至少记录以下字段,写入 PR/issue/comment,不写入仓库 `reports/**`
| 字段 | 说明 |
| --- | --- |
| Deployment | namespace、name、generation、template annotation、容器 image。 |
| Pod | 新旧 pod 名、phase、node、用于验证的 running pod。 |
| ConfigMap | 名称、key 名、用途;不得把 data 全量贴入 issue。 |
| annotation | 记录热修来源和目的的 Deployment template annotation。 |
| mount/subPath | volume 名、ConfigMap 名、mountPath、subPath、readOnly。 |
| traceId / operationId | 能力验证请求的 trace 与 operation 标识。 |
| 验证命令 | `grep` marker、`node --check`、API 返回字段等只读或最小验证命令。 |
| 回滚方式 | 移除 volume/mount/annotation 的方法,或用源码 artifact/CD 覆盖的方法。 |
| 源码化 follow-up | 关联 issue/PR,说明热修不会作为长期 runtime truth。 |
#465 的典型对象是:
| 项 | 值 |
| --- | --- |
| Deployment | `hwlab-dev/hwlab-cloud-api` |
| ConfigMap | `hwlab-cloud-api-code-agent-hotfix` |
| 覆盖文件 | `/app/internal/cloud/code-agent-chat.mjs` |
| subPath | `code-agent-chat.mjs` |
| marker | `runtime-hotfix-pc-gateway-shell` |
| annotation | `hwlab.pikastech.local/pc-gateway-shell-hotfix` |
| 能力路径 | `/v1/agent/chat -> /v1/rpc/hardware.invoke.shell -> PC gateway -> Windows cmd` |
## 只读审计入口
仓库内只读入口是:
```sh
node scripts/dev-runtime-hotfix-audit.mjs --pretty
node scripts/dev-runtime-hotfix-audit.mjs --collect-readonly --pretty
```
默认 `--plan` 模式只输出 compact JSON 计划,不执行 `kubectl``--collect-readonly` 只允许 `kubectl get``kubectl exec` 形态的读检查,用于判断当前 DEV 是否仍被 hotfix 覆盖;它不会执行 `apply``patch``rollout``restart``delete``create``set image`,也不会读取 Secret resources 或 secret values。
输出分类固定包含以下语义:
| 分类 | 含义 |
| --- | --- |
| `hotfix-configmap-present` | 目标 ConfigMap 仍存在。 |
| `deployment-mounts-hotfix` | Deployment template 仍通过 volumeMount/subPath 覆盖目标文件。 |
| `pod-loads-hotfix-marker` | running pod 内目标文件仍包含 hotfix marker。 |
| `source-artifact-expected` | 正式收口应回到 source/PR/artifact/CD。 |
| `rollback-required` | 当前仍检测到热修残留或覆盖,不能把运行态当源码真相。 |
| `no-hotfix-detected` | 只读审计未发现该 hotfix ConfigMap 或 mount 覆盖。 |
| `unknown-needs-manual-readonly-check` | 无法确认节点、对象或 pod 状态,需要人工继续只读核对。 |
## 回滚口径
优先回滚方式是用源码化 artifact/CD 覆盖 runtime hotfix#460/#461 合并并发布后,Deployment 应消费正式镜像,不再通过 ConfigMap 覆盖 `/app/internal/cloud/code-agent-chat.mjs`。只读确认口径是:
```sh
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get nodes -o jsonpath='{.items[*].metadata.name}'
kubectl -n hwlab-dev get deployment hwlab-cloud-api -o json
kubectl -n hwlab-dev get configmap hwlab-cloud-api-code-agent-hotfix -o json
node scripts/dev-runtime-hotfix-audit.mjs --collect-readonly --pretty
```
如果必须直接移除运行态覆盖,授权操作者应先从 `kubectl -n hwlab-dev get deployment hwlab-cloud-api -o json` 中定位精确 indexes,再移除:
- 指向 hotfix ConfigMap 的 `spec.template.spec.volumes[]`
- 指向 `/app/internal/cloud/code-agent-chat.mjs``containers[].volumeMounts[]`
- `hwlab.pikastech.local/pc-gateway-shell-hotfix` 等 hotfix annotation
- 不再需要的 `hwlab-cloud-api-code-agent-hotfix` ConfigMap。
直接 `kubectl patch``kubectl delete configmap``kubectl rollout status` 或等价写操作必须由明确授权的 DEV 操作者执行,并且仍要使用 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` 与节点 `d601` 确认。本 runbook 的审计脚本不执行这些写操作。回滚后再次运行 `scripts/dev-runtime-hotfix-audit.mjs --collect-readonly`,期望分类包含 `no-hotfix-detected`,且不包含 `deployment-mounts-hotfix``pod-loads-hotfix-marker``rollback-required`
## 禁止误用
- 不得把 ConfigMap/pod 覆盖当作 source truth;正式修复必须回到 source、PR、artifact 和 repo-owned CD。
- 不得把 #462 runbook 或只读审计包装成 #460/#461 源码化完成。
- 不得把 #462 runbook 或只读审计包装成 #464 DEV-LIVE smoke/harness 完成。
- 不得把热修期间的 stdout、trace 或 operation 扩大为 M3 trusted evidenceM3 判定仍按 [m3-loop-rollout-runbook.md](m3-loop-rollout-runbook.md)。
- 不得读取或打印 Secret value、kubeconfig token、DB URL 密码、provider token。
- 不得新增或修改仓库 `reports/**`;过程证据写入 PR/issue/comment,临时 JSON 只能放 `/tmp``.state` 或 CI artifact。