ci: 新增 Gitea Actions 部署流水线 + Runner/Deploy 一键脚本
This commit is contained in:
@@ -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 ""
|
||||
@@ -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 ""
|
||||
Reference in New Issue
Block a user