Files
BYW-VoiceHub/.gitea/workflows/deploy.yml
T
Henry_Du 1718542228
构建并部署 VoiceHub / 构建 Docker 镜像 (push) Canceled after 0s
构建并部署 VoiceHub / 部署到服务器 (push) Canceled after 0s
chore(deploy): 修复 Docker 启动链 + 补 compose + Gitea Actions
2026-09-06 08:23:39 +08:00

165 lines
6.3 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: 构建并部署 VoiceHub
run-name: ${{ gitea.actor }} 触发部署 #${{{{ gitea.run_number }}}}
on:
push:
branches:
- main
- master
# 允许在 Gitea 页面手动点「运行工作流」
workflow_dispatch:
inputs:
deploy_target:
description: 是否在构建后自动部署到服务器
type: boolean
default: true
required: false
# 同一时刻只跑一个部署,避免部署竞态
concurrency:
group: deploy-production
cancel-in-progress: false
env:
# ====== 按需修改(改成你的 Gitea 域名,不要 http:// 前缀) ======
GITEA_REGISTRY: gitea.example.com
# ====== 一般不改 ======
IMAGE_NAME: byw-voicehub
DEPLOY_PATH: /opt/byw-voicehub
NODE_VERSION: "22"
jobs:
# ============================================================
# Job 1: 构建 & 推送 Docker 镜像到 Gitea 自带容器仓库
# ============================================================
build-image:
name: 构建 Docker 镜像
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.meta.outputs.tag }}
image_full: ${{ steps.meta.outputs.full }}
steps:
- name: 📥 拉取代码
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: 🔧 设置 Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: https://registry.npmmirror.com # 国内加速,不需要可删
- name: 🧪 环境校验
run: |
set -euxo pipefail
node -v
npm -v
npm ci --no-audit --no-fund
- name: 🔐 登录 Gitea 容器仓库
uses: docker/login-action@v3
with:
registry: ${{ env.GITEA_REGISTRY }}
username: ${{ gitea.repository_owner }}
password: ${{ secrets.REGISTRY_TOKEN || gitea.token }}
- name: 🏷️ 生成镜像标签
id: meta
run: |
set -euo pipefail
SHORT_SHA="${GITEA_SHA:0:7}"
DATE_TAG="$(date +%Y%m%d)-${SHORT_SHA}"
FULL="${GITEA_REGISTRY}/${GITEA_REPO_OWNER}/${IMAGE_NAME}:${DATE_TAG}"
LATEST="${GITEA_REGISTRY}/${GITEA_REPO_OWNER}/${IMAGE_NAME}:latest"
echo "tag=${DATE_TAG}" >> "$GITEA_OUTPUT"
echo "full=${FULL}" >> "$GITEA_OUTPUT"
echo "latest=${LATEST}" >> "$GITEA_OUTPUT"
echo "✅ 镜像 tag: ${DATE_TAG}"
echo "✅ 镜像完整: ${FULL}"
- name: 🐳 构建并推送镜像(BuildKit 多阶段 + 缓存)
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: |
${{ steps.meta.outputs.full }}
${{ steps.meta.outputs.latest }}
cache-from: type=registry,ref=${{ env.GITEA_REGISTRY }}/${{ gitea.repository_owner }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.GITEA_REGISTRY }}/${{ gitea.repository_owner }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
build-args: |
BUILDKIT_INLINE_CACHE=1
labels: |
org.opencontainers.image.source=${{ gitea.server_url }}/${{ gitea.repository }}
org.opencontainers.image.revision=${{ gitea.sha }}
# ============================================================
# Job 2: SSH 到服务器拉取新镜像并重启
# ============================================================
deploy:
name: 部署到服务器
needs: build-image
if: ${{ !cancelled() && !failure() && (inputs.deploy_target == true || github.event_name == 'push') }}
runs-on: ubuntu-latest
environment: production
steps:
- name: 🌐 SSH 部署到生产服务器
uses: https://github.com/appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
port: ${{ secrets.DEPLOY_PORT || 22 }}
script_stop: true
command_timeout: 30m
script: |
set -euxo pipefail
# 1) 首次部署时自动创建目录 & 空的 docker-compose.yml/.env
mkdir -p "${DEPLOY_PATH}"
cd "${DEPLOY_PATH}"
# 2) 登录 Gitea 镜像仓库(用一个仅 pull 权限的 token 更安全)
echo "${{ secrets.REGISTRY_PULL_TOKEN || gitea.token }}" \
| docker login "${GITEA_REGISTRY}" -u "${{ secrets.REGISTRY_PULL_USER || gitea.repository_owner }}" --password-stdin 2>/dev/null || true
# 3) 拉最新镜像
IMAGE_LATEST="${GITEA_REGISTRY}/${GITEA_REPO_OWNER}/${IMAGE_NAME}:latest"
docker pull "$IMAGE_LATEST"
# 4) 写一个最小的 docker-compose.override.yml,指向刚拉的镜像
# (避免改动服务器上已配置好的 docker-compose.yml 和 .env)
cat > docker-compose.override.yml <<'YAML'
services:
voicehub:
image: __REPLACE_WITH_IMAGE__
YAML
sed -i "s|__REPLACE_WITH_IMAGE__|${IMAGE_LATEST}|g" docker-compose.override.yml
# 5) 启动(如果没有 docker-compose.yml 就自动从你的仓库默认模板里下载一份)
if [ ! -f docker-compose.yml ]; then
echo "ℹ️ 首次部署:写入默认 docker-compose.yml 模板(请稍后在服务器上编辑 .env)"
curl -fsSL "${{ gitea.server_url }}/${{ gitea.repository }}/raw/branch/main/docker-compose.yml" \
-o docker-compose.yml || echo "下载失败,跳过(你需要手动上传 docker-compose.yml)"
fi
# 6) 健康拉取 + 滚动重启(先拉好再 up,downtime 最小)
docker compose pull --quiet voicehub 2>/dev/null || true
docker compose up -d --remove-orphans
# 7) 等健康检查通过,最多等 120s
for i in $(seq 1 24); do
if docker compose ps --format json 2>/dev/null | grep -q '"Health":"healthy"'; then
echo "✅ 容器健康"
break
fi
sleep 5
done
# 8) 清理旧镜像(只留最近 2 个 tag,省磁盘)
docker image prune -af --filter "until=72h" || true
echo "🎉 部署完成!镜像=${{ needs.build-image.outputs.image_full }}"