cangku/服务器部署规范.md

9.3 KiB
Raw Permalink Blame History

服务器部署规范(开发者与 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、登录方式和对象存储配置向导。

常用启动命令:

npm --prefix backend ci
npm --prefix frontend ci
npm run remote:dev

不要运行会创建本地业务库、覆盖中央配置或向生产库导入初始化 SQL 的命令。确实需要隔离数据库做迁移测试时,必须使用单独的测试环境,并在 PR 中说明,不能连接生产系统库执行测试。

3. 部署前先把代码安全合入主仓库

服务器只能部署已经进入远端 origin/main 的提交。不得把开发机器上的未提交文件直接复制到服务器,也不得让服务器拉取尚未审核的个人分支。

开发者或 AI 在本地依次检查:

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 文件锁。先检查当前服务和更新进程:

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> 替换为实际值:

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;合并后再按同一流程部署。涉及不可逆数据库迁移时,部署前必须另行制定备份、兼容与回退方案,本文件不能替代迁移评审。