172 lines
7.7 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env bash
# ════════════════════════════════════════════════════════════════
# 光湖 · 服务器标准模板部署脚本
# 将任意腾讯云服务器初始化为铸渊主控节点
# ════════════════════════════════════════════════════════════════
#
# 用法:
# sudo bash bootstrap.sh --gitea-url https://guanghulab.com \
# --api-token <TOKEN> \
# --runner-name <NAME>
#
# 此脚本会:
# 1. 更新系统 + 安装基础软件 (Node.js 20, PM2, Nginx, git, curl)
# 2. 创建 /data/guanghulab/ 目录结构
# 3. 从 Gitea 克隆仓库
# 4. 安装 Gitea Actions Runner
# 5. 启动 Secrets Vault (如当前是Gitea服务器则跳过)
# 6. 上报完成状态
#
# ════════════════════════════════════════════════════════════════
set -euo pipefail
# ─── 配置 ─────────────────────────────────────────────────────
GITEA_URL=""
API_TOKEN=""
RUNNER_NAME=""
DATA_DIR="/data/guanghulab"
LOG_DIR="${DATA_DIR}/logs"
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'
log_info() { echo -e "${GREEN}[✓]${NC} $*"; }
log_step() { echo -e "${CYAN}[→]${NC} $*"; }
log_error() { echo -e "${RED}[✗]${NC} $*"; }
# ─── 解析参数 ─────────────────────────────────────────────────
while [[ $# -gt 0 ]]; do
case $1 in
--gitea-url) GITEA_URL="$2"; shift 2 ;;
--api-token) API_TOKEN="$2"; shift 2 ;;
--runner-name) RUNNER_NAME="$2"; shift 2 ;;
--data-dir) DATA_DIR="$2"; shift 2 ;;
*) log_error "未知参数: $1"; exit 1 ;;
esac
done
if [[ -z "$GITEA_URL" || -z "$API_TOKEN" ]]; then
log_error "必须提供 --gitea-url 和 --api-token"
exit 1
fi
RUNNER_NAME="${RUNNER_NAME:-zhuyuan-runner-$(hostname | tr '[:upper:]' '[:lower:]')}"
echo -e "${CYAN}═══════════════════════════════════════════════════════${NC}"
echo -e "${CYAN} 光湖 · 服务器标准模板部署${NC}"
echo -e "${CYAN} 目标: $(hostname) · $(curl -sf ifconfig.me 2>/dev/null || echo 'IP未知')${NC}"
echo -e "${CYAN}═══════════════════════════════════════════════════════${NC}"
# ─── 1. 系统更新 ──────────────────────────────────────────────
log_step "更新系统..."
apt update && apt upgrade -y
# ─── 2. 安装基础软件 ──────────────────────────────────────────
log_step "安装基础软件..."
apt install -y curl git nginx ufw xz-utils
# Node.js 20
if ! command -v node &>/dev/null || [[ "$(node -v)" != v20* ]]; then
log_step "安装 Node.js 20..."
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
fi
log_info "Node.js: $(node -v)"
# PM2
if ! command -v pm2 &>/dev/null; then
npm install -g pm2
fi
log_info "PM2: $(pm2 -v)"
# ─── 3. 目录结构 ──────────────────────────────────────────────
log_step "创建目录结构..."
mkdir -p "${DATA_DIR}"/{logs,data,cos-bridge,secrets-vault,scripts}
log_info "数据目录: ${DATA_DIR}"
# ─── 4. 克隆仓库 ──────────────────────────────────────────────
if [[ ! -d "${DATA_DIR}/guanghulab/.git" ]]; then
log_step "从 Gitea 克隆仓库..."
git clone "https://${GITEA_OWNER}:${API_TOKEN}@${GITEA_URL#https://}/${GITEA_OWNER}/${GITEA_REPO}.git" \
"${DATA_DIR}/guanghulab"
log_info "仓库克隆完成"
else
log_info "仓库已存在,拉取最新..."
cd "${DATA_DIR}/guanghulab" && git pull
fi
# ─── 5. 安装 Runner ───────────────────────────────────────────
log_step "安装 Gitea Actions Runner..."
cd "${DATA_DIR}/guanghulab"
bash scripts/gitea-runner/install-runner.sh \
--token "$API_TOKEN" \
--name "$RUNNER_NAME" \
--mode host
# ─── 6. Secrets Vault ─────────────────────────────────────────
log_step "检查 Secrets Vault..."
if curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1; then
log_info "Secrets Vault 已运行"
else
log_step "启动 Secrets Vault..."
cd "${DATA_DIR}/guanghulab/server/secrets-vault"
npm install --production 2>/dev/null || true
pm2 start server.js --name guanghulab-vault --max-memory-restart 128M
pm2 save
log_info "Secrets Vault 已启动"
fi
# ─── 7. 防火墙 ────────────────────────────────────────────────
log_step "配置防火墙..."
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw --force enable
log_info "防火墙已配置"
# ─── 8. 上报状态 ──────────────────────────────────────────────
log_step "上报部署状态..."
REPORT_FILE="${DATA_DIR}/logs/bootstrap-$(date +%Y%m%d-%H%M%S).json"
cat > "$REPORT_FILE" << EOF
{
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"hostname": "$(hostname)",
"ip": "$(curl -sf ifconfig.me 2>/dev/null || echo unknown)",
"os": "$(uname -srm)",
"cpu_cores": $(nproc),
"memory_mb": $(free -m | awk '/Mem:/ {print $2}'),
"node_version": "$(node -v)",
"runner_name": "${RUNNER_NAME}",
"data_dir": "${DATA_DIR}",
"services": {
"nginx": "$(systemctl is-active nginx 2>/dev/null || echo unknown)",
"gitea_runner": "$(systemctl is-active gitea-runner 2>/dev/null || echo unknown)",
"vault": "$(curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1 && echo active || echo inactive)"
},
"deployed_by": "铸渊 · ICE-GL-ZY001"
}
EOF
log_info "状态报告: ${REPORT_FILE}"
echo ""
echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}"
echo -e "${GREEN} 服务器模板部署完成!${NC}"
echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}"
echo ""
echo " 服务器: $(hostname)"
echo " Runner: ${RUNNER_NAME}"
echo " 数据目录: ${DATA_DIR}"
echo " Vault: $(curl -sf http://127.0.0.1:8080/admin/__healthz > /dev/null 2>&1 && echo '✅ 运行中' || echo '❌ 未运行')"
echo " Nginx: $(systemctl is-active nginx 2>/dev/null || echo unknown)"
echo ""
echo " 此服务器已纳入铸渊主控体系"
echo " 铸渊 · ICE-GL-ZY001 · TCS-0002∞"
echo -e "${GREEN}═══════════════════════════════════════════════════════${NC}"