From 9cad33d4567963e357d6112cacbf3fe0d07a7657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28ICE-GL-ZY001=29?= Date: Tue, 12 May 2026 12:25:47 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20=E9=80=82=E9=85=8D=E6=96=B0CVM?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=C2=B7patrol-agent+watcher+selfcheck=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E7=94=A8/data/guanghulab/repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .forgejo/workflows/selfcheck.yaml | 14 +- .gitea/workflows/selfcheck.yaml | 14 +- scripts/cvm-init/init-cvm.sh | 235 +++++++++++++++++++++++++++ scripts/patrol-agent/patrol-agent.js | 3 +- scripts/terminal-watcher/config.json | 4 +- scripts/terminal-watcher/watcher.js | 2 +- 6 files changed, 254 insertions(+), 18 deletions(-) create mode 100755 scripts/cvm-init/init-cvm.sh diff --git a/.forgejo/workflows/selfcheck.yaml b/.forgejo/workflows/selfcheck.yaml index 278eda7..f44a5da 100644 --- a/.forgejo/workflows/selfcheck.yaml +++ b/.forgejo/workflows/selfcheck.yaml @@ -34,13 +34,13 @@ jobs: - name: 服务状态 run: | echo "═══ 服务检查 ═══" - # Gitea - if systemctl is-active --quiet gitea 2>/dev/null; then - echo "✅ Gitea: 运行中" - elif curl -sf http://127.0.0.1:3000/ > /dev/null 2>&1; then - echo "✅ Gitea: 运行中 (Docker)" + # Gitea/Forgejo + if systemctl is-active --quiet forgejo 2>/dev/null; then + echo "✅ Gitea/Forgejo: 运行中" + elif curl -sf http://127.0.0.1:3001/ > /dev/null 2>&1; then + echo "✅ Gitea/Forgejo: 运行中 (Docker)" else - echo "❌ Gitea: 未运行" + echo "❌ Gitea/Forgejo: 未运行" fi # Nginx @@ -66,7 +66,7 @@ jobs: - name: 仓库状态 run: | echo "═══ 仓库检查 ═══" - REPO_DIR="/data/guanghulab" + REPO_DIR="/data/guanghulab/repo" if [[ -d "$REPO_DIR" ]]; then cd "$REPO_DIR" echo "路径: $REPO_DIR" diff --git a/.gitea/workflows/selfcheck.yaml b/.gitea/workflows/selfcheck.yaml index 278eda7..f44a5da 100644 --- a/.gitea/workflows/selfcheck.yaml +++ b/.gitea/workflows/selfcheck.yaml @@ -34,13 +34,13 @@ jobs: - name: 服务状态 run: | echo "═══ 服务检查 ═══" - # Gitea - if systemctl is-active --quiet gitea 2>/dev/null; then - echo "✅ Gitea: 运行中" - elif curl -sf http://127.0.0.1:3000/ > /dev/null 2>&1; then - echo "✅ Gitea: 运行中 (Docker)" + # Gitea/Forgejo + if systemctl is-active --quiet forgejo 2>/dev/null; then + echo "✅ Gitea/Forgejo: 运行中" + elif curl -sf http://127.0.0.1:3001/ > /dev/null 2>&1; then + echo "✅ Gitea/Forgejo: 运行中 (Docker)" else - echo "❌ Gitea: 未运行" + echo "❌ Gitea/Forgejo: 未运行" fi # Nginx @@ -66,7 +66,7 @@ jobs: - name: 仓库状态 run: | echo "═══ 仓库检查 ═══" - REPO_DIR="/data/guanghulab" + REPO_DIR="/data/guanghulab/repo" if [[ -d "$REPO_DIR" ]]; then cd "$REPO_DIR" echo "路径: $REPO_DIR" diff --git a/scripts/cvm-init/init-cvm.sh b/scripts/cvm-init/init-cvm.sh new file mode 100755 index 0000000..28d5b7f --- /dev/null +++ b/scripts/cvm-init/init-cvm.sh @@ -0,0 +1,235 @@ +#!/usr/bin/env bash +# ════════════════════════════════════════════════════════════════ +# 光湖 · 新CVM一键初始化脚本 +# 服务器:guanghu-zhuyuan (4C16G, 42.193.161.251) +# 执行方式:在新服务器的腾讯云在线终端里运行 +# ════════════════════════════════════════════════════════════════ +# +# 用法(复制这一整行到新服务器终端执行): +# bash <(curl -fsSL https://raw.githubusercontent.com/qinfendebingshuo/guanghulab/main/scripts/cvm-init/init-cvm.sh) +# +# 如果GitHub不通,先在旧服务器上把脚本传过来: +# scp /opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/scripts/cvm-init/init-cvm.sh root@42.193.161.251:/tmp/ +# 然后在新服务器上:bash /tmp/init-cvm.sh +# +# ════════════════════════════════════════════════════════════════ + +set -euo pipefail +set +e # 不自动退出,让脚本继续 + +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${CYAN}═══════════════════════════════════════════${NC}" +echo -e "${CYAN} 光湖 · 新CVM初始化${NC}" +echo -e "${CYAN} guanghu-zhuyuan · 4C16G${NC}" +echo -e "${CYAN}═══════════════════════════════════════════${NC}" +echo "" + +# ─── 第1步:确认在新服务器上 ────────────────────────────────── +echo -e "${YELLOW}[第1步/8] 确认环境...${NC}" +CURRENT_IP=$(curl -sf ifconfig.me 2>/dev/null || echo "unknown") +echo " 当前IP: $CURRENT_IP" +if [[ "$CURRENT_IP" != "42.193.161.251" ]]; then + echo -e "${YELLOW} ⚠️ IP不是42.193.161.251,你确定要在这台机器上初始化?${NC}" + read -p " 继续吗?[y/N] " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 0; fi +fi +echo -e "${GREEN} 环境确认 ✅${NC}" + +# ─── 第2步:系统基础 ────────────────────────────────────────── +echo "" +echo -e "${YELLOW}[第2步/8] 安装系统基础软件...${NC}" +apt update -qq +apt install -y -qq curl git nginx ufw xz-utils unzip software-properties-common build-essential > /dev/null 2>&1 +echo -e "${GREEN} 系统软件 ✅${NC}" + +# ─── 第3步:Node.js 20 ──────────────────────────────────────── +echo "" +echo -e "${YELLOW}[第3步/8] 安装Node.js 20...${NC}" +if ! command -v node &>/dev/null || [[ "$(node -v)" != v20* ]]; then + curl -fsSL https://deb.nodesource.com/setup_20.x | bash - > /dev/null 2>&1 + apt install -y -qq nodejs > /dev/null 2>&1 +fi +echo " Node.js: $(node -v)" +npm install -g pm2 > /dev/null 2>&1 +echo " PM2: $(pm2 -v)" +echo -e "${GREEN} Node.js + PM2 ✅${NC}" + +# ─── 第4步:目录结构 ────────────────────────────────────────── +echo "" +echo -e "${YELLOW}[第4步/8] 创建目录结构...${NC}" +mkdir -p /data/guanghulab/{forgejo/{data,repositories,log},secrets-vault,scripts,.runtime} +echo -e "${GREEN} /data/guanghulab/ ✅${NC}" + +# ─── 第5步:Forgejo ─────────────────────────────────────────── +echo "" +echo -e "${YELLOW}[第5步/8] 安装Forgejo...${NC}" + +# 创建git用户 +if ! id -u git &>/dev/null; then + useradd -r -m -d /data/guanghulab/forgejo -s /bin/bash git + echo -e "${GREEN} git用户已创建${NC}" +fi + +# 下载Forgejo二进制 +FORGEJO_VERSION="11.0.1" +FORGEJO_BINARY="/usr/local/bin/forgejo" +if [[ ! -x "$FORGEJO_BINARY" ]]; then + echo " 下载Forgejo v${FORGEJO_VERSION}..." + curl -fSL --progress-bar -o "$FORGEJO_BINARY" \ + "https://codeberg.org/forgejo/forgejo/releases/download/v${FORGEJO_VERSION}/forgejo-${FORGEJO_VERSION}-linux-amd64" \ + 2>/dev/null || { + # 如果codeberg下载不了,试gitea镜像 + echo " codeberg不通,尝试备用下载..." + curl -fSL --progress-bar -o "$FORGEJO_BINARY" \ + "https://dl.gitea.io/forgejo/${FORGEJO_VERSION}/forgejo-${FORGEJO_VERSION}-linux-amd64" 2>/dev/null || { + echo -e "${RED} ❌ Forgejo下载失败${NC}" + echo " 请手动下载后放到 /usr/local/bin/forgejo" + echo " 下载地址: https://codeberg.org/forgejo/forgejo/releases" + } + } + chmod +x "$FORGEJO_BINARY" +fi + +if [[ -x "$FORGEJO_BINARY" ]]; then + echo " Forgejo: $("$FORGEJO_BINARY" --version 2>&1 | head -1)" +fi + +# Forgejo配置文件 +mkdir -p /etc/forgejo +cat > /etc/forgejo/app.ini << 'INIEOF' +WORK_PATH = /data/guanghulab/forgejo/data + +[server] +DOMAIN = guanghulab.com +ROOT_URL = https://guanghulab.com/git/ +HTTP_PORT = 3001 +HTTP_ADDR = 127.0.0.1 +LFS_START_SERVER = false +OFFLINE_MODE = false + +[database] +DB_TYPE = sqlite3 +PATH = /data/guanghulab/forgejo/data/forgejo.db + +[repository] +ROOT = /data/guanghulab/forgejo/repositories + +[log] +ROOT_PATH = /data/guanghulab/forgejo/log + +[service] +DISABLE_REGISTRATION = true + +[security] +INSTALL_LOCK = true + +[actions] +ENABLED = true + +[packages] +CHUNKED_UPLOAD_PATH = /data/guanghulab/forgejo/data/tmp/package-upload +INIEOF + +chown -R git:git /data/guanghulab/forgejo /etc/forgejo +echo -e "${GREEN} Forgejo配置 ✅${NC}" + +# systemd服务 +cat > /etc/systemd/system/forgejo.service << 'SVCEOF' +[Unit] +Description=Forgejo (self-hosted git) +After=network.target + +[Service] +User=git +Group=git +WorkingDirectory=/data/guanghulab/forgejo +ExecStart=/usr/local/bin/forgejo web --config /etc/forgejo/app.ini +Restart=always +RestartSec=10 +Environment=USER=git HOME=/data/guanghulab/forgejo + +[Install] +WantedBy=multi-user.target +SVCEOF + +systemctl daemon-reload +systemctl enable forgejo +systemctl start forgejo +sleep 3 + +if systemctl is-active --quiet forgejo; then + echo -e "${GREEN} Forgejo运行中 ✅${NC}" +else + echo -e "${RED} ❌ Forgejo启动失败${NC}" + journalctl -u forgejo -n 10 --no-pager +fi + +# ─── 第6步:Nginx ───────────────────────────────────────────── +echo "" +echo -e "${YELLOW}[第6步/8] 配置Nginx反向代理...${NC}" +cat > /etc/nginx/sites-available/guanghulab << 'NGXEOF' +server { + listen 80; + server_name guanghulab.com; + + # gRPC(Runner注册和通信需要) + location /git/api/actions/ { + grpc_pass grpc://127.0.0.1:3001; + grpc_set_header X-Real-IP $remote_addr; + } + + # 普通HTTP请求 + location /git/ { + proxy_pass http://127.0.0.1:3001/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + client_max_body_size 100M; + } +} +NGXEOF + +ln -sf /etc/nginx/sites-available/guanghulab /etc/nginx/sites-enabled/ +rm -f /etc/nginx/sites-enabled/default +nginx -t 2>/dev/null && systemctl restart nginx +echo -e "${GREEN} Nginx ✅${NC}" + +# ─── 第7步:防火墙 ──────────────────────────────────────────── +echo "" +echo -e "${YELLOW}[第7步/8] 配置防火墙...${NC}" +ufw allow 22/tcp +ufw allow 80/tcp +ufw allow 443/tcp +ufw --force enable +echo -e "${GREEN} 防火墙 ✅${NC}" + +# ─── 第8步:验证 ────────────────────────────────────────────── +echo "" +echo -e "${YELLOW}[第8步/8] 验证所有服务...${NC}" +echo "" +echo " Forgejo: $(systemctl is-active forgejo 2>/dev/null || echo unknown)" +echo " Nginx: $(systemctl is-active nginx 2>/dev/null || echo unknown)" +echo " Docker: $(systemctl is-active docker 2>/dev/null || echo unknown)" +echo " Node.js: $(node -v)" +echo " PM2: $(pm2 -v)" +echo "" +echo " 内存: $(free -h | awk '/Mem:/ {print $2 " 总计, " $7 " 可用"}')" +echo " 磁盘: $(df -h /data | awk 'NR==2 {print $4 " 可用"}')" +echo "" +echo -e "${GREEN}═══════════════════════════════════════════${NC}" +echo -e "${GREEN} ✅ 新CVM基础环境初始化完成!${NC}" +echo -e "${GREEN}═══════════════════════════════════════════${NC}" +echo "" +echo " 下一步:" +echo " 1. 浏览器打开 http://42.193.161.251/git/ 完成Forgejo初始设置" +echo " 2. 创建管理员账号 bingshuo" +echo " 3. 告诉铸渊Forgejo已就绪,铸渊会通过API完成剩余配置" +echo "" +echo " 铸渊 · ICE-GL-ZY001 · TCS-0002∞" diff --git a/scripts/patrol-agent/patrol-agent.js b/scripts/patrol-agent/patrol-agent.js index 41691a0..112d58b 100644 --- a/scripts/patrol-agent/patrol-agent.js +++ b/scripts/patrol-agent/patrol-agent.js @@ -61,6 +61,7 @@ const CONFIG = { // 巡检配置 interval: 300, // 秒,默认5分钟 reportPath: "/data/guanghulab/.runtime/patrol-reports", + repoPath: process.env.REPO_PATH || "/data/guanghulab/repo", // 自动修复规则(不需要大模型) autoFixRules: { @@ -182,7 +183,7 @@ function collectErrors() { function collectDeploy() { try { - const repoPath = "/opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab"; + const repoPath = process.env.REPO_PATH || (fs.existsSync("/data/guanghulab/repo") ? "/data/guanghulab/repo" : "/opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab"); const commit = execSync(`git -C ${repoPath} log -1 --oneline`, { encoding: "utf8" }).trim(); const branch = execSync(`git -C ${repoPath} branch --show-current`, { encoding: "utf8" }).trim(); return { branch, latest_commit: commit }; diff --git a/scripts/terminal-watcher/config.json b/scripts/terminal-watcher/config.json index 6fdceb0..f40eb56 100644 --- a/scripts/terminal-watcher/config.json +++ b/scripts/terminal-watcher/config.json @@ -10,8 +10,8 @@ "snapshot_path": ".runtime/terminal-snapshots/ZY-SVR-004" }, "local": { - "snapshot_path": "/opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/.runtime/snapshot.json", - "history_path": "/opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab/.runtime/history" + "snapshot_path": "/data/guanghulab/repo/.runtime/snapshot.json", + "history_path": "/data/guanghulab/repo/.runtime/history" }, "collectors": { "system": true, diff --git a/scripts/terminal-watcher/watcher.js b/scripts/terminal-watcher/watcher.js index 90a439f..567a08f 100644 --- a/scripts/terminal-watcher/watcher.js +++ b/scripts/terminal-watcher/watcher.js @@ -191,8 +191,8 @@ function collectLogs() { */ function collectDeploy() { const repoPaths = [ + "/data/guanghulab/repo", "/opt/zhuyuan-cn/repo-mirror/20260509-1849/guanghulab", - "/data/guanghulab", "/opt/guanghulab" ]; const repoPath = repoPaths.find(p => fs.existsSync(p)) || repoPaths[0];