# 服务器部署规范(开发者与 AI 必读) 本规范适用于所有开发者及其使用的 AI 编程工具。任何人准备更新生产服务器前,都必须先阅读根目录 `AGENTS.md`、`仓库提交与合并规范.md` 和本文件。目标是让仓库成为唯一代码来源,防止本地修改、并行推送和同时部署互相覆盖。 ## 1. 固定环境与边界 - 生产服务器项目根目录:`/opt/cangku` - 服务器代码目录:`/opt/cangku/app` - 生产编排文件:`/opt/cangku/app/deploy/production/docker-compose.yml` - 对外站点及注册接口:`https://ck.yydd.ai:8443` - 公网 TLS Redis:`ck.yydd.ai:6380` - 服务器 SSH 密钥目录位于开发者桌面:`~/Desktop/cangku-156.225.27.52-ssh-key` - 当前私钥文件:`~/Desktop/cangku-156.225.27.52-ssh-key/cangku-prod-root-ed25519` - SSH 目标:`root@156.225.27.52`,端口 `50232` 私钥只能保存在获准访问服务器的开发机器上,权限必须为 `0600`。禁止把私钥、密码、部署 Key、`.env`、`.remote-access` 或服务器 `/opt/cangku/shared` 中的内容复制到仓库、提交、PR、聊天记录或部署日志。没有上述密钥目录的开发者无权部署,应把已经合并的提交 SHA 交给有权限的维护者。 ## 2. 开发机器无需安装数据库或 Redis 本项目的团队开发环境使用中央托管服务。开发者和 AI 不得为了本地开发另建或初始化 MySQL、Redis,也不要把生产连接密码写入代码: 1. 第一次运行 `npm run remote:dev`,在弹窗中填写维护者提供的配置请求地址和部署 Key。 2. 注册服务自动配置中央系统数据库、TLS Redis、第三方数据库连接和独立管理员。 3. 系统数据库通过受限 SSH 隧道连接;Redis 使用 `ck.yydd.ai:6380` TLS 直连。 4. 获取到的凭据只写入 Git 已忽略的 `backend/.env` 和 `.remote-access/`。部署 Key 不保存。 5. 管理员账号和随机密码只显示一次,开发者必须保存在自己的密码管理器中。 6. 注册完成后直接登录系统,不需要执行数据库初始化,也不再进入业务数据库、Redis、登录方式和对象存储配置向导。 常用启动命令: ```bash npm --prefix backend ci npm --prefix frontend ci npm run remote:dev ``` 不要运行会创建本地业务库、覆盖中央配置或向生产库导入初始化 SQL 的命令。确实需要隔离数据库做迁移测试时,必须使用单独的测试环境,并在 PR 中说明,不能连接生产系统库执行测试。 ## 3. 部署前先把代码安全合入主仓库 服务器只能部署已经进入远端 `origin/main` 的提交。不得把开发机器上的未提交文件直接复制到服务器,也不得让服务器拉取尚未审核的个人分支。 开发者或 AI 在本地依次检查: ```bash pwd git remote -v git branch --show-current git status --short git fetch origin --prune git log --left-right --oneline HEAD...origin/main git diff --check origin/main...HEAD git diff --stat origin/main...HEAD ``` 必须确认: 1. 当前目录确实是本项目的独立工作目录,当前分支不是 `main`,并且没有混入其他任务或其他开发者的未提交文件。 2. 本地已有修改先按 `仓库提交与合并规范.md` 提交到唯一任务分支,再同步最新 `origin/main`。 3. 如果主仓库已有更新,先合并到任务分支,逐处处理冲突,重新检查最终差异并运行受影响测试。 4. 禁止使用强制推送、`git reset --hard`、批量选择 `ours/theirs` 或复制旧目录覆盖新代码来解决冲突。 5. 将任务分支推送到主仓库,创建 PR,经过审核和验证后合并到 `main`。这里的“先推送主仓库”指推送任务分支并通过 PR 合并,禁止直接推送 `main`。 6. PR 合并后再次执行 `git fetch origin`,记录准备部署的 `origin/main` 完整 SHA。部署 SHA 必须与审核通过的最终提交一致。 如果本次变更涉及数据表、索引、查询、数据映射或同步任务,部署者还必须确认 PR 已按《仓库提交与合并规范》记录索引与执行计划证据、分批/并发/超时边界、大表锁影响和回退方式。证据缺失、依赖全表扫描、可能对系统库或第三方云库造成不可控负载时,不得部署。 有冲突时,AI 必须阅读共同基线和双方改动,保留双方仍然有效的行为。无法确定业务取舍时,停止该冲突的处理并请负责人决定。冲突解决后的代码必须重新测试、重新审核,不能沿用冲突前的结果。 ## 4. 检查服务器是否正在更新 任何部署都必须使用 `/opt/cangku/deploy.lock` 文件锁。先检查当前服务和更新进程: ```bash SSH_KEY="$HOME/Desktop/cangku-156.225.27.52-ssh-key/cangku-prod-root-ed25519" chmod 600 "$SSH_KEY" ssh -i "$SSH_KEY" -p 50232 -o BatchMode=yes root@156.225.27.52 ' cd /opt/cangku/app docker compose -f deploy/production/docker-compose.yml ps ps -ef | grep -E "[g]it (pull|fetch|merge)|[d]ocker compose|[n]pm .*build" || true flock -n /opt/cangku/deploy.lock true ' ``` 最后一条命令返回非零时,表示另一名开发者或 AI 正在部署。必须等待对方完成并确认服务恢复,不能绕过、删除或替换锁文件,也不能同时执行 Git、构建、容器重建或数据库操作。 取得锁之前发现容器不健康、Git 操作未结束、构建仍在运行或存在 `.git/index.lock` 时,不得继续更新。先确认是否有正在运行的部署;需要处理故障时保留现场和日志并联系当前部署者。禁止在不清楚来源时终止进程或删除 Git 锁。 ## 5. 在同一个服务器锁内拉取和部署 确认目标 SHA 已进入 `origin/main` 后,通过一次 SSH 会话取得锁并保持到验证结束。将下面的 `<审核通过的完整 SHA>` 替换为实际值: ```bash SSH_KEY="$HOME/Desktop/cangku-156.225.27.52-ssh-key/cangku-prod-root-ed25519" DEPLOY_SHA="<审核通过的完整 SHA>" ssh -i "$SSH_KEY" -p 50232 -o BatchMode=yes root@156.225.27.52 \ "DEPLOY_SHA='$DEPLOY_SHA' flock -w 1800 /opt/cangku/deploy.lock bash -s" <<'REMOTE' set -euo pipefail cd /opt/cangku/app test -d .git || { echo '服务器代码目录不是 Git 工作区,停止部署'; exit 1; } test -z "$(git status --porcelain)" || { echo '服务器存在未提交修改,停止部署'; exit 1; } docker compose -f deploy/production/docker-compose.yml ps curl -fsS http://127.0.0.1:4090/health >/dev/null || { echo '更新前服务不健康,停止部署并先查明当前状态' exit 1 } git fetch origin --prune test "$(git rev-parse "origin/main^{commit}")" = "$DEPLOY_SHA" || { echo 'origin/main 与待部署 SHA 不一致,停止部署' exit 1 } git switch main git pull --ff-only origin main test "$(git rev-parse HEAD)" = "$DEPLOY_SHA" || { echo '服务器 HEAD 与待部署 SHA 不一致,停止部署' exit 1 } npm --prefix frontend ci npm --prefix frontend run build if grep -q '^SOURCE_GIT_SHA=' /opt/cangku/shared/backend.env; then sed -i "s/^SOURCE_GIT_SHA=.*/SOURCE_GIT_SHA=$DEPLOY_SHA/" /opt/cangku/shared/backend.env else printf 'SOURCE_GIT_SHA=%s\n' "$DEPLOY_SHA" >> /opt/cangku/shared/backend.env fi if grep -q '^SOURCE_GIT_REF=' /opt/cangku/shared/backend.env; then sed -i 's/^SOURCE_GIT_REF=.*/SOURCE_GIT_REF=main/' /opt/cangku/shared/backend.env else printf 'SOURCE_GIT_REF=main\n' >> /opt/cangku/shared/backend.env fi docker compose -f deploy/production/docker-compose.yml config >/dev/null docker compose -f deploy/production/docker-compose.yml up -d --build for attempt in $(seq 1 60); do if curl -fsS http://127.0.0.1:4090/health >/dev/null; then break fi if [ "$attempt" -eq 60 ]; then echo '后端健康检查超时' exit 1 fi sleep 2 done curl -fsS https://ck.yydd.ai:8443/ >/dev/null curl -fsS https://ck.yydd.ai:8443/health docker compose -f deploy/production/docker-compose.yml ps git status --short git rev-parse HEAD REMOTE ``` `flock -w 1800` 会等待最多 30 分钟。等待期间不得另开会话绕过锁部署。超时后先联系当前部署者并检查服务状态,不要直接杀进程。 服务器工作区必须保持干净并只做快进更新。`git pull --ff-only` 失败、服务器出现未提交文件或目标 SHA 变化时,应停止部署,在本地仓库通过新提交和 PR 解决;禁止在服务器上编辑业务代码、处理合并冲突、强制切换提交或重置历史。 ## 6. 部署完成标准 部署者和 AI 只有在以下项目全部确认后才能报告完成: - 服务器 `HEAD` 等于预先记录且已合并的 `origin/main` SHA。 - `git status --short` 没有输出。 - MySQL、Redis、Redis TLS 网关、后端和注册服务容器处于正常运行状态。 - `https://ck.yydd.ai:8443/` 返回成功,`/health` 显示系统数据库、第三方数据库和 Redis 连接成功。 - `ck.yydd.ai:6380` 的 TLS 证书校验通过;原始 Redis 端口没有对公网开放。 - 新版本的关键用户路径已验证,没有覆盖其他开发者已经上线的功能。 - 最终报告包含任务分支、PR、部署 SHA、实际检查结果和未解决问题。 如果部署失败,不得把服务器强制重置到某个旧提交。先保留日志和当前 SHA,在本地创建修复或回退 PR;合并后再按同一流程部署。涉及不可逆数据库迁移时,部署前必须另行制定备份、兼容与回退方案,本文件不能替代迁移评审。