Files
sundynix-pets/.gitea/workflows/deploy.yml
T
Blizzard eaa21585de ci: Docker 单镜像部署 + Gitea 自动发布
- pets-be/Dockerfile:多阶段单镜像,node 构建管理后台 → Go 编译内嵌
  (go:embed)→ alpine 运行。一个容器同时提供 /api 与 /admin,50MB,
  非 root、内置 tzdata 保证按东八区计算每日任务
- deploy/docker-compose.yml:只有一个 app 容器,MySQL/MinIO 用外部现成的,
  容器内 9090 映射宿主机 4000
- deploy/.env.example:全部配置项(MySQL/MinIO/微信/AI/管理员)
- .gitea/workflows/deploy.yml:push 或合并到 main 触发,runner 构建镜像 →
  save 打包 → scp 到服务器 → docker load + compose up -d → 健康检查
- 修复容器化阻塞问题:config.Load 原本强制要求 config.yaml(而它不进 git),
  且 viper 未登记默认值的 key 环境变量绑不上。现补全默认值并把配置文件
  改为可选,纯 .env 即可启动
- 服务端口统一改为 9090

验证:镜像构建通过;本地起完整栈 ping/admin/登录/建表 seed/图片上传全通;
对接真实 MySQL 9.4(sundynix_pet)建表 19 张并 seed 成功。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 16:47:49 +08:00

84 lines
3.4 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.
name: deploy
# 只认 main(含 PR 合并入 main)。
# runner 上构建单个应用镜像 → docker save 打包 → scp 镜像包 + compose 到服务器
# → 服务器 docker load + docker compose up -d(用预构建镜像,不在服务器上 build)。
# 服务器上只有 compose + .env(+ 临时镜像包),没有源码。
on:
push:
branches: [main]
workflow_dispatch:
env:
REMOTE_DIR: /home/workspace/sundynix-pet
IMAGE: sundynix/pets-be:latest
jobs:
deploy:
runs-on: ubuntu-latest # 须匹配已注册 runner 的标签
steps:
# 不用 actions/checkout(它要去 github.com 下载 action,内网 runner 连不上会 EOF);
# 直接从内网 Gitea 用工作流自带 token 拉本仓库当前分支。
- name: 检出代码(内网 Gitea
run: |
git init -q .
git remote add origin "https://token:${{ github.token }}@git.sundynix.cn/${{ github.repository }}.git"
git fetch -q --depth 1 origin "${{ github.ref_name }}"
git checkout -q FETCH_HEAD
# 单镜像:内部先用 node 构建管理后台前端,再 Go 编译内嵌进二进制。
# 构建上下文是 pets-be/go.mod 和 web/admin 都在里面)。
- name: 构建应用镜像
run: docker build -f pets-be/Dockerfile -t "$IMAGE" pets-be
- name: 导出镜像为压缩包
run: docker save "$IMAGE" | gzip > image.tar.gz
- name: 安装 ssh 工具
run: |
if command -v apt-get >/dev/null; then
apt-get update && apt-get install -y sshpass openssh-client
elif command -v apk >/dev/null; then
apk add --no-cache sshpass openssh-client
fi
- name: 传镜像包与 compose 到服务器
env:
SSHPASS: ${{ secrets.DEPLOY_PASSWORD }}
run: |
H="${{ secrets.DEPLOY_HOST }}"
U="${{ secrets.DEPLOY_USER }}"
# 只送两样:镜像包 + compose。服务器上的 .env 由人工预放,绝不覆盖。
sshpass -e ssh -o StrictHostKeyChecking=no "$U@$H" "mkdir -p $REMOTE_DIR"
sshpass -e scp -o StrictHostKeyChecking=no image.tar.gz "$U@$H:$REMOTE_DIR/"
sshpass -e scp -o StrictHostKeyChecking=no \
deploy/docker-compose.yml "$U@$H:$REMOTE_DIR/docker-compose.yml"
- name: 服务器加载镜像并起服务
env:
SSHPASS: ${{ secrets.DEPLOY_PASSWORD }}
run: |
H="${{ secrets.DEPLOY_HOST }}"
U="${{ secrets.DEPLOY_USER }}"
sshpass -e ssh -o StrictHostKeyChecking=no "$U@$H" "\
cd $REMOTE_DIR && \
test -f .env || { echo '❌ 缺少 .env,请先按 deploy/.env.example 创建'; exit 1; } && \
gunzip -c image.tar.gz | docker load && \
rm -f image.tar.gz && \
docker compose up -d --no-build && \
docker image prune -f"
- name: 健康检查(宿主机 :4000/api/ping
env:
SSHPASS: ${{ secrets.DEPLOY_PASSWORD }}
run: |
H="${{ secrets.DEPLOY_HOST }}"
U="${{ secrets.DEPLOY_USER }}"
sshpass -e ssh -o StrictHostKeyChecking=no "$U@$H" "\
for i in \$(seq 1 20); do \
curl -sf http://127.0.0.1:4000/api/ping && echo ' ✅ 健康' && exit 0; \
sleep 3; \
done; \
echo '❌ 健康检查失败'; \
cd $REMOTE_DIR && docker compose logs --tail 50 app; exit 1"