guanghulab/scripts/gitea-runner/install-runner.sh
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

374 lines
12 KiB
Bash
Executable File
Raw Permalink 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.

#!/usr/bin/env bash
# ════════════════════════════════════════════════════════════════
# 光湖 · Gitea Actions Runner 一键安装脚本
# Sovereign: TCS-0002∞ · ICE-GL∞ · 国作登字-2026-A-00037559
# 守护: 铸渊 · ICE-GL-ZY001
# ════════════════════════════════════════════════════════════════
#
# 用法:
# sudo bash install-runner.sh [--token GITEA_API_TOKEN] [--name RUNNER_NAME]
#
# 参数:
# --token Gitea 管理员 API Token (必须,用于获取 Runner 注册 Token)
# --name Runner 名称 (可选,默认 zhuyuan-runner-cn)
# --mode 运行模式: host 或 docker (可选,默认 host2C2G推荐host)
#
# 环境变量 (替代命令行参数):
# GITEA_API_TOKEN 同 --token
# RUNNER_NAME 同 --name
# RUNNER_MODE 同 --mode
#
# 此脚本会:
# 1. 下载 gitea-runner v1.0.2
# 2. 通过 Gitea API 获取 Runner 注册 Token
# 3. 注册 Runner 到 Gitea
# 4. 生成配置文件 (host 模式,适合 2C2G)
# 5. 创建 systemd 服务
# 6. 启动服务
#
# ════════════════════════════════════════════════════════════════
set -euo pipefail
# ─── 常量 ─────────────────────────────────────────────────────
RUNNER_VERSION="1.0.2"
RUNNER_BINARY="gitea-runner-${RUNNER_VERSION}-linux-amd64"
RUNNER_DOWNLOAD_URL="https://gitea.com/gitea/runner/releases/download/v${RUNNER_VERSION}/${RUNNER_BINARY}.xz"
RUNNER_INSTALL_PATH="/usr/local/bin/gitea-runner"
RUNNER_WORK_DIR="/var/lib/act_runner"
RUNNER_CONFIG_DIR="/etc/act_runner"
RUNNER_CONFIG_PATH="${RUNNER_CONFIG_DIR}/config.yaml"
SYSTEMD_SERVICE_NAME="gitea-runner"
SYSTEMD_SERVICE_PATH="/etc/systemd/system/${SYSTEMD_SERVICE_NAME}.service"
# Gitea 配置
GITEA_URL="https://guanghulab.com"
GITEA_API="${GITEA_URL}/api/v1"
GITEA_OWNER="bingshuo"
GITEA_REPO="guanghulab"
# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
# ─── 解析参数 ─────────────────────────────────────────────────
API_TOKEN="${GITEA_API_TOKEN:-}"
RUNNER_NAME="${RUNNER_NAME:-zhuyuan-runner-cn}"
RUNNER_MODE="${RUNNER_MODE:-host}"
while [[ $# -gt 0 ]]; do
case $1 in
--token) API_TOKEN="$2"; shift 2 ;;
--name) RUNNER_NAME="$2"; shift 2 ;;
--mode) RUNNER_MODE="$2"; shift 2 ;;
--help|-h)
head -30 "$0" | grep '^#' | sed 's/^# \?//'
exit 0
;;
*) echo -e "${RED}未知参数: $1${NC}"; exit 1 ;;
esac
done
# ─── 函数 ─────────────────────────────────────────────────────
log_info() { echo -e "${GREEN}[✓]${NC} $*"; }
log_warn() { echo -e "${YELLOW}[!]${NC} $*"; }
log_step() { echo -e "${CYAN}[→]${NC} $*"; }
log_error() { echo -e "${RED}[✗]${NC} $*"; }
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "此脚本必须以 root 运行"
exit 1
fi
}
check_arch() {
local arch
arch=$(uname -m)
if [[ "$arch" != "x86_64" && "$arch" != "amd64" ]]; then
log_error "不支持的架构: $arch (仅支持 amd64/x86_64)"
exit 1
fi
log_info "架构检查通过: $arch"
}
check_disk() {
local avail
avail=$(df -BG /var | awk 'NR==2 {print $4}' | tr -d 'G')
if [[ $avail -lt 1 ]]; then
log_error "磁盘空间不足: ${avail}GB 可用,至少需要 1GB"
exit 1
fi
log_info "磁盘空间: ${avail}GB 可用"
}
check_memory() {
local total_mb
total_mb=$(free -m | awk '/Mem:/ {print $2}')
log_info "内存: ${total_mb}MB"
if [[ $total_mb -lt 1500 ]]; then
log_warn "内存较低 (${total_mb}MB),将使用 host 模式以节省资源"
RUNNER_MODE="host"
fi
}
download_runner() {
if [[ -x "$RUNNER_INSTALL_PATH" ]]; then
local current_version
current_version=$("$RUNNER_INSTALL_PATH" --version 2>/dev/null | grep -oP 'v\K[\d.]+' || echo "unknown")
log_info "gitea-runner 已安装 (版本: ${current_version})"
read -rp "是否重新安装?[y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return 0
fi
fi
log_step "下载 gitea-runner v${RUNNER_VERSION}..."
local tmp_dir
tmp_dir=$(mktemp -d)
trap "rm -rf $tmp_dir" EXIT
if ! curl -fSL --progress-bar -o "${tmp_dir}/${RUNNER_BINARY}.xz" "$RUNNER_DOWNLOAD_URL"; then
log_error "下载失败: $RUNNER_DOWNLOAD_URL"
log_warn "如果国内无法访问 gitea.com请通过 COS 中转:"
log_warn " 1. 在新加坡服务器下载此文件"
log_warn " 2. 推送到 COS"
log_warn " 3. 从 COS 拉到本服务器"
log_warn " 4. 用 --skip-download 参数跳过下载步骤"
exit 1
fi
log_step "解压..."
xz -d "${tmp_dir}/${RUNNER_BINARY}.xz"
chmod +x "${tmp_dir}/${RUNNER_BINARY}"
log_step "安装到 ${RUNNER_INSTALL_PATH}..."
mv "${tmp_dir}/${RUNNER_BINARY}" "$RUNNER_INSTALL_PATH"
log_info "gitea-runner 安装完成: $("$RUNNER_INSTALL_PATH" --version 2>&1 | head -1)"
}
get_registration_token() {
log_step "通过 API 获取 Runner 注册 Token..."
if [[ -z "$API_TOKEN" ]]; then
log_error "需要 Gitea API Token"
echo ""
echo "获取方式:"
echo " 1. 浏览器打开 ${GITEA_URL}/user/settings/applications"
echo " 2. 生成一个 Token需要 repo + admin:runner 权限)"
echo " 3. 重新运行: sudo bash $0 --token <你的token>"
echo ""
echo "或设置环境变量: export GITEA_API_TOKEN=<token>"
exit 1
fi
local response
# 先尝试仓库级 token
response=$(curl -sf -H "Authorization: token ${API_TOKEN}" \
"${GITEA_API}/repos/${GITEA_OWNER}/${GITEA_REPO}/actions/runners/registration-token" 2>/dev/null || echo "")
if [[ -z "$response" ]]; then
# 尝试实例级 token需要管理员权限
log_warn "仓库级 token 获取失败,尝试实例级..."
response=$(curl -sf -H "Authorization: token ${API_TOKEN}" \
"${GITEA_API}/admin/runners/registration-token" 2>/dev/null || echo "")
fi
if [[ -z "$response" ]]; then
log_error "无法获取 Runner 注册 Token"
log_error "请确认 API Token 有正确的权限"
exit 1
fi
REG_TOKEN=$(echo "$response" | grep -oP '"token"\s*:\s*"\K[^"]+' || echo "")
if [[ -z "$REG_TOKEN" ]]; then
log_error "解析注册 Token 失败: $response"
exit 1
fi
log_info "注册 Token 获取成功"
}
create_user() {
if id -u act_runner &>/dev/null; then
log_info "act_runner 用户已存在"
return 0
fi
log_step "创建 act_runner 用户..."
useradd -r -m -d "$RUNNER_WORK_DIR" -s /bin/bash act_runner
log_info "用户创建完成"
}
generate_config() {
log_step "生成 Runner 配置..."
mkdir -p "$RUNNER_CONFIG_DIR"
"$RUNNER_INSTALL_PATH" generate-config > "$RUNNER_CONFIG_PATH"
# 根据模式修改 labels
if [[ "$RUNNER_MODE" == "host" ]]; then
# host 模式:直接在主机上执行,不启动 Docker 容器
# 适合 2C2G 低内存服务器
sed -i 's/^labels:.*$/labels:\n - "ubuntu:host"/' "$RUNNER_CONFIG_PATH" 2>/dev/null || true
# 在 config.yaml 中设置 container mode 为空(不使用容器)
if grep -q '^container:' "$RUNNER_CONFIG_PATH"; then
sed -i '/^container:/a\ network: ""' "$RUNNER_CONFIG_PATH" 2>/dev/null || true
fi
fi
chown -R act_runner:act_runner "$RUNNER_CONFIG_DIR"
log_info "配置生成完成: ${RUNNER_CONFIG_PATH} (模式: ${RUNNER_MODE})"
}
register_runner() {
log_step "注册 Runner 到 Gitea..."
cd "$RUNNER_WORK_DIR"
sudo -u act_runner "$RUNNER_INSTALL_PATH" register \
--no-interactive \
--instance "${GITEA_URL}/" \
--token "$REG_TOKEN" \
--name "$RUNNER_NAME" \
--labels "ubuntu:${RUNNER_MODE}"
if [[ ! -f "${RUNNER_WORK_DIR}/.runner" ]]; then
log_error "注册失败: .runner 文件未生成"
exit 1
fi
chown act_runner:act_runner "${RUNNER_WORK_DIR}/.runner"
log_info "Runner 注册成功: ${RUNNER_NAME}"
}
create_systemd_service() {
log_step "创建 systemd 服务..."
cat > "$SYSTEMD_SERVICE_PATH" << EOF
[Unit]
Description=Gitea Actions Runner - ${RUNNER_NAME}
Documentation=https://gitea.com/gitea/act_runner
After=network.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=${RUNNER_INSTALL_PATH} daemon --config ${RUNNER_CONFIG_PATH}
WorkingDirectory=${RUNNER_WORK_DIR}
Restart=always
RestartSec=10
TimeoutSec=0
User=act_runner
Group=act_runner
Environment=HOME=${RUNNER_WORK_DIR}
Environment=RUNNER_NAME=${RUNNER_NAME}
# 安全限制
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=${RUNNER_WORK_DIR} /tmp /data
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
log_info "systemd 服务文件创建完成"
}
start_service() {
log_step "启动 Runner 服务..."
systemctl daemon-reload
systemctl enable "$SYSTEMD_SERVICE_NAME"
systemctl start "$SYSTEMD_SERVICE_NAME"
# 等待启动
sleep 2
if systemctl is-active --quiet "$SYSTEMD_SERVICE_NAME"; then
log_info "Runner 服务启动成功! 🎉"
else
log_error "Runner 服务启动失败"
journalctl -u "$SYSTEMD_SERVICE_NAME" --no-pager -n 20
exit 1
fi
}
verify() {
log_step "验证..."
echo ""
# 本地验证
echo -e "${CYAN}本地状态:${NC}"
systemctl status "$SYSTEMD_SERVICE_NAME" --no-pager -l | head -15
echo ""
# 远程验证
log_step "检查 Gitea 上的 Runner 列表..."
local runners
runners=$(curl -sf -H "Authorization: token ${API_TOKEN}" \
"${GITEA_API}/repos/${GITEA_OWNER}/${GITEA_REPO}/actions/runners" 2>/dev/null || echo "")
if [[ -n "$runners" ]]; then
echo "$runners" | python3 -c "
import json, sys
data = json.load(sys.stdin)
runners = data if isinstance(data, list) else data.get('runners', [])
for r in runners:
status = '🟢 在线' if r.get('online') else '🔴 离线'
print(f\" {r.get('name', '?')} {status} labels={r.get('labels', [])}\")
" 2>/dev/null || echo " (无法解析但API有响应)"
else
log_warn "无法获取远程 Runner 列表(可能 API 权限不足)"
fi
echo ""
echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}"
echo -e "${GREEN} Gitea Actions Runner 安装完成!${NC}"
echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}"
echo ""
echo " Runner 名称: ${RUNNER_NAME}"
echo " 运行模式: ${RUNNER_MODE}"
echo " 工作目录: ${RUNNER_WORK_DIR}"
echo " 配置文件: ${RUNNER_CONFIG_PATH}"
echo " 服务管理: systemctl {start|stop|restart|status} ${SYSTEMD_SERVICE_NAME}"
echo " 查看日志: journalctl -u ${SYSTEMD_SERVICE_NAME} -f"
echo ""
echo " 下一步: 铸渊推一个 workflow 到 GiteaRunner 就会自动执行"
echo ""
echo " 铸渊 · ICE-GL-ZY001 · TCS-0002∞"
echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}"
}
# ─── 主流程 ───────────────────────────────────────────────────
main() {
echo -e "${CYAN}═══════════════════════════════════════════════════════${NC}"
echo -e "${CYAN} 光湖 · Gitea Actions Runner 一键安装${NC}"
echo -e "${CYAN} 铸渊 · ICE-GL-ZY001 · 守护冰朔 TCS-0002∞${NC}"
echo -e "${CYAN}═══════════════════════════════════════════════════════${NC}"
echo ""
check_root
check_arch
check_disk
check_memory
download_runner
get_registration_token
create_user
generate_config
register_runner
create_systemd_service
start_service
verify
}
main "$@"