# Code Queue Deploy `bun scripts/cli.ts codex deploy ` 是旧兼容入口,现已禁用。原因是它会通过 backend-core `host.ssh` 维护通道直连 D601 部署 Code Queue,把维护入口扩张成第二套部署系统。 Code Queue 后续正式生产部署必须走一条受控 CD 路径并单独审查;当前阶段只提供 dev artifact consumer。`deploy apply --env dev --service code-queue` 或 `artifact-registry deploy-service --env dev --service code-queue` 可以消费 D601 registry 中的 `unidesk/code-queue:`,只更新 `unidesk-dev` Code Queue execution slice,并通过 Kubernetes API service proxy 验证健康。`--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`。 ## Command ```bash bun scripts/cli.ts codex deploy ``` 该命令必须返回结构化错误,说明维护通道直连 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 ` 导出 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-base;provider-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. `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. `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-only 规则,直到具体任务或指挥官要求改为 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/] [--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 view` 和只读 `gh pr list` 探测;`--push-dry-run` 会额外执行 `git push --dry-run`,验证远端写权限但不创建分支。探测输出只报告 `GH_TOKEN`/`GITHUB_TOKEN` 是否存在,不得输出 token 内容。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 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;只有工具、token、网络和 push dry-run 都满足且任务明确允许时,才创建 draft PR 或普通 PR。若创建真实 probe PR,最终报告必须记录 URL 并说明保留或关闭状态。 preflight failure 必须定位到具体缺失项。已知必须区分的状态包括:`gh`/`hub` 缺失、`GH_TOKEN`/`GITHUB_TOKEN`/`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 隧道脚本。