From f0321b5bddcf85cf9479b2a2b6d8782a07f92b1b Mon Sep 17 00:00:00 2001 From: wangziqi Date: Sun, 9 Aug 2026 21:41:48 +0800 Subject: [PATCH] =?UTF-8?q?ci(deploy):=20=E9=83=A8=E7=BD=B2=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E6=94=B9=E4=B8=BA=E6=9C=AC=E5=9C=B0=20runner?= =?UTF-8?q?=20=E7=9B=B4=E8=B7=91=E7=89=88=EF=BC=88=E5=85=8D=20SSH/Secrets?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 SSH/rsync 步骤与 SSH 相关 Secrets 依赖,runs-on: self-hosted 本机直跑 - 步骤:git pull → npm ci → build → migration:run → pm2 startOrReload --update-env → 健康检查 - 新增可选输入 seed_roles:首次部署/新增权限码时强制播种 RBAC,跑完自动去掉 - .env 无需配置到 Gitea,仅放服务器部署目录 - 注释说明 runner 在 docker 容器时的挂载与宿主 pm2 要求 --- .gitea/workflows/deploy.yml | 125 +++++++++++++++++------------------- 1 file changed, 59 insertions(+), 66 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index aa8958a..561b896 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -1,90 +1,83 @@ -# PM2 手动部署工作流 -# 手动触发 → 构建 → rsync → 安装依赖 → 数据库迁移 → PM2 重载 +# PM2 本地 runner 手动部署工作流 +# 手动触发 → 服务器本地 git pull → 构建 → 依赖安装 → 数据库迁移 → PM2 重载 +# +# 适用场景:Gitea runner 与生产服务器同机(本机直跑,不需要 SSH/Secrets)。 # # 前置准备: -# 1. 服务器 MySQL 已在运行 -# 2. 服务器已安装 PM2: npm i -g pm2 -# 3. Gitea 仓库 Settings → Secrets 配置: -# - SSH_PRIVATE_KEY : 部署用 SSH 私钥 -# - SSH_HOST : 服务器地址 -# - SSH_USER : SSH 用户名 -# - SSH_PORT : SSH 端口(默认 22,可选) -# - REMOTE_DIR : 服务器项目目录,如 /opt/gongxue +# 1. Gitea Actions 已开启,且已注册 self-hosted runner(runs-on 标签与下面一致) +# 2. 服务器已 clone 仓库到部署目录(默认 /opt/gongxue,可用仓库 Variable REMOTE_DIR 覆盖) +# 3. 服务器已安装 Node 22 + PM2(npm i -g pm2),MySQL 已运行 +# 4. runner 运行账户对部署目录有写权限、可执行 npm/pm2 +# +# 关于 .env:不需要配置在 Gitea 界面。.env 只放在服务器部署目录下, +# git pull 不会覆盖它,PM2/Nest 启动时直接读取服务器上的 .env。 +# +# 关于“在 docker 里构建/迁移”: +# - 如果 runner 以“宿主机进程”方式运行(推荐,最省事):本 workflow 的 +# npm ci / build / migration 直接在宿主机执行,pm2 直接操作宿主 pm2。 +# - 如果 runner 跑在 docker 容器里:需要把部署目录挂载进容器 +# (如 -v /opt/gongxue:/opt/gongxue),构建/迁移在容器内完成; +# PM2 重载则必须打到宿主机(挂载 docker.sock 后 docker exec 到宿主, +# 或在宿主机单独跑 pm2 服务端)——容器里的 pm2 管理不了宿主进程。 -name: PM2 部署 +name: PM2 本地部署 on: workflow_dispatch: + inputs: + seed_roles: + description: '强制播种 RBAC 权限码(首次部署或新增权限码时勾选,跑完会自动去掉)' + required: false + default: false + type: boolean concurrency: - group: deploy + group: deploy-local cancel-in-progress: false jobs: deploy: - runs-on: ubuntu-latest + runs-on: self-hosted # 改为你注册 runner 时使用的 label(如 ubuntu-latest) steps: - - name: 检出代码 - uses: actions/checkout@v4 - - - name: 安装 Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' + - name: 拉取最新代码 + run: | + cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }} + git fetch origin + git checkout main + git pull origin main - name: 安装依赖 & 构建 run: | + cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }} npm ci npm run build -w @gongxue/server npm run build -w @gongxue/admin - - name: 配置 SSH + - name: 执行数据库迁移 run: | - mkdir -p ~/.ssh - # 单引号 EOF 防止 key 中的 $ / 反引号被 shell 插值(YAML 会剥掉缩进,bash 实际收到列首 EOF) - cat > ~/.ssh/deploy_key <<'EOF' - ${{ secrets.SSH_PRIVATE_KEY }} - EOF - chmod 600 ~/.ssh/deploy_key - cat >> ~/.ssh/config <<'EOF' - Host deploy-server - HostName ${{ secrets.SSH_HOST }} - User ${{ secrets.SSH_USER }} - Port ${{ secrets.SSH_PORT || '22' }} - IdentityFile ~/.ssh/deploy_key - StrictHostKeyChecking accept-new - EOF + cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }} + npm run migration:run -w @gongxue/server - - name: 同步代码到服务器 + - name: PM2 重载 run: | - rsync -avz --delete \ - --exclude='node_modules' \ - --exclude='.git' \ - --exclude='*.db' \ - --exclude='.DS_Store' \ - --exclude='logs/' \ - --exclude='.turbo/' \ - --exclude='.claude/' \ - --exclude='.codegraph/' \ - --exclude='.env*' \ - --exclude='data.sql' \ - --exclude='uploads/' \ - ./ deploy-server:${{ secrets.REMOTE_DIR }}/ - - - name: 安装依赖 → 迁移 → PM2 重载 - run: | - ssh deploy-server " - set -e - cd ${{ secrets.REMOTE_DIR }} - mkdir -p logs - echo '安装依赖...' - # 注意:migration:run 依赖 ts-node/tsconfig-paths(devDependencies),不能 --omit=dev - npm ci - echo '执行数据库迁移...' - npm run migration:run -w @gongxue/server - echo 'PM2 重载...' + cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }} + if [ "${{ github.event.inputs.seed_roles }}" = "true" ]; then + echo '>>> 强制播种 RBAC 权限码(本次进程带 SEED_ROLES=true)' + SEED_ROLES=true pm2 startOrReload ecosystem.config.cjs --only gongxue-backend --update-env + pm2 restart gongxue-backend --update-env # 去掉 SEED_ROLES 正常重启 + else pm2 startOrReload ecosystem.config.cjs --update-env - pm2 save - echo '=== PM2 状态 ===' - pm2 status - " + fi + pm2 save + pm2 status + + - name: 健康检查 + run: | + cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }} + sleep 3 + code="$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/api/dashboard/stats || true)" + echo "后端 HTTP 状态: ${code}(401=正常,接口需登录)" + if [ "${code}" != "401" ] && [ "${code}" != "200" ]; then + echo "健康检查失败:后端未按预期响应" >&2 + exit 1 + fi