ci: 部署工作流改为本地 runner 直跑版(免 SSH/Secrets) #65
@@ -1,90 +1,83 @@
|
|||||||
# PM2 手动部署工作流
|
# PM2 本地 runner 手动部署工作流
|
||||||
# 手动触发 → 构建 → rsync → 安装依赖 → 数据库迁移 → PM2 重载
|
# 手动触发 → 服务器本地 git pull → 构建 → 依赖安装 → 数据库迁移 → PM2 重载
|
||||||
|
#
|
||||||
|
# 适用场景:Gitea runner 与生产服务器同机(本机直跑,不需要 SSH/Secrets)。
|
||||||
#
|
#
|
||||||
# 前置准备:
|
# 前置准备:
|
||||||
# 1. 服务器 MySQL 已在运行
|
# 1. Gitea Actions 已开启,且已注册 self-hosted runner(runs-on 标签与下面一致)
|
||||||
# 2. 服务器已安装 PM2: npm i -g pm2
|
# 2. 服务器已 clone 仓库到部署目录(默认 /opt/gongxue,可用仓库 Variable REMOTE_DIR 覆盖)
|
||||||
# 3. Gitea 仓库 Settings → Secrets 配置:
|
# 3. 服务器已安装 Node 22 + PM2(npm i -g pm2),MySQL 已运行
|
||||||
# - SSH_PRIVATE_KEY : 部署用 SSH 私钥
|
# 4. runner 运行账户对部署目录有写权限、可执行 npm/pm2
|
||||||
# - SSH_HOST : 服务器地址
|
#
|
||||||
# - SSH_USER : SSH 用户名
|
# 关于 .env:不需要配置在 Gitea 界面。.env 只放在服务器部署目录下,
|
||||||
# - SSH_PORT : SSH 端口(默认 22,可选)
|
# git pull 不会覆盖它,PM2/Nest 启动时直接读取服务器上的 .env。
|
||||||
# - REMOTE_DIR : 服务器项目目录,如 /opt/gongxue
|
#
|
||||||
|
# 关于“在 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:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
seed_roles:
|
||||||
|
description: '强制播种 RBAC 权限码(首次部署或新增权限码时勾选,跑完会自动去掉)'
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: deploy
|
group: deploy-local
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: self-hosted # 改为你注册 runner 时使用的 label(如 ubuntu-latest)
|
||||||
steps:
|
steps:
|
||||||
- name: 检出代码
|
- name: 拉取最新代码
|
||||||
uses: actions/checkout@v4
|
run: |
|
||||||
|
cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }}
|
||||||
- name: 安装 Node.js
|
git fetch origin
|
||||||
uses: actions/setup-node@v4
|
git checkout main
|
||||||
with:
|
git pull origin main
|
||||||
node-version: '22'
|
|
||||||
|
|
||||||
- name: 安装依赖 & 构建
|
- name: 安装依赖 & 构建
|
||||||
run: |
|
run: |
|
||||||
|
cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }}
|
||||||
npm ci
|
npm ci
|
||||||
npm run build -w @gongxue/server
|
npm run build -w @gongxue/server
|
||||||
npm run build -w @gongxue/admin
|
npm run build -w @gongxue/admin
|
||||||
|
|
||||||
- name: 配置 SSH
|
- name: 执行数据库迁移
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/.ssh
|
cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }}
|
||||||
# 单引号 EOF 防止 key 中的 $ / 反引号被 shell 插值(YAML 会剥掉缩进,bash 实际收到列首 EOF)
|
npm run migration:run -w @gongxue/server
|
||||||
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
|
|
||||||
|
|
||||||
- name: 同步代码到服务器
|
- name: PM2 重载
|
||||||
run: |
|
run: |
|
||||||
rsync -avz --delete \
|
cd ${{ vars.REMOTE_DIR || '/opt/gongxue' }}
|
||||||
--exclude='node_modules' \
|
if [ "${{ github.event.inputs.seed_roles }}" = "true" ]; then
|
||||||
--exclude='.git' \
|
echo '>>> 强制播种 RBAC 权限码(本次进程带 SEED_ROLES=true)'
|
||||||
--exclude='*.db' \
|
SEED_ROLES=true pm2 startOrReload ecosystem.config.cjs --only gongxue-backend --update-env
|
||||||
--exclude='.DS_Store' \
|
pm2 restart gongxue-backend --update-env # 去掉 SEED_ROLES 正常重启
|
||||||
--exclude='logs/' \
|
else
|
||||||
--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 重载...'
|
|
||||||
pm2 startOrReload ecosystem.config.cjs --update-env
|
pm2 startOrReload ecosystem.config.cjs --update-env
|
||||||
pm2 save
|
fi
|
||||||
echo '=== PM2 状态 ==='
|
pm2 save
|
||||||
pm2 status
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user