224 lines
9.8 KiB
YAML
224 lines
9.8 KiB
YAML
# ═══════════════════════════════════════════════════════════════
|
||
# Demo 部署工作流 — CI 成功后自动部署 / 可手动触发
|
||
#
|
||
# 触发条件:
|
||
# 1. "CI — Docker Build & Push" 在 main/master 上成功完成后自动触发
|
||
# 2. workflow_dispatch 手动触发(可指定镜像标签)
|
||
#
|
||
# 运行环境:
|
||
# - self-hosted runner(与 Gitea 同一服务器)
|
||
# - Docker 部署,外置 MySQL & Caddy
|
||
#
|
||
# 前置配置(Gitea → 仓库 → 设置 → Secrets):
|
||
# REGISTRY_TOKEN — 具有 package:read 权限的 Gitea Access Token
|
||
# DEMO_SECRET_KEY — Flask SECRET_KEY(随机字符串,≥32位)
|
||
# DEMO_ADMIN_PASS — Demo 管理员密码(首次部署时设置)
|
||
#
|
||
# 服务器前置条件:
|
||
# - 已安装 Docker + docker compose(或 docker-compose)
|
||
# - 已安装并运行 Caddy,配置了 sites 目录 include
|
||
# - runner 用户在 docker 组 或 使用 sudo(见下方 SUDO_DOCKER 变量)
|
||
# ═══════════════════════════════════════════════════════════════
|
||
|
||
name: Deploy — Demo Environment
|
||
|
||
on:
|
||
# CI 工作流在 main/master 完成后触发
|
||
workflow_run:
|
||
workflows:
|
||
- "CI — Docker Build & Push"
|
||
branches:
|
||
- main
|
||
- master
|
||
types:
|
||
- completed
|
||
|
||
# 手动触发,支持指定镜像标签
|
||
workflow_dispatch:
|
||
inputs:
|
||
image_tag:
|
||
description: '镜像标签(默认: latest)'
|
||
required: false
|
||
default: 'latest'
|
||
|
||
env:
|
||
REGISTRY: git.hty1024.com
|
||
# Demo 部署目录(需与服务器实际路径一致)
|
||
DEPLOY_DIR: /opt/resource-library-demo
|
||
# Caddy 站点配置目录(需在 Caddyfile 中通过 import 引用)
|
||
CADDY_SITES_DIR: /etc/caddy/sites
|
||
# 应用对外端口(Caddy 反向代理到此端口)
|
||
APP_PORT: 5000
|
||
# Demo 域名
|
||
DOMAIN: prl.hty1024.com
|
||
# 外置 MySQL 连接串
|
||
DB_URL: mysql+pymysql://resource_library:BWRVzzCwzuuP_1Hj@pma.hty1024.com:31000/resource_library
|
||
|
||
jobs:
|
||
deploy-demo:
|
||
name: Deploy to Demo
|
||
runs-on: self-hosted
|
||
|
||
# workflow_run 触发时,仅在 CI 成功时继续
|
||
if: >
|
||
github.event_name == 'workflow_dispatch' ||
|
||
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
|
||
|
||
steps:
|
||
# ── 1. 检出代码(获取 compose 文件等) ──────────────────────
|
||
- name: 检出代码
|
||
uses: actions/checkout@v4
|
||
|
||
# ── 2. 确定目标镜像标签 ──────────────────────────────────────
|
||
- name: 确定镜像标签
|
||
id: image
|
||
run: |
|
||
REPO=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
|
||
IMAGE_NAME="${{ env.REGISTRY }}/${REPO}"
|
||
|
||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||
TAG="${{ github.event.inputs.image_tag }}"
|
||
else
|
||
TAG="latest"
|
||
fi
|
||
|
||
echo "name=${IMAGE_NAME}" >> $GITHUB_OUTPUT
|
||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||
echo "full=${IMAGE_NAME}:${TAG}" >> $GITHUB_OUTPUT
|
||
echo "镜像: ${IMAGE_NAME}:${TAG}"
|
||
|
||
# ── 3. 登录 Gitea 镜像仓库 ──────────────────────────────────
|
||
- name: 登录 Gitea 镜像仓库
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ${{ env.REGISTRY }}
|
||
username: ${{ gitea.actor }}
|
||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||
|
||
# ── 4. 检测 Docker Compose 命令 ─────────────────────────────
|
||
- name: 检测 Compose 命令
|
||
run: |
|
||
if docker compose version &>/dev/null 2>&1; then
|
||
echo "COMPOSE_CMD=docker compose" >> $GITHUB_ENV
|
||
echo "使用: docker compose"
|
||
elif command -v docker-compose &>/dev/null; then
|
||
echo "COMPOSE_CMD=docker-compose" >> $GITHUB_ENV
|
||
echo "使用: docker-compose"
|
||
else
|
||
echo "错误:未找到 docker compose 或 docker-compose,请先安装"
|
||
exit 1
|
||
fi
|
||
|
||
# ── 5. 拉取最新镜像 ──────────────────────────────────────────
|
||
- name: 拉取镜像
|
||
run: |
|
||
docker pull ${{ steps.image.outputs.full }}
|
||
echo "镜像摘要: $(docker inspect ${{ steps.image.outputs.full }} --format='{{.Id}}')"
|
||
|
||
# ── 6. 创建部署目录 ──────────────────────────────────────────
|
||
- name: 准备部署目录
|
||
run: |
|
||
mkdir -p ${{ env.DEPLOY_DIR }}
|
||
|
||
# ── 7. 写入环境配置文件 ──────────────────────────────────────
|
||
- name: 写入 .env 文件
|
||
run: |
|
||
cat > ${{ env.DEPLOY_DIR }}/.env.demo << 'ENVEOF'
|
||
# 自动生成 — 请勿手动编辑,由 CI/CD 工作流维护
|
||
DATABASE_URL=${{ env.DB_URL }}
|
||
SECRET_KEY=${{ secrets.DEMO_SECRET_KEY }}
|
||
APP_PORT=${{ env.APP_PORT }}
|
||
FLASK_ENV=production
|
||
ENVEOF
|
||
chmod 600 ${{ env.DEPLOY_DIR }}/.env.demo
|
||
echo "env 文件已写入"
|
||
|
||
# ── 8. 复制 compose 文件到部署目录 ───────────────────────────
|
||
- name: 复制 Compose 文件
|
||
run: |
|
||
cp docker-compose.external-db.yml ${{ env.DEPLOY_DIR }}/docker-compose.yml
|
||
|
||
# ── 9. 更新 compose 文件中的镜像引用 ─────────────────────────
|
||
- name: 更新镜像标签
|
||
run: |
|
||
cd ${{ env.DEPLOY_DIR }}
|
||
# 将 compose 文件中的镜像替换为当前目标镜像
|
||
sed -i "s|image:.*resource-library.*|image: ${{ steps.image.outputs.full }}|g" docker-compose.yml
|
||
echo "已更新镜像引用为: ${{ steps.image.outputs.full }}"
|
||
|
||
# ── 10. 部署 / 更新容器 ──────────────────────────────────────
|
||
- name: 部署容器
|
||
run: |
|
||
cd ${{ env.DEPLOY_DIR }}
|
||
|
||
$COMPOSE_CMD \
|
||
--env-file .env.demo \
|
||
--project-name resource-library-demo \
|
||
up -d --remove-orphans --pull never
|
||
|
||
echo "容器已启动"
|
||
$COMPOSE_CMD --project-name resource-library-demo ps
|
||
|
||
# ── 11. 等待服务就绪 ─────────────────────────────────────────
|
||
- name: 健康检查
|
||
run: |
|
||
max_wait=90
|
||
elapsed=0
|
||
url="http://127.0.0.1:${{ env.APP_PORT }}/auth/login"
|
||
|
||
echo "等待服务就绪(最长 ${max_wait}s)…"
|
||
while [ "$elapsed" -lt "$max_wait" ]; do
|
||
if curl -fsSL --max-time 5 "$url" > /dev/null 2>&1; then
|
||
echo "服务健康!(${elapsed}s)"
|
||
exit 0
|
||
fi
|
||
sleep 5
|
||
elapsed=$((elapsed + 5))
|
||
echo " 已等待 ${elapsed}s…"
|
||
done
|
||
echo "健康检查超时,查看日志:"
|
||
$COMPOSE_CMD \
|
||
--project-name resource-library-demo \
|
||
logs --tail 50 2>/dev/null || true
|
||
exit 1
|
||
|
||
# ── 12. 配置 Caddy 站点 ──────────────────────────────────────
|
||
- name: 配置 Caddy
|
||
run: |
|
||
# 确保 Caddy sites 目录存在
|
||
mkdir -p ${{ env.CADDY_SITES_DIR }}
|
||
|
||
# 写入站点配置(仅在文件内容变更时才重载)
|
||
CADDY_CONF="${{ env.CADDY_SITES_DIR }}/${{ env.DOMAIN }}.caddy"
|
||
NEW_CONF=$(cat docker/caddy/${{ env.DOMAIN }}.caddy)
|
||
OLD_CONF=$(cat "$CADDY_CONF" 2>/dev/null || echo "")
|
||
|
||
if [ "$NEW_CONF" != "$OLD_CONF" ]; then
|
||
cp docker/caddy/${{ env.DOMAIN }}.caddy "$CADDY_CONF"
|
||
echo "Caddy 配置已更新,重载…"
|
||
# 优先使用 systemctl,退而使用 caddy reload
|
||
if systemctl is-active --quiet caddy; then
|
||
systemctl reload caddy || caddy reload --config /etc/caddy/Caddyfile
|
||
elif caddy validate --config /etc/caddy/Caddyfile &>/dev/null; then
|
||
caddy reload --config /etc/caddy/Caddyfile
|
||
else
|
||
echo "警告:无法重载 Caddy,请手动执行 systemctl reload caddy"
|
||
fi
|
||
else
|
||
echo "Caddy 配置未变更,跳过重载"
|
||
fi
|
||
|
||
# ── 13. 输出部署摘要 ─────────────────────────────────────────
|
||
- name: 输出部署摘要
|
||
run: |
|
||
echo "## 🚀 Demo 环境部署成功" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 项目 | 值 |" >> $GITHUB_STEP_SUMMARY
|
||
echo "|------|-----|" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 访问地址 | https://${{ env.DOMAIN }} |" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 镜像 | \`${{ steps.image.outputs.full }}\` |" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 触发方式 | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
|
||
echo "| 部署时间 | $(date -u '+%Y-%m-%d %H:%M:%S UTC') |" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**Demo 地址:** https://${{ env.DOMAIN }}" >> $GITHUB_STEP_SUMMARY
|