Files
pikasTech-unidesk/docs/reference/codex-deploy.md
T
2026-06-11 15:41:11 +08:00

99 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.
# Code Queue Deploy
`bun scripts/cli.ts codex deploy <commitId>` 是旧兼容入口,现已禁用。原因是它会通过 backend-core `host.ssh` 维护通道直连 D601 部署 Code Queue,把维护入口扩张成第二套部署系统。
P0 控制面说明:D601 生产/DEV Kubernetes 入口只允许原生 k3sDocker Desktop Kubernetes 已停用且不得重新启用。裸 `kubectl` 仍可能命中残留 `docker-desktop` kubeconfig,不能作为 Code Queue 恢复、部署或回滚证据。详细证据和治理计划见 [pikasTech/unidesk#138](https://github.com/pikasTech/unidesk/issues/138)2026-05-23 恢复过程见 [pikasTech/unidesk#118](https://github.com/pikasTech/unidesk/issues/118)。
Code Queue 后续正式生产部署必须走一条受控 CD 路径并单独审查;当前阶段只提供 dev artifact consumer 的 dry-run/source/contract readiness。`deploy apply --env dev --service code-queue --dry-run``artifact-registry deploy-service --env dev --service code-queue --dry-run` 可以计划消费 D601 registry 中的 `unidesk/code-queue:<commit>`,但输出必须显示 `selfBootstrapGuard``requiresSupervisorApproval`、pull-only/no-build、image tag/digest provenance,并说明只会在获授权后更新 `unidesk-dev` Code Queue execution slice。非 dry-run DEV apply 必须由 human operator/supervisor 在 Code Queue 任务之外授权;当前 Code Queue runner 不能自己上线 Code Queue。`--env prod --service code-queue` 必须明确 unsupported,不能执行生产 artifact deploy、rollout 或 manifest 变更。persistent dev apply 的完整服务范围见 `docs/reference/dev-environment.md`Code Queue temporary smoke 仍通过 `ci run-dev-e2e`,规则见 `docs/reference/dev-ci-runner.md`
The reproducible dry-run delivery path is:
1. CI publishes `127.0.0.1:5000/unidesk/code-queue:<full-sha>` from pushed Git and reports the immutable digest/label summary.
2. A runner or operator runs `bun scripts/cli.ts deploy plan --env dev --service code-queue` or `bun scripts/cli.ts deploy apply --env dev --service code-queue --commit <full-sha> --dry-run`; this is non-mutating evidence only.
3. A human operator reviews the dry-run and, if accepted, separately authorizes DEV apply. That apply may touch only `unidesk-dev` Code Queue execution objects.
4. PROD remains unsupported. A dry-run or plan may document the gap, but no Code Queue runner may perform prod apply, rollout restart, scheduler/runner rebuild, interrupt or cancel as part of delivering Code Queue itself.
This contract is checked by `bun scripts/code-queue-cicd-dry-run-contract-test.ts`. The test is intentionally lightweight and does not run full e2e, Playwright, Code Queue deployment, or task interruption flows.
## Command
```bash
bun scripts/cli.ts codex deploy <commitId>
```
该命令必须返回结构化错误,说明维护通道直连 D601 部署已禁用;不得再创建后台部署 job。`--skip-build` 不再支持。
## Pipeline
历史部署 job 曾固定为以下步骤;它们现在只能作为未来受控 Code Queue CD 的目标行为,不能由 `codex deploy` 或维护通道直连触发:
1. 对 Code Queue 部署先确保 PostgreSQL 中存在 `unidesk_deploy_ssh_identities(id='github.com')`,该记录保存 GitHub deploy SSH identity 的 private key、public key fingerprint 和 github.com `known_hosts` 行。未来受控 CD 不得把 secret 写入 task payload、deploy 日志、Docker image 或 Kubernetes Secret。
2. 在 D601 的 deploy cache 中通过本机 provider-gateway WS egress proxy 执行 `git fetch` remote,并用 `git archive <commitId>` 导出 tracked files 到一次性 export 目录;不得让 D601 直连 GitHub,也不得临时创建 SSH SOCKS、公网 master proxy 或 backend-core/provider-ingress fallback。
3.`rsync --delete` 同步导出的 repo 到 `/home/ubuntu/cq-deploy`,保留 `.state/``logs/``.git/``node_modules/``dist/`。同步完成后、任何 scheduler/read/write rollout 前,必须运行 Code Queue hostPath source guard`bun scripts/code-queue-source-guard.ts --root /home/ubuntu/cq-deploy` 或等价 `bun scripts/cli.ts deploy guard code-queue-source --root /home/ubuntu/cq-deploy`。该 guard 至少扫描 `src/components/microservices/code-queue/src/**/*.ts` 的相对 `import` / `export ... from` / `import(...)`,确认目标文件存在;失败必须返回结构化 `degradedReason=missing-relative-import-target``source-root-missing`,并阻止 rollout。
4. 在 D601 用目标 Docker daemon 的本地 BuildKit builder 构建 `unidesk-code-queue:d601`,复用 D601 上已有基础镜像、inline cache 和 Code Queue build-baseprovider-gateway WS egress 是唯一允许的构建代理通道,只作为本次 build 的环境变量与 build-arg 注入,并配合本次 build 的 `--network host` 让 RUN 阶段访问 D601 宿主 loopback proxy,不能污染 D601 宿主 Docker/HTTP proxy 配置,不能新建 SSH SOCKS、公网 master proxy 或直连 fallback。
5. `docker save` 镜像并导入原生 k3s containerd`docker save unidesk-code-queue:d601 | sudo ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images import -`。导入后必须用同一个 containerd socket 验证 `unidesk-code-queue:d601` tag 存在;D601 Docker daemon 的本地 tag 不是 k3s containerd 的 source of truth。
6. `KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -f src/components/microservices/k3sctl-adapter/k3s/code-queue.k8s.yaml`,其中包含 Code Queue、`d601-provider-egress-proxy``d601-tcp-egress-gateway`。apply 后必须验证 `code-queue``code-queue-read``code-queue-write``d601-provider-egress-proxy``d601-tcp-egress-gateway` 这些 Deployment 的 container image 都是 `unidesk-code-queue:d601`,不能让 kubelet 回退到 Docker Hub 或其他外部 registry。
7. 将解析后的 40 位 remote commit 写入 `deployment/code-queue``CODE_QUEUE_DEPLOY_COMMIT` / `CODE_QUEUE_DEPLOY_REQUESTED_COMMIT`,并记录到 Deployment annotation。
8. `KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n unidesk rollout restart deployment/d601-tcp-egress-gateway deployment/code-queue` 并等待 rollout 完成。
9. 通过 backend-core 的真实微服务代理读取 Code Queue `/health`,强制校验 `deploy.commit` 等于本次解析出的 remote commit;如果健康的是旧服务或旧 Pod,job 必须失败。
## HostPath Source Guard
生产 `unidesk` namespace 的 Code Queue scheduler/read/write 仍处在 hostPath source 过渡模式:Pod 内 `/app``/root/unidesk` 都挂载 D601 host 的 `/home/ubuntu/cq-deploy`。这意味着镜像内已经包含的源码会被 hostPath 覆盖,镜像构建成功不能证明运行时源码完整。已知失效模式是 hostPath repo 部分同步:`src/components/microservices/code-queue/src/index.ts` 已包含 `./runtime-preflight` 导入,但 `/home/ubuntu/cq-deploy/src/components/microservices/code-queue/src/runtime-preflight.ts` 缺失,scheduler 启动即因 Bun 模块解析失败进入 CrashLoopBackOff。
`/home/ubuntu/cq-deploy` 是生产 Code Queue/k3s 共享 hostPath 部署仓库,也是当前 `code-queue.k8s.yaml` 中 repo、state 和 logs hostPath 的根。`/home/ubuntu/unidesk-code-queue-deploy` 是历史/开发工作区口径,不是生产 Pod 的 `/app` source mount;生产 rollout 判断必须以 `/home/ubuntu/cq-deploy` 为准。若两者需要保留软链接或迁移关系,必须先在 manifest、config 和文档中显式统一,不能让部署脚本从一个路径同步而 Pod 从另一个路径启动。
人工排查 D601 生产 k3s 状态时必须显式使用原生 k3s kubeconfig
```bash
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n unidesk get deploy,svc,pod,endpoints
```
D601 默认 `kubectl` context 可能指向 Docker Desktop、kind 或其他本地集群,不能作为 UniDesk 原生 k3s scheduler 是否 ready、Service 是否有 endpoint、Pod 是否 CrashLoop 的证据。
hostPath source 模式只允许作为过渡态。长期生产 Code Queue 应收敛到 commit-pinned artifact/image CD:以 pushed commit 为版本真相,CI 产出带 source commit label 的镜像,CD 只消费 commit-pinned image、更新 manifest/env/annotation 并验证 live health commit;生产 Pod 不应再用可部分同步的 hostPath source 覆盖镜像内应用源码。
## Observability
未来受控 Code Queue CD 实现后,部署触发本身不应阻塞等待完成。返回 JSON 中必须包含 run id、status command 或等价查询入口;后台日志必须有界可查,失败时能显示最后日志尾部。
部署 run 到 `succeeded` 时,必须已经完成 live commit 验证。需要人工复核时可用以下命令确认 `deploy.commit`
```bash
bun scripts/cli.ts microservice health code-queue
bun scripts/cli.ts microservice proxy code-queue '/api/tasks/overview?limit=5&transcriptLimit=1&compact=1&afterSeq=0&preferId='
```
D601 原生 k3s 的人工诊断必须显式使用 host kubeconfig`KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n unidesk ...`。D601 上的默认 `kubectl` context 可能指向 Docker Desktop 或其他本地集群,不能作为 UniDesk Code Queue 部署是否 ready 的证据。部署后直接查 k3s 时,至少确认 `deployment/code-queue``code-queue-read``code-queue-write``d601-provider-egress-proxy``d601-tcp-egress-gateway` ready,两个 egress Service 的 Endpoints 非空,Pod 环境中的 `UNIDESK_DEPLOY_REQUESTED_COMMIT`/`CODE_QUEUE_DEPLOY_REQUESTED_COMMIT` 等于期望 commit,并且 scheduler `/health` 暴露 PostgreSQL ready、`storage.lastError=null`、egress proxy connected、stale active/retry_wait reconcile 状态和 MiniMax `NO_PROXY` 例外。
`bun scripts/cli.ts microservice diagnostics code-queue` 必须作为 Code Queue 的长期诊断入口。它必须显式报告 `d601-provider-egress-proxy``d601-tcp-egress-gateway` 的 Deployment available、Endpoint non-empty、scheduler 到 PostgreSQL route、以及 stale active/retry_wait reconcile;任何一项失败都应让诊断结果 degraded/failing,而不是只显示 scheduler HTTP healthy。
## Pull Request Delivery
Code Queue worker 可以在任务明确要求审查型交付时创建 Pull Request。PR 交付不是唯一出口;默认集成目标仍是 `master`,轻量改动可直接合入,风险较高或需要审查的改动使用短生命周期 PR。PR 型任务必须从最新目标线创建短生命周期分支,报告源分支、目标分支、PR URL、关联 issue、验证证据和未完成风险;分支命名应使用 `probe/``code-queue/` 或其他明确任务前缀,禁止把隐藏分支当成长期交付状态。
Code Queue runtime 提供 `/api/runtime-preflight` 作为 PR 能力探测入口;CLI 稳定入口是 `bun scripts/cli.ts codex pr-preflight [--remote] [--push-dry-run --push-dry-run-ref refs/heads/probe/<name>] [--pr-create-dry-run --pr-create-dry-run-head <head>] [--issue N]`。默认请求只检查本地工具、凭证可见性、Git worktree、HOME、known_hosts、agent port 和 proxy DNS`--remote` 会增加 GitHub 网络、issue API、SSH/HTTPS `git ls-remote`、GitHub SSH、`gh auth status``gh repo view``gh issue read/view` 和只读 `gh pr list` 探测;`--push-dry-run` 会额外执行 `git push --dry-run`,验证远端写权限但不创建分支;`--pr-create-dry-run` 会在 runner 内生成受控 PR body 并执行 `scripts/cli.ts gh pr create --dry-run`,只证明 PR body guard 和命令形态可用,不 POST GitHub。探测输出只报告 `GH_TOKEN`/`GITHUB_TOKEN` 是否存在,不得输出 token 内容,并通过 `prCapabilityContract` 明确 token source、target branch、expected PR handoff、dry-run 不写远端和 merge unsupported 边界。缺少 runner env token 时,`authBroker.source="broker/auth-broker-needed"` 是标准结构化证据;系统 `gh` binary 缺失必须与 UniDesk REST `bun scripts/cli.ts gh` 可用性分开报告。backend-core 的稳定 `code-queue` proxy 必须把 `/api/runtime-preflight` 路由到 D601 scheduler,而不是主 server `code-queue-mgr`,因为 token 和 PR runner 能力属于执行面环境。
PR 创建依赖以下最小运行时能力:
- runtime image 必须包含 `git``gh``jq``ca-certificates``curl``openssh-client`D601 provider dev container 准备脚本也必须补齐这些工具。
- GitHub 凭证只能通过运行时 secret、环境变量或已有 SSH identity 注入。优先使用 `GH_TOKEN`,兼容 `GITHUB_TOKEN`;不得把 token 写入 Git remote、任务 prompt、日志、镜像或仓库文件。
- `CODE_QUEUE_REMOTE_CODEX_ENV_KEYS` 默认允许把 `GH_TOKEN`/`GITHUB_TOKEN` 以及 `GH_HOST``GITHUB_API_URL``GH_REPO` 从 scheduler 传给 provider dev container,供隔离执行环境内的 `gh repo view``gh issue read/view``gh pr list``gh pr create` 使用。
- DEV 的持久注入路径复用 `unidesk-dev-runtime-secrets`:把 `GH_TOKEN``GITHUB_TOKEN` 写入该 Secret 后,通过受控 `deploy apply --env dev --service code-queue` 或等价 dev-only rollout 重启 Code Queue scheduler/read/write。default/prod runner 使用生产 `unidesk` namespace 的 `code-queue-env` Secret;仅修复 dev Secret 不会覆盖 default queue scheduler。不要在 PROD Code Queue 上直接 patch Secret 或 rollout,生产 token 覆盖需要显式 release/runtime 授权。
安全验证顺序固定为先只读、再 dry-run、最后才创建真实 PR。优先执行 `/api/runtime-preflight``/api/runtime-preflight?remote=1`、带 `pushDryRun=1` 的 probe ref,以及带 `prCreateDryRun=1` 的 PR body/create dry-run guard;只有工具、token、网络、push dry-run 和 PR body guard 都满足且任务明确允许时,才创建 draft PR 或普通 PR。若创建真实 probe PR,最终报告必须记录 URL 并说明保留或关闭状态。
preflight failure 必须定位到具体缺失项。已知必须区分的状态包括:`auth-missing``GH_TOKEN`/`GITHUB_TOKEN` 未注入,且需要 env token 或 auth-broker)、`control-plane-missing`(远程 frontend/backend-core/code-queue proxy 不可达)、`git-remote-gap``git ls-remote``git push --dry-run` 失败)、系统 `gh`/`hub` 缺失、`GH_HOST`/`GITHUB_API_URL`/`GH_REPO` 未注入、`/root/.config/gh/hosts.yml``/root/.git-credentials` 缺失、SSH Git 可读但 GitHub issue/API 匿名访问返回 404、匿名 HTTPS Git 不可用、以及 `HTTP_PROXY`/`HTTPS_PROXY` 指向的 egress proxy 在 runner 内不可解析。发现这类缺口时,worker 应报告 preflight error 和阻塞项,不得强行创建 PR。
## Boundaries
Code Queue 由 D601 k3s/k8s 控制面代管,不再通过 `server rebuild``codex deploy`、维护通道直连 D601 或手工 `docker compose up` 作为正式部署路径。Code Queue 部署必须在自身正在执行任务时仍可运行;服务重启后由 restart-recovery 恢复任务状态,不能等待当前 Code Queue task 退出后再部署。
## TCP Egress Gateway
D601 k3s Pod 不能依赖主 server 公开 `15432`/`4255` 作为直连 TCP 入口;PostgreSQL 也不会自动使用 HTTP proxy 环境变量。`code-queue.k8s.yaml` 因此提供一个通用 `d601-tcp-egress-gateway`
- Pod 内业务只访问集群内 Service:`d601-tcp-egress-gateway.unidesk.svc.cluster.local:15432``:4255`
- gateway 通过 D601 provider-gateway egress proxy 的 HTTP CONNECT 转发到底层 TCP 目标。
- 新增 TCP 依赖时只扩展 `TCP_EGRESS_ROUTES`,不要在业务容器里散落公网直连地址或 ad hoc 隧道脚本。