fix(k3s): make credential freshness nonblocking

This commit is contained in:
pikastech
2026-07-20 07:28:30 +02:00
parent 6cf3fed084
commit 4514f4f3e4
4 changed files with 46 additions and 8 deletions
+4
View File
@@ -98,6 +98,10 @@ description: UniDesk YAML-first 运维正规化技能。用户提到 ymal-first/
- control-plane drop-in 只走 `hwlab nodes control-plane infra k3s-config` 窄域:
- 渲染结果一致且节点容量已收敛时返回 `mutation=false`
- 只在必要时写入 drop-in、reload 和重启 k3s
- 确需重启 server 时,先停止服务并备份 k3s 派生
`server/cred/passwd`;禁止用该文件与 datastore 的
mtime/freshness 预判阻断变更,备份只输出
`blocking=false` warning
- WireGuard 内容一致时不重启,API/容量读取暂时失败时保持 unknown 并停止 mutation
- worker agent 使用 YAML 派生摘要决定是否重装,禁止每次 apply 先卸载再覆盖;
- 禁止借用全量 infra apply 顺带覆盖 registry、CI/CD 或业务运行面。
+6
View File
@@ -33,6 +33,12 @@
- control-plane 节点配置只组合 `hwlab nodes control-plane infra k3s-config plan|status|apply`
- 该窄域只比较并安装 owning YAML 渲染的 k3s systemd drop-in
- 只在 drop-in 或节点 pod 容量需要收敛时重启 k3s;
- 确需重启 k3s server 时,受控入口先停止服务并备份
`/var/lib/rancher/k3s/server/cred/passwd` 派生文件,再启动服务;
- 禁止用 `passwd``state.db` 的文件 mtime、datastore freshness
预判或其他凭据新旧检查阻断 YAML-first 变更;备份动作必须以
`blocking=false` warning 披露,只有真实 stop/start、Node Ready
或期望状态收敛失败才可使 apply 失败;
- 同一入口等待节点 Ready;
- 禁止调用 HWLAB 全量 `infra apply`,也不得触碰 Kubernetes manifests、registry、Tekton、Argo、git-mirror 或业务 rollout。
- 运行边界:
@@ -251,6 +251,18 @@ PipelineRun source step 不得以 mutable `refs/heads/<branch>` 作为本轮源
status/closeout 必须同时展示 selected snapshot、PipelineRun snapshot、latest mirror head、GitOps revision 和 runtime provenance。branch 在发布过程中前进只能标记为 `latest-drift``superseded`,不得把 selected commit 的成功发布误判为本轮失败。
### 6.8 OPS-TARGET-REQ-008 k3s server 重启门禁非阻塞
| 编号 | 短名 | 主责模块 | 关联模块 |
| --- | --- | --- | --- |
| OPS-TARGET-REQ-008 | k3s重启 | PJ2026-01060308 YAML目标治理 | [平台运维](PJ2026-0106-platform-ops.md)、[控制面模块化](PJ2026-01060307-control-plane-modularity.md) |
k3s server 受控重启不得以派生凭据文件与 datastore 的 mtime 或
freshness 预判阻断 YAML-first 变更。入口应在停止服务后备份派生
`server/cred/passwd`,并以 `blocking=false` warning 披露;只有真实启停、
节点就绪或期望状态收敛失败才可使 apply 失败。不得重新引入凭据新旧
preflight、CI gate 或人工确认门禁。
## 7. 过程控制
本规格的执行 issue 为 [#911](https://github.com/pikasTech/unidesk/issues/911)。源码文件头部应标注 `SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets`;自动生成文件、纯配置、锁文件和无法承载注释头的二进制产物可例外。
@@ -246,6 +246,8 @@ fi
mutation=false
daemon_reload_rc=0
restart_rc=0
credential_backup_path=
credential_backup_rc=0
if [ "$apply" = true ] && [ "$restart_required" = true ]; then
mkdir -p "$(dirname "$dropin")"
if [ "$changed" = true ]; then
@@ -255,12 +257,15 @@ if [ "$apply" = true ] && [ "$restart_required" = true ]; then
fi
systemctl daemon-reload || daemon_reload_rc=$?
if [ "$daemon_reload_rc" = 0 ]; then
state_db=/var/lib/rancher/k3s/server/db/state.db
derived_passwd=/var/lib/rancher/k3s/server/cred/passwd
if [ -f "$state_db" ] && [ -f "$derived_passwd" ] && [ "$derived_passwd" -nt "$state_db" ]; then
mv "$derived_passwd" "$derived_passwd.unidesk-pre-restart-$(date -u +%Y%m%dT%H%M%SZ)"
systemctl stop "$service" || restart_rc=$?
if [ "$restart_rc" = 0 ] && [ -f "$derived_passwd" ]; then
credential_backup_path="$derived_passwd.unidesk-pre-restart-$(date -u +%Y%m%dT%H%M%SZ)-$$"
mv "$derived_passwd" "$credential_backup_path" || credential_backup_rc=$?
fi
if [ "$restart_rc" = 0 ]; then
systemctl start "$service" || restart_rc=$?
fi
systemctl restart "$service" || restart_rc=$?
fi
mutation=true
fi
@@ -290,15 +295,25 @@ if [ -f "$dropin" ]; then after_sha=$(sha256sum "$dropin" | awk '{print "sha256:
after_capacity=$(kubectl get node "$node" -o 'jsonpath={.status.capacity.pods}' 2>/dev/null || true)
after_allocatable=$(kubectl get node "$node" -o 'jsonpath={.status.allocatable.pods}' 2>/dev/null || true)
service_active=$(systemctl is-active "$service" 2>/dev/null || true)
python3 - "$apply" "$mutation" "$changed" "$restart_required" "$daemon_reload_rc" "$restart_rc" "$before_sha" "$after_sha" "$expected_sha" "$service_active" "$ready" "$before_capacity" "$before_allocatable" "$after_capacity" "$after_allocatable" "$desired_max_pods" <<'PY'
python3 - "$apply" "$mutation" "$changed" "$restart_required" "$daemon_reload_rc" "$restart_rc" "$credential_backup_path" "$credential_backup_rc" "$before_sha" "$after_sha" "$expected_sha" "$service_active" "$ready" "$before_capacity" "$before_allocatable" "$after_capacity" "$after_allocatable" "$desired_max_pods" <<'PY'
import json, sys
apply, mutation, changed, restart_required = [value == "true" for value in sys.argv[1:5]]
daemon_reload_rc, restart_rc = int(sys.argv[5]), int(sys.argv[6])
before_sha, after_sha, expected_sha = sys.argv[7:10]
service_active, ready = sys.argv[10], sys.argv[11] == "true"
before_capacity, before_allocatable, after_capacity, after_allocatable, desired = sys.argv[12:17]
credential_backup_path, credential_backup_rc = sys.argv[7], int(sys.argv[8])
before_sha, after_sha, expected_sha = sys.argv[9:12]
service_active, ready = sys.argv[12], sys.argv[13] == "true"
before_capacity, before_allocatable, after_capacity, after_allocatable, desired = sys.argv[14:19]
def number(value):
return int(value) if value.isdigit() else None
warnings = []
if credential_backup_path:
warnings.append({
"code": "k3s-derived-credential-backed-up",
"blocking": False,
"message": "已在受控重启前备份 k3s 派生 passwd,避免 datastore freshness 门禁阻断变更",
"backupPath": credential_backup_path,
"backupExitCode": credential_backup_rc,
})
ok = (
after_sha == expected_sha
and service_active == "active"
@@ -316,6 +331,7 @@ print(json.dumps({
"restartRequired": restart_required,
"daemonReloadExitCode": daemon_reload_rc,
"restartExitCode": restart_rc,
"warnings": warnings,
"beforeDropInSha256": before_sha or None,
"dropInSha256": after_sha or None,
"expectedDropInSha256": expected_sha,