feat: align with upstream 1.5.9.9
This commit is contained in:
@@ -0,0 +1,811 @@
|
||||
From 5d015a3529957b98b6b4719f1fad4f4d4c0a5fd4 Mon Sep 17 00:00:00 2001
|
||||
From: HenryDu8133 <813367384@qq.com>
|
||||
Date: Sun, 6 Sep 2026 08:44:11 +0800
|
||||
Subject: [PATCH 02/58] =?UTF-8?q?ci:=20=E6=96=B0=E5=A2=9E=20Gitea=20Action?=
|
||||
=?UTF-8?q?s=20=E9=83=A8=E7=BD=B2=E6=B5=81=E6=B0=B4=E7=BA=BF=20+=20Runner/?=
|
||||
=?UTF-8?q?Deploy=20=E4=B8=80=E9=94=AE=E8=84=9A=E6=9C=AC?=
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
---
|
||||
.gitea/workflows/deploy.yml | 321 ++++++++++++++++++++++++++---------
|
||||
scripts/setup-deploy-user.sh | 159 +++++++++++++++++
|
||||
scripts/setup-runner.sh | 211 +++++++++++++++++++++++
|
||||
3 files changed, 609 insertions(+), 82 deletions(-)
|
||||
create mode 100644 scripts/setup-deploy-user.sh
|
||||
create mode 100644 scripts/setup-runner.sh
|
||||
|
||||
diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml
|
||||
index ca3da1f..e8d783b 100644
|
||||
--- a/.gitea/workflows/deploy.yml
|
||||
+++ b/.gitea/workflows/deploy.yml
|
||||
@@ -1,164 +1,321 @@
|
||||
-name: 构建并部署 VoiceHub
|
||||
-run-name: ${{ gitea.actor }} 触发部署 #${{{{ gitea.run_number }}}}
|
||||
+name: 构建 & 部署 BYW VoiceHub
|
||||
+run-name: ${{ github.actor }} 触发部署 · Run ${{ github.run_number }}
|
||||
|
||||
on:
|
||||
push:
|
||||
- branches:
|
||||
- - main
|
||||
- - master
|
||||
- # 允许在 Gitea 页面手动点「运行工作流」
|
||||
+ branches: [main, master]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
deploy_target:
|
||||
- description: 是否在构建后自动部署到服务器
|
||||
+ description: 构建完成后是否自动部署到服务器
|
||||
type: boolean
|
||||
default: true
|
||||
required: false
|
||||
+ skip_build_cache:
|
||||
+ description: 跳过 BuildKit 分层缓存,强制重新构建(排错用)
|
||||
+ type: boolean
|
||||
+ default: false
|
||||
+ required: false
|
||||
|
||||
-# 同一时刻只跑一个部署,避免部署竞态
|
||||
+# 同一时刻只允许一个部署在跑,避免冲突;如果新提交进来,取消前一个未完成的
|
||||
concurrency:
|
||||
group: deploy-production
|
||||
- cancel-in-progress: false
|
||||
+ cancel-in-progress: true
|
||||
|
||||
env:
|
||||
- # ====== 按需修改(改成你的 Gitea 域名,不要 http:// 前缀) ======
|
||||
- GITEA_REGISTRY: gitea.example.com
|
||||
- # ====== 一般不改 ======
|
||||
+ # ============================================================
|
||||
+ # 👇👇👇 这里改成你自己的 Gitea 域名(不要 https:// 前缀,不要端口默认 443/80)
|
||||
+ # 例:git.baoyiwai.com 或 gitea.example.com:3000
|
||||
+ GITEA_HOST: gitea.example.com
|
||||
+ # 👆👆👆
|
||||
+ # ============================================================
|
||||
IMAGE_NAME: byw-voicehub
|
||||
DEPLOY_PATH: /opt/byw-voicehub
|
||||
- NODE_VERSION: "22"
|
||||
|
||||
jobs:
|
||||
# ============================================================
|
||||
- # Job 1: 构建 & 推送 Docker 镜像到 Gitea 自带容器仓库
|
||||
+ # Job 1: 校验构建环境 & 打包产物(npm ci + build,不依赖 Docker)
|
||||
# ============================================================
|
||||
- build-image:
|
||||
- name: 构建 Docker 镜像
|
||||
+ preflight:
|
||||
+ name: Preflight 语法 & 构建检查
|
||||
runs-on: ubuntu-latest
|
||||
- outputs:
|
||||
- image_tag: ${{ steps.meta.outputs.tag }}
|
||||
- image_full: ${{ steps.meta.outputs.full }}
|
||||
+ timeout-minutes: 15
|
||||
steps:
|
||||
- - name: 📥 拉取代码
|
||||
+ - name: 📥 Checkout 代码
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- - name: 🔧 设置 Node.js
|
||||
+ - name: 🔧 安装 Node.js 22
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
- node-version: ${{ env.NODE_VERSION }}
|
||||
- registry-url: https://registry.npmmirror.com # 国内加速,不需要可删
|
||||
+ node-version: "22"
|
||||
+ cache: "npm"
|
||||
|
||||
- - name: 🧪 环境校验
|
||||
+ - name: 🧪 安装依赖(npm ci,严格按锁文件)
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
- node -v
|
||||
- npm -v
|
||||
- npm ci --no-audit --no-fund
|
||||
+ # 国内加速镜像(Runner 在国外可以删掉这两行)
|
||||
+ npm config set registry https://registry.npmmirror.com || true
|
||||
+ npm config set fund false
|
||||
+ npm config set audit false
|
||||
+ npm ci
|
||||
|
||||
- - name: 🔐 登录 Gitea 容器仓库
|
||||
- uses: docker/login-action@v3
|
||||
+ - name: 🔎 检查 package.json 没有 pnpm 残留
|
||||
+ run: |
|
||||
+ set -euo pipefail
|
||||
+ if grep -qE '"packageManager"\s*:\s*"pnpm' package.json; then
|
||||
+ echo "❌ package.json 里有 pnpm 包管理器声明,和用户要求冲突"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ echo "✅ package.json 未发现 pnpm 声明"
|
||||
+
|
||||
+ - name: 🏗️ 本地 nuxt build(独立于 Docker 先验证代码是可构建的)
|
||||
+ run: |
|
||||
+ set -euxo pipefail
|
||||
+ NODE_OPTIONS="--max-old-space-size=2048" npm run build
|
||||
+ echo "✅ .output/ 生成成功:"
|
||||
+ ls -la .output/ 2>/dev/null || true
|
||||
+ du -sh .output 2>/dev/null || true
|
||||
+
|
||||
+ # ============================================================
|
||||
+ # Job 2: 构建 Docker 镜像 → 推送到 Gitea 自带容器仓库
|
||||
+ # ============================================================
|
||||
+ build-image:
|
||||
+ name: 构建并推送镜像
|
||||
+ needs: preflight
|
||||
+ runs-on: ubuntu-latest
|
||||
+ timeout-minutes: 40
|
||||
+ outputs:
|
||||
+ image_tag: ${{ steps.meta.outputs.tag }}
|
||||
+ image_full: ${{ steps.meta.outputs.full }}
|
||||
+ image_latest: ${{ steps.meta.outputs.latest }}
|
||||
+ steps:
|
||||
+ - name: 📥 Checkout 代码
|
||||
+ uses: actions/checkout@v4
|
||||
with:
|
||||
- registry: ${{ env.GITEA_REGISTRY }}
|
||||
- username: ${{ gitea.repository_owner }}
|
||||
- password: ${{ secrets.REGISTRY_TOKEN || gitea.token }}
|
||||
+ fetch-depth: 1
|
||||
|
||||
- - name: 🏷️ 生成镜像标签
|
||||
+ - name: 🏷️ 计算镜像 tag(日期 + 短 SHA)
|
||||
id: meta
|
||||
+ shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
- SHORT_SHA="${GITEA_SHA:0:7}"
|
||||
+ SHA="${GITHUB_SHA:-$(git rev-parse HEAD)}"
|
||||
+ SHORT_SHA="${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 多阶段 + 缓存)
|
||||
+ IMG_FULL="${GITEA_HOST}/${GITHUB_REPOSITORY_OWNER}/${IMAGE_NAME}:${DATE_TAG}"
|
||||
+ IMG_LATEST="${GITEA_HOST}/${GITHUB_REPOSITORY_OWNER}/${IMAGE_NAME}:latest"
|
||||
+ echo "tag=${DATE_TAG}" >> "$GITHUB_OUTPUT"
|
||||
+ echo "full=${IMG_FULL}" >> "$GITHUB_OUTPUT"
|
||||
+ echo "latest=${IMG_LATEST}" >> "$GITHUB_OUTPUT"
|
||||
+ echo "======================================"
|
||||
+ echo "🪪 镜像版本 tag : ${DATE_TAG}"
|
||||
+ echo "🪪 镜像完整名 : ${IMG_FULL}"
|
||||
+ echo "🪪 镜像 latest : ${IMG_LATEST}"
|
||||
+ echo "======================================"
|
||||
+
|
||||
+ - name: 🔧 启用 QEMU(跨架构小概率用得到,保险)
|
||||
+ uses: docker/setup-qemu-action@v3
|
||||
+ with:
|
||||
+ platforms: linux/amd64
|
||||
+
|
||||
+ - name: 🔧 启用 Docker Buildx
|
||||
+ uses: docker/setup-buildx-action@v3
|
||||
+ with:
|
||||
+ install: true
|
||||
+
|
||||
+ - name: 🔐 登录 Gitea 容器仓库(Packages)
|
||||
+ uses: docker/login-action@v3
|
||||
+ with:
|
||||
+ registry: ${{ env.GITEA_HOST }}
|
||||
+ # Secrets 里 REGISTRY_USER 没填就默认用触发构建的用户
|
||||
+ username: ${{ secrets.REGISTRY_USER || github.actor }}
|
||||
+ # Secrets 里 REGISTRY_TOKEN 优先,没填就用 Gitea Actions 自动注入的仓库级 token
|
||||
+ password: ${{ secrets.REGISTRY_TOKEN || github.token }}
|
||||
+
|
||||
+ - name: 🐳 构建 & 推送(BuildKit 分层缓存,skip_build_cache=true 时禁用)
|
||||
+ id: build_push
|
||||
uses: docker/build-push-action@v6
|
||||
+ env:
|
||||
+ CACHE_REF: ${{ env.GITEA_HOST }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:buildcache
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
+ platforms: linux/amd64
|
||||
push: true
|
||||
+ provenance: false
|
||||
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
|
||||
+ NODE_ENV=production
|
||||
+ cache-from: ${{ inputs.skip_build_cache == true && '""' || format('type=registry,ref={0}', env.CACHE_REF) }}
|
||||
+ cache-to: ${{ inputs.skip_build_cache == true && '""' || format('type=registry,ref={0},mode=max', env.CACHE_REF) }}
|
||||
labels: |
|
||||
- org.opencontainers.image.source=${{ gitea.server_url }}/${{ gitea.repository }}
|
||||
- org.opencontainers.image.revision=${{ gitea.sha }}
|
||||
+ org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
|
||||
+ org.opencontainers.image.revision=${{ github.sha }}
|
||||
+ org.opencontainers.image.created=${{ github.event.head_commit.timestamp }}
|
||||
+
|
||||
+ - name: 🧮 镜像体积 & 层信息(日志里看一下,避免镜像越来越大)
|
||||
+ run: |
|
||||
+ set -euxo pipefail
|
||||
+ docker pull "${{ steps.meta.outputs.full }}" || true
|
||||
+ docker image inspect "${{ steps.meta.outputs.full }}" --format='{{.Size}}' 2>/dev/null \
|
||||
+ | awk '{printf "✅ 镜像体积:%.2f MB\n", $1/1024/1024}' || true
|
||||
+ docker history --no-trunc "${{ steps.meta.outputs.full }}" 2>/dev/null | head -20 || true
|
||||
|
||||
# ============================================================
|
||||
- # Job 2: SSH 到服务器拉取新镜像并重启
|
||||
+ # Job 3: SSH 到服务器 → 拉新镜像 → 滚动重启
|
||||
# ============================================================
|
||||
deploy:
|
||||
- name: 部署到服务器
|
||||
+ name: 部署到生产服务器
|
||||
needs: build-image
|
||||
- if: ${{ !cancelled() && !failure() && (inputs.deploy_target == true || github.event_name == 'push') }}
|
||||
+ # push 事件默认自动部署;手动触发时看 checkbox
|
||||
+ if: ${{ !cancelled() && !failure() && (github.event_name == 'push' || inputs.deploy_target == true) }}
|
||||
runs-on: ubuntu-latest
|
||||
- environment: production
|
||||
+ timeout-minutes: 25
|
||||
+ environment:
|
||||
+ name: production
|
||||
+ url: ${{ secrets.NUXT_PUBLIC_SITE_URL }}
|
||||
steps:
|
||||
- - name: 🌐 SSH 部署到生产服务器
|
||||
- uses: https://github.com/appleboy/ssh-action@v1.2.0
|
||||
+ - name: ⚠️ 检查部署所需 Secrets 是否都配置了
|
||||
+ shell: bash
|
||||
+ run: |
|
||||
+ set -euo pipefail
|
||||
+ MISSING=()
|
||||
+ [ -n "${{ secrets.DEPLOY_HOST }}" ] || MISSING+=("DEPLOY_HOST")
|
||||
+ [ -n "${{ secrets.DEPLOY_USER }}" ] || MISSING+=("DEPLOY_USER")
|
||||
+ [ -n "${{ secrets.DEPLOY_SSH_KEY }}" ] || MISSING+=("DEPLOY_SSH_KEY")
|
||||
+ if [ ${#MISSING[@]} -gt 0 ]; then
|
||||
+ echo "❌ 缺少以下 Repository Secrets:${MISSING[*]}"
|
||||
+ echo "👉 去 Gitea 仓库 → Settings → Secrets and variables → Actions 里添加"
|
||||
+ exit 1
|
||||
+ fi
|
||||
+ echo "✅ 部署 Secrets 配置完整"
|
||||
+
|
||||
+ - name: 🚀 一键滚动部署(SSH)
|
||||
+ uses: appleboy/ssh-action@v1.2.0
|
||||
with:
|
||||
host: ${{ secrets.DEPLOY_HOST }}
|
||||
+ port: ${{ secrets.DEPLOY_PORT || 22 }}
|
||||
username: ${{ secrets.DEPLOY_USER }}
|
||||
key: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||
- port: ${{ secrets.DEPLOY_PORT || 22 }}
|
||||
- script_stop: true
|
||||
+ # 部署可能慢,给足 30 分钟
|
||||
command_timeout: 30m
|
||||
+ # 出错立刻停,不继续往下跑
|
||||
+ script_stop: true
|
||||
script: |
|
||||
set -euxo pipefail
|
||||
|
||||
- # 1) 首次部署时自动创建目录 & 空的 docker-compose.yml/.env
|
||||
- mkdir -p "${DEPLOY_PATH}"
|
||||
- cd "${DEPLOY_PATH}"
|
||||
+ # ---------- 0. 基本参数 ----------
|
||||
+ IMAGE_NEW="${{ needs.build-image.outputs.image_full }}"
|
||||
+ IMAGE_LATEST="${{ needs.build-image.outputs.image_latest }}"
|
||||
+ DEPLOY_DIR="${DEPLOY_PATH}"
|
||||
+ COMPOSE="docker compose"
|
||||
+
|
||||
+ echo "=============================================="
|
||||
+ echo "🚢 本次部署镜像: ${IMAGE_NEW}"
|
||||
+ echo "🗂️ 部署目录 : ${DEPLOY_DIR}"
|
||||
+ echo "👤 执行用户 : $(whoami)"
|
||||
+ echo "=============================================="
|
||||
|
||||
- # 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
|
||||
+ # ---------- 1. 确保部署目录存在 ----------
|
||||
+ mkdir -p "${DEPLOY_DIR}"
|
||||
+ cd "${DEPLOY_DIR}"
|
||||
|
||||
- # 3) 拉最新镜像
|
||||
- IMAGE_LATEST="${GITEA_REGISTRY}/${GITEA_REPO_OWNER}/${IMAGE_NAME}:latest"
|
||||
- docker pull "$IMAGE_LATEST"
|
||||
+ # ---------- 2. 登录 Gitea 容器仓库(用 pull token,最小权限) ----------
|
||||
+ if [ -n "${{ secrets.REGISTRY_PULL_TOKEN }}" ] && [ -n "${{ secrets.REGISTRY_PULL_USER }}" ]; then
|
||||
+ echo "🔐 使用专用 pull 凭证登录 Gitea Container Registry"
|
||||
+ echo "${{ secrets.REGISTRY_PULL_TOKEN }}" \
|
||||
+ | docker login "${GITEA_HOST}" \
|
||||
+ -u "${{ secrets.REGISTRY_PULL_USER }}" \
|
||||
+ --password-stdin 2>/dev/null || true
|
||||
+ fi
|
||||
+
|
||||
+ # ---------- 3. 先拉镜像(提前下好,后面 up 不会卡) ----------
|
||||
+ echo "⬇️ 开始拉取新镜像 ${IMAGE_NEW} ..."
|
||||
+ docker pull "${IMAGE_NEW}"
|
||||
+ docker tag "${IMAGE_NEW}" "${IMAGE_LATEST}"
|
||||
+ echo "✅ 新镜像拉取完成,并已打 latest tag"
|
||||
|
||||
- # 4) 写一个最小的 docker-compose.override.yml,指向刚拉的镜像
|
||||
- # (避免改动服务器上已配置好的 docker-compose.yml 和 .env)
|
||||
- cat > docker-compose.override.yml <<'YAML'
|
||||
+ # ---------- 4. 生成 / 更新 docker-compose.override.yml ----------
|
||||
+ # 指向新的精确 tag(不是 latest,出问题能快速回滚)
|
||||
+ cat > docker-compose.override.yml <<YAML
|
||||
services:
|
||||
voicehub:
|
||||
- image: __REPLACE_WITH_IMAGE__
|
||||
+ image: ${IMAGE_NEW}
|
||||
YAML
|
||||
- sed -i "s|__REPLACE_WITH_IMAGE__|${IMAGE_LATEST}|g" docker-compose.override.yml
|
||||
+ echo "📝 docker-compose.override.yml 已写入,指定镜像=${IMAGE_NEW}"
|
||||
|
||||
- # 5) 启动(如果没有 docker-compose.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)"
|
||||
+ echo "ℹ️ 未发现 docker-compose.yml,自动从仓库模板下载"
|
||||
+ TEMPLATE_URL="${GITHUB_SERVER_URL:-https://${GITEA_HOST}}/${GITHUB_REPOSITORY:-${GITHUB_REPOSITORY_OWNER}/${IMAGE_NAME}}/raw/branch/${GITHUB_REF_NAME:-main}/docker-compose.yml"
|
||||
+ echo " ↓ URL=${TEMPLATE_URL}"
|
||||
+ curl -fsSL --max-time 30 "${TEMPLATE_URL}" -o docker-compose.yml \
|
||||
+ || (
|
||||
+ echo "⚠️ 自动下载模板失败,跳过(你需要手动上传 docker-compose.yml 和 .env)"
|
||||
+ # 不 exit,因为用户可能已经有一套自定义部署
|
||||
+ )
|
||||
+ fi
|
||||
+
|
||||
+ # ---------- 6. 没有 .env? 给一份占位(方便首次部署发现问题) ----------
|
||||
+ if [ ! -f .env ]; then
|
||||
+ echo "================================================================="
|
||||
+ echo "⚠️ WARNING:${DEPLOY_DIR}/.env 不存在!!!"
|
||||
+ echo "👉 第一次部署请先在服务器上创建 .env(至少填 POSTGRES_PASSWORD / JWT_SECRET / NUXT_PUBLIC_SITE_URL)"
|
||||
+ echo "👉 参考仓库根的 .env.example 或部署文档"
|
||||
+ echo "================================================================="
|
||||
+ # 不退出,因为 compose 会用 environment 默认值尝试启动(只是大概率连不上 DB)
|
||||
fi
|
||||
|
||||
- # 6) 健康拉取 + 滚动重启(先拉好再 up,downtime 最小)
|
||||
- docker compose pull --quiet voicehub 2>/dev/null || true
|
||||
- docker compose up -d --remove-orphans
|
||||
+ # ---------- 7. 滚动启动(如果只有 voicehub 单服务,不会动 postgres/redis) ----------
|
||||
+ echo "🔄 docker compose up -d(只重建变更过的 voicehub)..."
|
||||
+ ${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 "✅ 容器健康"
|
||||
+ # ---------- 8. 等待应用变 healthy,最多 2 分钟 ----------
|
||||
+ MAX_WAIT=24 # 24 × 5s = 2min
|
||||
+ WAITED=0
|
||||
+ echo "⏳ 等待容器 healthcheck 通过(最多 120s)..."
|
||||
+ while [ ${WAITED} -lt ${MAX_WAIT} ]; do
|
||||
+ STATUS="$(${COMPOSE} ps --format json 2>/dev/null || true)"
|
||||
+ if echo "${STATUS}" | grep -q '"Health":"healthy"'; then
|
||||
+ echo "✅ voicehub 容器健康检查通过"
|
||||
break
|
||||
fi
|
||||
+ # 同时也检查是否已经 running 但健康检查还没跑完(防止 healthcheck 写太严误判)
|
||||
+ if echo "${STATUS}" | grep -q '"State":"running"'; then
|
||||
+ :
|
||||
+ else
|
||||
+ # 连 running 都不是 → 直接打印日志末尾 60 行帮忙排错
|
||||
+ echo "⚠️ voicehub 还没 running,当前状态:"
|
||||
+ ${COMPOSE} ps || true
|
||||
+ fi
|
||||
sleep 5
|
||||
+ WAITED=$((WAITED + 1))
|
||||
done
|
||||
+ if [ ${WAITED} -ge ${MAX_WAIT} ]; then
|
||||
+ echo "⚠️ 等待超时,下面是最近 120 行 voicehub 日志:"
|
||||
+ ${COMPOSE} logs --tail=120 voicehub || true
|
||||
+ exit 1
|
||||
+ fi
|
||||
|
||||
- # 8) 清理旧镜像(只留最近 2 个 tag,省磁盘)
|
||||
+ # ---------- 9. 清理旧镜像(保留最近 2 个 tag + latest) ----------
|
||||
+ echo "🧹 清理 3 天前的旧镜像 / 悬空层,防止磁盘爆"
|
||||
docker image prune -af --filter "until=72h" || true
|
||||
+ docker builder prune -af || true
|
||||
|
||||
- echo "🎉 部署完成!镜像=${{ needs.build-image.outputs.image_full }}"
|
||||
+ # ---------- 10. 回滚指引 ----------
|
||||
+ echo ""
|
||||
+ echo "================================================================="
|
||||
+ echo "🎉 部署成功!访问: ${{ secrets.NUXT_PUBLIC_SITE_URL || '请查看你的站点 URL' }}"
|
||||
+ echo "🔁 如需紧急回滚到上一个版本,在服务器执行:"
|
||||
+ echo " cd ${DEPLOY_DIR}"
|
||||
+ echo " # 1) 先看有哪些 tag:"
|
||||
+ echo " docker images | grep ${IMAGE_NAME} | head -5"
|
||||
+ echo " # 2) 选一个老 tag 填到 override:"
|
||||
+ echo " echo 'services:\n voicehub:\n image: ${GITEA_HOST}/${GITHUB_REPOSITORY_OWNER}/${IMAGE_NAME}:<旧TAG>' > docker-compose.override.yml"
|
||||
+ echo " docker compose up -d"
|
||||
+ echo "================================================================="
|
||||
diff --git a/scripts/setup-deploy-user.sh b/scripts/setup-deploy-user.sh
|
||||
new file mode 100644
|
||||
index 0000000..38ac0b1
|
||||
--- /dev/null
|
||||
+++ b/scripts/setup-deploy-user.sh
|
||||
@@ -0,0 +1,159 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# ============================================================================
|
||||
+# setup-deploy-user.sh
|
||||
+# 在「生产服务器」上一键做好 CI 自动部署所需的系统配置:
|
||||
+# 1) 新建 deploy 用户(低权限,禁止密码登录,只能 key 登录)
|
||||
+# 2) 生成 ed25519 SSH 密钥对(私钥你粘去 Gitea Secrets DEPLOY_SSH_KEY)
|
||||
+# 3) 加入 docker 组,允许 docker compose 操作
|
||||
+# 4) 给 /opt/byw-voicehub 目录读写权限(setfacl)
|
||||
+# 5) 打印私钥内容 & 公钥指纹,便于你检查和复制
|
||||
+#
|
||||
+# 用法(在生产服务器上,sudo 运行):
|
||||
+# sudo bash scripts/setup-deploy-user.sh [--deploy-dir /opt/byw-voicehub]
|
||||
+# ============================================================================
|
||||
+set -euo pipefail
|
||||
+
|
||||
+RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[1;36m'; NC='\033[0m'
|
||||
+info(){ echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
+warn(){ echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
+err(){ echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
|
||||
+ok(){ echo -e "${CYAN}[ OK ]${NC} $*"; }
|
||||
+
|
||||
+DEPLOY_DIR="/opt/byw-voicehub"
|
||||
+DEPLOY_USER="deploy"
|
||||
+while [[ $# -gt 0 ]]; do
|
||||
+ case "$1" in
|
||||
+ --deploy-dir) DEPLOY_DIR="$2"; shift 2 ;;
|
||||
+ --user) DEPLOY_USER="$2"; shift 2 ;;
|
||||
+ -h|--help)
|
||||
+ sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//'
|
||||
+ exit 0
|
||||
+ ;;
|
||||
+ *) err "未知参数 $1(--help 查看帮助)" ;;
|
||||
+ esac
|
||||
+done
|
||||
+
|
||||
+[[ $EUID -eq 0 ]] || err "请用 sudo 运行本脚本"
|
||||
+command -v docker >/dev/null 2>&1 || err "先装完 Docker 再跑本脚本(路径一的教程里有)"
|
||||
+command -v setfacl >/dev/null 2>&1 || {
|
||||
+ warn "没装 acl 工具,现在 apt install"
|
||||
+ apt-get update && apt-get install -y acl
|
||||
+}
|
||||
+
|
||||
+# -------- 1. 建用户 --------
|
||||
+if ! id -u "${DEPLOY_USER}" >/dev/null 2>&1; then
|
||||
+ useradd --create-home --shell /usr/bin/bash --disabled-password "${DEPLOY_USER}"
|
||||
+ ok "新建用户:${DEPLOY_USER}(无密码,仅 SSH key 登录)"
|
||||
+else
|
||||
+ info "用户 ${DEPLOY_USER} 已存在,跳过创建"
|
||||
+fi
|
||||
+
|
||||
+# -------- 2. 加入 docker 组 --------
|
||||
+usermod -aG docker "${DEPLOY_USER}"
|
||||
+ok "${DEPLOY_USER} 加入 docker 组(有权限执行 docker compose)"
|
||||
+
|
||||
+# -------- 3. 生成 SSH 密钥(无密码) --------
|
||||
+SSH_DIR="/home/${DEPLOY_USER}/.ssh"
|
||||
+mkdir -p "${SSH_DIR}"
|
||||
+chmod 700 "${SSH_DIR}"
|
||||
+chown "${DEPLOY_USER}:${DEPLOY_USER}" "${SSH_DIR}"
|
||||
+
|
||||
+KEY_PATH="${SSH_DIR}/id_ed25519"
|
||||
+if [[ ! -f "${KEY_PATH}" ]]; then
|
||||
+ sudo -u "${DEPLOY_USER}" ssh-keygen -t ed25519 \
|
||||
+ -C "gitea-actions-deploy-$(hostname)" \
|
||||
+ -f "${KEY_PATH}" \
|
||||
+ -N "" >/dev/null
|
||||
+ ok "SSH ed25519 密钥对生成:${KEY_PATH}"
|
||||
+else
|
||||
+ info "密钥对已存在,跳过生成:${KEY_PATH}"
|
||||
+fi
|
||||
+
|
||||
+# 公钥加入 authorized_keys(允许持对应私钥的人以 deploy 用户 ssh 登录)
|
||||
+AUTH_KEYS="${SSH_DIR}/authorized_keys"
|
||||
+touch "${AUTH_KEYS}"
|
||||
+PUBKEY_CONTENT="$(cat "${KEY_PATH}.pub")"
|
||||
+if ! grep -qF "${PUBKEY_CONTENT}" "${AUTH_KEYS}" 2>/dev/null; then
|
||||
+ echo "${PUBKEY_CONTENT}" >> "${AUTH_KEYS}"
|
||||
+ ok "公钥已写入 authorized_keys"
|
||||
+fi
|
||||
+chmod 600 "${AUTH_KEYS}"
|
||||
+chmod 644 "${KEY_PATH}.pub"
|
||||
+chmod 600 "${KEY_PATH}"
|
||||
+chown -R "${DEPLOY_USER}:${DEPLOY_USER}" "${SSH_DIR}"
|
||||
+
|
||||
+# -------- 4. sshd 加固(只允许公钥登录;别让 root 密码登录;deploy 禁止转发)--------
|
||||
+SSHD_SNIPPET="/etc/ssh/sshd_config.d/99-deploy-user.conf"
|
||||
+if [[ ! -f "${SSHD_SNIPPET}" ]]; then
|
||||
+ mkdir -p /etc/ssh/sshd_config.d
|
||||
+ cat > "${SSHD_SNIPPET}" <<SSHD
|
||||
+# 针对 deploy 用户:仅允许公钥登录,禁用 TCP 转发等
|
||||
+Match User ${DEPLOY_USER}
|
||||
+ PasswordAuthentication no
|
||||
+ PubkeyAuthentication yes
|
||||
+ PermitTTY yes
|
||||
+ AllowTcpForwarding no
|
||||
+ X11Forwarding no
|
||||
+SSHD
|
||||
+ systemctl reload sshd 2>/dev/null || service ssh reload || true
|
||||
+ ok "sshd 配置已加固(deploy 只允许公钥登录,并禁用端口转发)"
|
||||
+fi
|
||||
+
|
||||
+# -------- 5. 创建部署目录并给 deploy 权限 --------
|
||||
+mkdir -p "${DEPLOY_DIR}"
|
||||
+# 既设组权限,又加 ACL,确保后续新建文件也有
|
||||
+setfacl -R -m "u:${DEPLOY_USER}:rwX" "${DEPLOY_DIR}"
|
||||
+setfacl -R -d -m "u:${DEPLOY_USER}:rwX" "${DEPLOY_DIR}"
|
||||
+ok "部署目录 ${DEPLOY_DIR} 已给 ${DEPLOY_USER} 完整读写权限(+ 新建文件继承权限)"
|
||||
+
|
||||
+# 如果目录里有 compose/环境文件,顺便改一下属组,避免「root 建的文件 deploy 改不了」
|
||||
+chgrp -R docker "${DEPLOY_DIR}" 2>/dev/null || true
|
||||
+chmod -R g+rwX "${DEPLOY_DIR}" 2>/dev/null || true
|
||||
+
|
||||
+# -------- 6. 验证 docker 是否真能用(不报错)--------
|
||||
+DOCKER_RC=0
|
||||
+sudo -u "${DEPLOY_USER}" docker ps >/dev/null 2>&1 || DOCKER_RC=$?
|
||||
+if [[ ${DOCKER_RC} -eq 0 ]]; then
|
||||
+ ok "✅ ${DEPLOY_USER} 可以执行 docker 命令"
|
||||
+else
|
||||
+ warn "⚠️ ${DEPLOY_USER} 暂时跑不了 docker(可能需要重新登录一次刷新组),部署时不会有影响(但验证时会再触发一次)"
|
||||
+fi
|
||||
+
|
||||
+# -------- 7. 打印信息 --------
|
||||
+FINGERPRINT="$(ssh-keygen -l -f "${KEY_PATH}.pub" 2>/dev/null || true)"
|
||||
+PUBKEY_CONTENT="$(cat "${KEY_PATH}.pub")"
|
||||
+PRIVATE_CONTENT="$(cat "${KEY_PATH}")"
|
||||
+
|
||||
+clear
|
||||
+echo -e "${GREEN}================================================================================${NC}"
|
||||
+echo -e "${GREEN} 🎉 部署用户 & SSH 密钥 配置完成!${NC}"
|
||||
+echo -e "${GREEN}================================================================================${NC}"
|
||||
+echo -e " 👤 部署用户名 :${CYAN}${DEPLOY_USER}${NC}"
|
||||
+echo -e " 📂 部署目录 :${CYAN}${DEPLOY_DIR}${NC}"
|
||||
+echo -e " 🔑 私钥文件路径 :${CYAN}${KEY_PATH}${NC}"
|
||||
+echo -e " 🧾 公钥指纹 :${FINGERPRINT}"
|
||||
+echo -e " 🧾 公钥内容(方便核对):"
|
||||
+echo -e " ${PUBKEY_CONTENT}"
|
||||
+echo ""
|
||||
+echo -e "${YELLOW}================================================================================${NC}"
|
||||
+echo -e "${YELLOW} ⚠️ 下面这一整段是【私钥】,完整复制(从 BEGIN 到 END 包括两行)到:${NC}"
|
||||
+echo -e "${YELLOW} Gitea 仓库 → Settings → Secrets and variables → Actions → New Secret${NC}"
|
||||
+echo -e "${YELLOW} Name = DEPLOY_SSH_KEY${NC}"
|
||||
+echo -e "${YELLOW} Value = 粘贴下面一整段(包括 -----BEGIN/END-----)${NC}"
|
||||
+echo -e "${YELLOW}================================================================================${NC}"
|
||||
+echo ""
|
||||
+echo "${PRIVATE_CONTENT}"
|
||||
+echo ""
|
||||
+echo -e "${YELLOW}================================================================================${NC}"
|
||||
+echo -e "${YELLOW} ⚠️ 上面就是 DEPLOY_SSH_KEY,不要在任何地方贴到别的文档或聊天。看完 Ctrl+L 清屏。${NC}"
|
||||
+echo -e "${YELLOW}================================================================================${NC}"
|
||||
+echo ""
|
||||
+echo -e "${CYAN}👉 同时你还需要补以下几个 Repository Secrets(都在同一页添加):${NC}"
|
||||
+echo -e " • DEPLOY_HOST = 你的服务器公网 IP 或域名"
|
||||
+echo -e " • DEPLOY_PORT = SSH 端口(一般 22)"
|
||||
+echo -e " • DEPLOY_USER = ${DEPLOY_USER}(就是这个用户名)"
|
||||
+echo -e " • REGISTRY_TOKEN = 你的 Gitea 个人访问令牌(Package 读写权限)"
|
||||
+echo -e " • REGISTRY_PULL_USER = 同 REGISTRY_USER(服务器上拉镜像用,一般和 REGISTRY_USER 一样)"
|
||||
+echo -e " • REGISTRY_PULL_TOKEN= 上面令牌同一个或新建一个仅 pull 权限的更安全"
|
||||
+echo -e " • NUXT_PUBLIC_SITE_URL = https://你的域名.com(用来显示部署成功后的跳转按钮)"
|
||||
+echo ""
|
||||
diff --git a/scripts/setup-runner.sh b/scripts/setup-runner.sh
|
||||
new file mode 100644
|
||||
index 0000000..bc424e7
|
||||
--- /dev/null
|
||||
+++ b/scripts/setup-runner.sh
|
||||
@@ -0,0 +1,211 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# ============================================================================
|
||||
+# setup-runner.sh —— 一键安装并注册 Gitea Actions Runner(act_runner)
|
||||
+#
|
||||
+# 使用方法:
|
||||
+# ① 先在你的 Gitea 仓库页面 → Settings → Actions → Runners → 「Create Runner」
|
||||
+# 选「Linux + amd64」,它会给你一条注册命令,里面有一串 registration token,
|
||||
+# 格式像: GFxxxxxxxxxxxxxxxxxxxx ,复制它。
|
||||
+# ② 再在你要跑 Runner 的机器上执行:
|
||||
+# curl -fsSL https://<你的-gitea>/<仓库>/-/raw/branch/main/scripts/setup-runner.sh \
|
||||
+# | sudo bash -s -- --gitea https://<你的-gitea> --token GFxxxxxxxxxxxxxxxxxxxx
|
||||
+#
|
||||
+# 或者直接本地执行:
|
||||
+# sudo bash scripts/setup-runner.sh \
|
||||
+# --gitea https://git.baoyiwai.com \
|
||||
+# --token GFxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
+# ============================================================================
|
||||
+set -euo pipefail
|
||||
+
|
||||
+# ---------- 颜色 ----------
|
||||
+RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||
+info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
+warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
+err() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
|
||||
+
|
||||
+# ---------- 解析参数 ----------
|
||||
+GITEA_URL=""
|
||||
+REG_TOKEN=""
|
||||
+RUNNER_NAME="runner-$(hostname | tr '[:upper:]' '[:lower:]')"
|
||||
+RUNNER_USER="gitrunner"
|
||||
+INSTALL_DIR="/opt/act_runner"
|
||||
+
|
||||
+while [[ $# -gt 0 ]]; do
|
||||
+ case "$1" in
|
||||
+ --gitea) GITEA_URL="${2}"; shift 2 ;;
|
||||
+ --token) REG_TOKEN="${2}"; shift 2 ;;
|
||||
+ --name) RUNNER_NAME="${2}"; shift 2 ;;
|
||||
+ --user) RUNNER_USER="${2}"; shift 2 ;;
|
||||
+ --dir) INSTALL_DIR="${2}"; shift 2 ;;
|
||||
+ -h|--help)
|
||||
+ sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'
|
||||
+ exit 0
|
||||
+ ;;
|
||||
+ *) err "未知参数:$1(--help 查看帮助)" ;;
|
||||
+ esac
|
||||
+done
|
||||
+
|
||||
+[[ -n "${GITEA_URL}" ]] || err "必须传 --gitea https://你的-gitea-地址"
|
||||
+[[ -n "${REG_TOKEN}" ]] || err "必须传 --token GF……(Gitea 页面里拿的注册 token)"
|
||||
+[[ $EUID -eq 0 ]] || err "请用 sudo 运行本脚本(需要写 /opt / /etc/systemd/system)"
|
||||
+
|
||||
+# 去掉末尾 /
|
||||
+GITEA_URL="${GITEA_URL%/}"
|
||||
+
|
||||
+# ---------- 0. 架构检测 ----------
|
||||
+ARCH="$(uname -m)"
|
||||
+case "${ARCH}" in
|
||||
+ x86_64|amd64) PLATFORM="linux-amd64" ;;
|
||||
+ aarch64|arm64) PLATFORM="linux-arm64" ;;
|
||||
+ armv7l) PLATFORM="linux-arm" ;;
|
||||
+ *) err "暂不支持的架构:${ARCH}(需要 x86_64 / aarch64 / armv7)" ;;
|
||||
+esac
|
||||
+info "检测到架构:${ARCH} → 下载版本:${PLATFORM}"
|
||||
+
|
||||
+# ---------- 1. 安装依赖:docker(Runner 要用 Docker-in-Docker 执行 buildx 等)----------
|
||||
+if ! command -v docker >/dev/null 2>&1; then
|
||||
+ info "检测到没装 Docker,现在用官方一键脚本安装(国内自动换清华源)..."
|
||||
+ curl -fsSL https://get.docker.com -o /tmp/get-docker.sh || err "下载 docker-install 脚本失败"
|
||||
+ if curl -sI https://mirrors.tuna.tsinghua.edu.cn >/dev/null; then
|
||||
+ bash /tmp/get-docker.sh --mirror Aliyun || bash /tmp/get-docker.sh
|
||||
+ else
|
||||
+ bash /tmp/get-docker.sh
|
||||
+ fi
|
||||
+ systemctl enable --now docker
|
||||
+ info "✅ Docker 安装完成:$(docker --version)"
|
||||
+else
|
||||
+ info "✅ Docker 已存在:$(docker --version)"
|
||||
+fi
|
||||
+
|
||||
+# ---------- 2. 建运行用户 gitrunner,加入 docker 组 ----------
|
||||
+if ! id -u "${RUNNER_USER}" >/dev/null 2>&1; then
|
||||
+ useradd -r -s /usr/sbin/nologin -d "${INSTALL_DIR}" "${RUNNER_USER}"
|
||||
+ info "✅ 新建系统用户 ${RUNNER_USER}"
|
||||
+else
|
||||
+ info "ℹ️ 用户 ${RUNNER_USER} 已存在,跳过创建"
|
||||
+fi
|
||||
+usermod -aG docker "${RUNNER_USER}"
|
||||
+info "✅ 把 ${RUNNER_USER} 加入 docker 组(允许操作 Docker daemon)"
|
||||
+
|
||||
+mkdir -p "${INSTALL_DIR}"
|
||||
+chown -R "${RUNNER_USER}:${RUNNER_USER}" "${INSTALL_DIR}"
|
||||
+
|
||||
+# ---------- 3. 下载最新 act_runner ----------
|
||||
+info "⬇️ 正在拉取 act_runner 最新 release 元数据..."
|
||||
+LATEST_JSON="$(curl -fsSL https://gitea.com/api/v1/repos/gitea/act_runner/releases/latest || true)"
|
||||
+if [[ -z "${LATEST_JSON}" ]]; then
|
||||
+ warn "gitea.com 不通,改用硬编码版本 0.2.10(你之后可手动升级)"
|
||||
+ VERSION="0.2.10"
|
||||
+else
|
||||
+ VERSION="$(echo "${LATEST_JSON}" | grep -oE '"tag_name":\s*"[^"]+"' | head -1 | cut -d'"' -f4 | sed 's/^v//')"
|
||||
+ [[ -n "${VERSION}" ]] || VERSION="0.2.10"
|
||||
+fi
|
||||
+BIN_URL="https://dl.gitea.com/act_runner/${VERSION}/act_runner-${VERSION}-${PLATFORM}"
|
||||
+info "⬇️ 下载 act_runner v${VERSION}:${BIN_URL}"
|
||||
+curl -fsSL "${BIN_URL}" -o /usr/local/bin/act_runner \
|
||||
+ || err "下载失败。请手动打开 ${BIN_URL} 看是否 404,然后换个版本"
|
||||
+chmod +x /usr/local/bin/act_runner
|
||||
+info "✅ act_runner 已安装到 /usr/local/bin,版本:$(act_runner --version 2>&1 || true)"
|
||||
+
|
||||
+# ---------- 4. 注册 Runner ----------
|
||||
+cd "${INSTALL_DIR}"
|
||||
+info "🔗 开始注册 Runner 到 ${GITEA_URL}(名称:${RUNNER_NAME})"
|
||||
+
|
||||
+# 切到 gitrunner 用户注册,避免 root 跑(安全)
|
||||
+rm -f .runner 2>/dev/null || true
|
||||
+sudo -u "${RUNNER_USER}" env HOME="${INSTALL_DIR}" \
|
||||
+ act_runner register \
|
||||
+ --instance "${GITEA_URL}" \
|
||||
+ --token "${REG_TOKEN}" \
|
||||
+ --name "${RUNNER_NAME}" \
|
||||
+ --labels "ubuntu-latest:docker://catthehacker/ubuntu:act-22.04" \
|
||||
+ --no-interactive \
|
||||
+ || err "注册失败!常见原因:\n 1) token 不对(复制时别带空格)\n 2) Runner 机器出不了网到 ${GITEA_URL}\n 3) Gitea 站点时间和这台机器差太远(证书验证失败)"
|
||||
+
|
||||
+chown "${RUNNER_USER}:${RUNNER_USER}" .runner 2>/dev/null || true
|
||||
+
|
||||
+# ---------- 5. 生成配置文件(建议开启 docker.host 特权)----------
|
||||
+CONFIG_FILE="${INSTALL_DIR}/config.yaml"
|
||||
+if [[ ! -f "${CONFIG_FILE}" ]]; then
|
||||
+ cat > "${CONFIG_FILE}" <<'YAML'
|
||||
+log:
|
||||
+ level: info
|
||||
+runner:
|
||||
+ file: .runner
|
||||
+ capacity: 2 # 同一台 Runner 最多同时跑 2 个 Job
|
||||
+ envs:
|
||||
+ GOPROXY: https://goproxy.cn,direct
|
||||
+ NPM_CONFIG_REGISTRY: https://registry.npmmirror.com
|
||||
+ timeout: 3h
|
||||
+cache:
|
||||
+ enabled: true
|
||||
+ dir: /opt/act_runner/cache
|
||||
+container:
|
||||
+ network: "bridge"
|
||||
+ privileged: true # build-push-action 用到 Docker daemon
|
||||
+ options: |
|
||||
+ --add-host "host.docker.internal:host-gateway"
|
||||
+YAML
|
||||
+ chown "${RUNNER_USER}:${RUNNER_USER}" "${CONFIG_FILE}"
|
||||
+ mkdir -p "${INSTALL_DIR}/cache"
|
||||
+ chown -R "${RUNNER_USER}:${RUNNER_USER}" "${INSTALL_DIR}/cache"
|
||||
+ info "✅ 默认 config 写入 ${CONFIG_FILE}"
|
||||
+fi
|
||||
+
|
||||
+# ---------- 6. 写 systemd 服务,开机自启 ----------
|
||||
+UNIT_FILE="/etc/systemd/system/gitea-act-runner.service"
|
||||
+cat > "${UNIT_FILE}" <<SYSTEMD
|
||||
+[Unit]
|
||||
+Description=Gitea Actions Runner (${RUNNER_NAME})
|
||||
+After=network.target docker.service
|
||||
+Requires=docker.service
|
||||
+
|
||||
+[Service]
|
||||
+Type=simple
|
||||
+User=${RUNNER_USER}
|
||||
+Group=${RUNNER_USER}
|
||||
+WorkingDirectory=${INSTALL_DIR}
|
||||
+Environment=HOME=${INSTALL_DIR}
|
||||
+ExecStart=/usr/local/bin/act_runner daemon --config ${CONFIG_FILE}
|
||||
+Restart=always
|
||||
+RestartSec=5
|
||||
+KillMode=mixed
|
||||
+TimeoutStopSec=30
|
||||
+
|
||||
+# 安全加固
|
||||
+NoNewPrivileges=true
|
||||
+PrivateTmp=true
|
||||
+ProtectSystem=strict
|
||||
+ReadWritePaths=${INSTALL_DIR} /var/run/docker.sock /tmp /var/tmp
|
||||
+
|
||||
+[Install]
|
||||
+WantedBy=multi-user.target
|
||||
+SYSTEMD
|
||||
+
|
||||
+systemctl daemon-reload
|
||||
+systemctl enable --now gitea-act-runner
|
||||
+info "✅ systemd 服务已写入并启动:${UNIT_FILE}"
|
||||
+
|
||||
+sleep 3 # 给 daemon 点时间注册
|
||||
+info "📌 当前 Runner 状态:"
|
||||
+systemctl --no-pager status gitea-act-runner | head -15 || true
|
||||
+info "📌 最近 30 行日志(验证 OK):"
|
||||
+journalctl --no-pager -u gitea-act-runner --since "2 minutes ago" -n 30 || true
|
||||
+
|
||||
+echo ""
|
||||
+echo -e "${GREEN}===========================================================================${NC}"
|
||||
+echo -e "${GREEN} 🎉 Gitea Actions Runner 安装 & 注册 & 开机自启 全部完成!${NC}"
|
||||
+echo -e "${GREEN}===========================================================================${NC}"
|
||||
+echo " ✅ Runner 名称 : ${RUNNER_NAME}"
|
||||
+echo " ✅ 运行用户 : ${RUNNER_USER}"
|
||||
+echo " ✅ 安装目录 : ${INSTALL_DIR}"
|
||||
+echo " ✅ 绑定 Gitea : ${GITEA_URL}"
|
||||
+echo ""
|
||||
+echo " 👉 下一步验证(建议立刻做):"
|
||||
+echo " 1. 浏览器打开:${GITEA_URL} → 仓库 → Settings → Actions → Runners"
|
||||
+echo " 应该能看到一个 Runner,状态 = Idle"
|
||||
+echo " 2. 回到终端,模拟跑一个 workflow 没问题就彻底大功告成!"
|
||||
+echo " 👉 常用命令:"
|
||||
+echo " systemctl {start|stop|restart|status} gitea-act-runner"
|
||||
+echo " journalctl -u gitea-act-runner -f # 实时看日志"
|
||||
+echo ""
|
||||
--
|
||||
2.45.1.windows.1
|
||||
|
||||
Reference in New Issue
Block a user