Files
OJ2/.github/workflows/deploy.yml
yuetsh 66d325d460
Some checks failed
Deploy / deploy (push) Has been cancelled
ci(部署): rsync 加 --no-owner --no-group,别把 runner 的 uid 搬到服务器
服务器上 `git pull` 报「检测到可疑的仓库所有权」:

    drwxr-xr-x 9 1001 1001  /root/OJDeploy/OJ2
    drwxr-xr-x 8    0    0  /root/OJDeploy/OJ2/.git

原因是 `rsync -a` 展开含 `-o -g`(保留属主/属组),接收端又是 root,
所以源端的 uid 会被真写上去 —— GitHub 托管 runner 的 runner 用户是 uid 1001。
而 `.git` 在 --exclude 里,一直是当初手动 clone 时的 root。两者对不上,
git 2.35.2 起的 safe.directory 检查就把服务器上所有 git 操作挡下了。

加 --no-owner --no-group 之后文件落地归 ssh 登录用户(root)所有,不再错位。

注意这只防复发,**不修复已经错位的目录**:rsync 不带 -o/-g 时不会去改已存在
文件的属主。服务器上还要手动跑一次

    chown root:root /root/OJDeploy/OJ2

只改这一个目录,**不要 -R** —— git 的属主检查不递归,而 OJ2/data 下可能是
「自带数据」形态的整个 postgres 数据目录和判题沙箱以别的 uid 建的运行目录,
递归 chown 会让它们起不来。

这个问题一直都在,只是以前没在服务器上跑过 git 命令所以没撞上。

验证:只做了 YAML 语法校验 —— 这条工作流要真的 push 到 github 才跑得起来,
本机验不了。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 08:08:06 -06:00

109 lines
4.6 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 在 runner 上编好产物 → rsync 到服务器 → 服务器上跑 docker/deploy.sh 起栈。
#
# 为什么产物在这里编:服务器性能差,镜像 builder 阶段1238 个包的 bun install +
# bun compile + vite build首次约 5 分钟,光前端就 160s。runner 编完传过去,
# 服务器那边的镜像构建只剩几条 COPY。
#
# 服务器自己编的能力**没有砍掉**docker/deploy.sh 不带 --prebuilt 就是原来的
# 行为ARTIFACTS=build只要机器上有 docker 就能手动部署,不依赖这个工作流。
#
# 触发的是 push 到 **github** 这个 remoteorigin 是 git.xuyue.cc平时那次
# push 不会触发):
#
# git push github main
#
# 仓库 Settings → Secrets 需要两个:
# HOST 服务器地址
# KEY 能以 root 登录该服务器的私钥(完整 PEM含首尾 BEGIN/END 行)
name: Deploy
on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
# 两次 push 挨得近时,别让两个 deploy.sh 在服务器上同时起栈。
concurrency:
group: deploy
cancel-in-progress: false
env:
REMOTE_PORT: 22
REMOTE_DIR: /root/OJDeploy/OJ2
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
# 依赖装到 ~/.bun/install/cache命中的话 install 只剩几秒。
# v6 起跑在 node24 上v4 还是 node20GitHub 正在退役 node20 runtime
# 和上面两个 action 一致。v5+ 要求 runner >= 2.327.1ubuntu-latest 是
# GitHub 托管的、始终满足;换自建 runner 的话要留意这条。
- uses: actions/cache@v6
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: bun-${{ runner.os }}-
- name: 装依赖
run: bun install --frozen-lockfile
# 单二进制,--target=bun-linux-x64runner 就是 linux-x64和服务器一致
# 输出到 dist/oj2-api正是 Dockerfile 里 artifacts-prebuilt 阶段要的位置。
- name: 编后端
run: bun run --filter '@oj2/api' build
# 默认 production 模式,读 apps/web/.env.production在版本库里
- name: 编前端
run: cd apps/web && bun run build
- name: 配置 SSH
run: |
mkdir -p ~/.ssh && chmod 700 ~/.ssh
printf '%s\n' "${{ secrets.KEY }}" > ~/.ssh/id_deploy
chmod 600 ~/.ssh/id_deploy
ssh-keyscan -p "$REMOTE_PORT" -H "${{ secrets.HOST }}" >> ~/.ssh/known_hosts 2>/dev/null
# 源码和产物一起传。dist/oj2-api 有 77MB但 rsync 对已存在的文件做增量,
# 重编后大部分bun 运行时那段)字节不变,实际传输量远小于这个数。
#
# --delete 的排除项少一个就会出事,逐条说明:
# docker/.env 服务器上唯一一份,不在版本库里(.gitignore 排掉了 .env*)。
# 删了下一步 deploy.sh 自检就直接 die。
# data/ 测试点、题面图片、学生上传的文件,还有「自带数据」形态下的
# 整个 postgres 数据目录。删了就是删库。
# node_modules 服务器上根本不需要prebuilt 形态下连编都不编),传过去纯浪费。
# .git checkout 出来的 .git 没有任何用处。
#
# --no-owner --no-group 别删:`-a` 展开含 `-o -g`(保留属主/属组),而接收端是
# rootrsync 会把**源端的 uid 真写上去**——GitHub 托管 runner 的 runner 用户是
# uid 1001于是服务器上的工作区目录变成 1001 所有。而 `.git` 被 --exclude 掉,
# 还是当初手动 clone 时的 root。两者对不上之后在服务器上跑任何 git 命令都会被
# 「检测到可疑的仓库所有权」挡下git 2.35.2 起的 safe.directory 检查)。
- name: 同步到服务器
run: |
rsync -az --no-owner --no-group --delete \
-e "ssh -i ~/.ssh/id_deploy -p $REMOTE_PORT" \
--exclude node_modules \
--exclude .git \
--exclude data \
--exclude 'docker/.env*' \
./ "root@${{ secrets.HOST }}:$REMOTE_DIR/"
# deploy.sh 自检不过 / 容器没起来 / 冒烟发现题目数是 0都会非零退出
# 这一步跟着红,日志里能看到具体是哪一条。
- name: 起栈
run: |
ssh -i ~/.ssh/id_deploy -p "$REMOTE_PORT" "root@${{ secrets.HOST }}" \
"cd $REMOTE_DIR && docker/deploy.sh --prebuilt"