From 74c1db2f1443c70be0cb43aaaf5005cf46dcf46a Mon Sep 17 00:00:00 2001 From: yoyo Date: Wed, 3 Dec 2025 22:08:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=B8=E8=BD=BD=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 286 ++++++++++++++++++++++++++++++++++++++++++++- uninstall.sh | 318 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 602 insertions(+), 2 deletions(-) create mode 100755 uninstall.sh diff --git a/README.md b/README.md index 842e4b3..3ad2fff 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,290 @@ BACKEND_URL=http://192.168.1.100:8080 ./run.sh start - 如果 Git 拉取失败(如网络问题),会使用当前代码继续编译 - 如果编译失败,服务不会启动 +## 脚本工具 + +项目提供了多个脚本工具,方便安装、卸载、运行、编译和发布。 + +### 1. install.sh - 一键安装脚本 + +自动安装 LinkMaster 节点端到系统,包括依赖安装、源码编译、systemd 服务配置等。 + +**使用方法:** + +```bash +# 通过 curl 下载并安装(推荐) +curl -fsSL https://gitee.nas.cpolar.cn/yoyo/linkmaster-node/raw/branch/main/install.sh | bash -s -- http://your-backend-server:8080 + +# 本地运行安装脚本 +./install.sh http://your-backend-server:8080 + +# 指定分支安装 +GITHUB_BRANCH=develop curl -fsSL https://gitee.nas.cpolar.cn/yoyo/linkmaster-node/raw/branch/main/install.sh | bash -s -- http://your-backend-server:8080 +``` + +**功能特性:** +- 自动检测系统类型和架构(Linux/macOS, amd64/arm64) +- 自动检测并配置最快的镜像源(Ubuntu/Debian/CentOS) +- 自动安装系统依赖(curl, wget, git, ping, traceroute 等) +- 自动安装 Go 环境(优先使用系统包管理器,失败则从官网下载) +- 优先从 Releases 下载预编译二进制文件,失败则从源码编译 +- 自动创建 systemd 服务并配置自启动 +- 自动配置防火墙规则(开放 2200 端口) +- 自动登记节点到后端服务器 +- 自动启动服务并验证安装 + +**安装位置:** +- 二进制文件:`/usr/local/bin/linkmaster-node` +- 源码目录:`/opt/linkmaster-node` +- 服务文件:`/etc/systemd/system/linkmaster-node.service` +- 配置文件:`/opt/linkmaster-node/config.yaml` + +### 2. uninstall.sh - 一键卸载脚本 + +完全卸载 LinkMaster 节点端,包括停止服务、删除文件、清理配置等。 + +**使用方法:** + +```bash +# 通过 curl 下载并运行 +curl -fsSL https://gitee.nas.cpolar.cn/yoyo/linkmaster-node/raw/branch/main/uninstall.sh | bash + +# 本地运行卸载脚本 +./uninstall.sh + +# 卸载并删除防火墙规则 +./uninstall.sh --remove-firewall +``` + +**功能特性:** +- 停止并禁用 systemd 服务 +- 删除 systemd 服务文件和配置目录 +- 删除二进制文件(`/usr/local/bin/linkmaster-node`) +- 删除源码目录(`/opt/linkmaster-node`) +- 清理所有残留进程 +- 重新加载 systemd daemon +- 可选:删除防火墙规则(默认保留) + +**注意事项:** +- 卸载前会询问确认(交互式环境) +- 默认保留防火墙规则,避免影响其他服务 +- 使用 `--remove-firewall` 参数可删除防火墙规则 + +### 3. run.sh - 运行管理脚本 + +用于管理节点端的启动、停止、重启、状态查看和日志查看。**每次启动时会自动拉取最新代码并重新编译**。 + +**使用方法:** + +```bash +# 启动服务(会自动拉取最新代码并编译) +./run.sh start + +# 停止服务 +./run.sh stop + +# 重启服务(会拉取最新代码并重新编译) +./run.sh restart + +# 查看运行状态 +./run.sh status + +# 实时查看日志 +./run.sh logs + +# 查看完整日志 +./run.sh logs-all + +# 显示帮助信息 +./run.sh help + +# 指定后端地址启动 +BACKEND_URL=http://192.168.1.100:8080 ./run.sh start +``` + +**功能特性:** +- 启动时自动执行 `git pull` 拉取最新代码 +- 自动执行 `go mod download` 更新依赖 +- 自动编译生成新的二进制文件 +- 自动检测端口占用并提示处理 +- 后台运行并保存 PID 文件 +- 健康检查验证服务状态 +- 支持通过环境变量 `BACKEND_URL` 指定后端地址 + +**环境变量:** +- `BACKEND_URL`: 后端服务地址(默认: `http://localhost:8080`) + +### 4. start-systemd.sh - systemd 启动脚本 + +用于 systemd 服务启动,直接运行二进制文件。如果二进制文件不存在,会自动拉取代码并编译。 + +**使用场景:** +- 由 systemd 服务自动调用 +- 不需要手动运行 + +**功能特性:** +- 检查二进制文件是否存在且有效 +- 如果二进制文件不存在,自动拉取代码并编译 +- 使用 vendor 目录编译(无需网络连接) +- 直接运行二进制文件(systemd 管理进程) + +**注意事项:** +- 此脚本由 systemd 服务调用,通常不需要手动运行 +- 需要确保源码目录存在且是 Git 仓库 +- 需要 Go 环境已安装并在 PATH 中 + +### 5. build-all.sh - 跨平台编译脚本 + +编译多个操作系统和架构的二进制文件,支持并行编译。 + +**使用方法:** + +```bash +# 编译所有平台 +./build-all.sh + +# 只编译指定平台 +./build-all.sh -p linux/amd64 + +# 编译前清理输出目录 +./build-all.sh -c + +# 设置并行编译数量 +./build-all.sh -j 2 + +# 设置版本号 +./build-all.sh -v 1.0.0 + +# 只生成不带版本号的文件 +./build-all.sh -s + +# 列出所有支持的平台 +./build-all.sh -l + +# 显示帮助信息 +./build-all.sh -h +``` + +**支持的平台:** +- `linux/amd64` - Linux x86_64 +- `linux/arm64` - Linux ARM64 +- `darwin/amd64` - macOS Intel +- `darwin/arm64` - macOS Apple Silicon +- `windows/amd64` - Windows x86_64 +- `windows/arm64` - Windows ARM64 + +**功能特性:** +- 支持并行编译(默认 4 个任务) +- 自动生成带版本号和不带版本号的文件 +- 输出到 `bin/` 目录 +- 显示编译进度和结果 +- 支持清理输出目录 + +**输出文件:** +- `bin/agent-{os}-{arch}` - 不带版本号的二进制文件 +- `bin/agent-{os}-{arch}-{version}` - 带版本号的二进制文件 +- Windows 平台会自动添加 `.exe` 扩展名 + +### 6. upload.sh - 发布上传脚本 + +将编译好的二进制文件上传到 Releases 或通过其他方式发布。 + +**使用方法:** + +```bash +# 上传到 Gitea Releases(自动从 .git/config 读取仓库信息) +./upload.sh -m gitea -t v1.0.0 -v 1.0.0 + +# 指定 Gitea 访问令牌 +./upload.sh -m gitea -t v1.0.0 -v 1.0.0 -T your_token + +# 上传到 GitHub Releases +./upload.sh -m github -r owner/repo -t v1.0.0 -v 1.0.0 + +# 通过 SCP 上传 +./upload.sh -m scp -H example.com -u user -d /path/to/release + +# 通过 SCP 上传(指定私钥) +./upload.sh -m scp -H example.com -u user -d /path/to/release -k ~/.ssh/id_rsa + +# 通过 FTP 上传 +./upload.sh -m ftp -H ftp.example.com -u user -d /path/to/release + +# 复制到本地目录 +./upload.sh -m local -d /path/to/release + +# 只打包不上传 +./upload.sh --pack-only -v 1.0.0 + +# 不上传压缩包,直接上传二进制文件 +./upload.sh -m scp --no-pack -H example.com -u user -d /path/to/release + +# 显示帮助信息 +./upload.sh -h +``` + +**支持的上传方式:** +- `gitea` - Gitea Releases(自动从 .git/config 读取仓库信息) +- `github` - GitHub Releases(需要 GitHub CLI `gh`) +- `scp` - 通过 SCP 上传到远程服务器 +- `ftp` - 通过 FTP 上传 +- `local` - 复制到本地目录 + +**功能特性:** +- 自动打包二进制文件(tar.gz 或 zip) +- 自动创建发布说明 +- 支持指定平台上传 +- 支持自定义版本号和标签 +- 支持自定义发布说明 +- 自动检测并处理已存在的 Release + +**参数说明:** +- `-m, --method`: 上传方式(gitea|github|scp|ftp|local) +- `-v, --version`: 版本号(默认: 时间戳) +- `-t, --tag`: Git 标签(Releases 需要) +- `-p, --platform`: 只上传指定平台 +- `-T, --token`: 访问令牌(Gitea/GitHub) +- `-H, --host`: 主机地址(SCP/FTP) +- `-u, --user`: 用户名(SCP/FTP) +- `-d, --dest`: 目标路径(SCP/FTP/local) +- `-k, --key`: 私钥路径(SCP) +- `--pack-only`: 只打包不上传 +- `--no-pack`: 不上传压缩包,直接上传二进制文件 + +### 7. vendor.sh - Vendor 依赖打包脚本 + +将项目依赖下载到 vendor 目录,客户端克隆后可直接编译,无需网络连接。 + +**使用方法:** + +```bash +# 运行脚本(会自动下载依赖并创建 vendor 目录) +./vendor.sh +``` + +**功能特性:** +- 检查 Go 环境 +- 配置 Go 代理(使用官方源) +- 下载所有依赖包 +- 创建 vendor 目录 +- 更新 .gitignore(允许 vendor 目录被提交) +- 自动添加到 Git 暂存区 + +**使用场景:** +- 项目需要离线编译能力 +- 需要确保依赖版本一致性 +- 客户端环境网络受限 + +**注意事项:** +- 需要 Go 环境已安装 +- vendor 目录会比较大,需要提交到 Git +- 编译时使用 `-mod=vendor` 标志 + +**编译命令(使用 vendor):** +```bash +go build -mod=vendor -o agent ./cmd/agent +``` + ## API ### POST /api/test @@ -180,5 +464,3 @@ BACKEND_URL=http://192.168.1.100:8080 ./run.sh start ### GET /api/health 健康检查 -# linkmaster-node -# linkmaster-node diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..318e48d --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,318 @@ +#!/bin/bash + +# ============================================ +# LinkMaster 节点端一键卸载脚本 +# 使用方法: curl -fsSL https://gitee.nas.cpolar.cn/yoyo/linkmaster-node/raw/branch/main/uninstall.sh | bash +# 或: ./uninstall.sh +# ============================================ + +set -e + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# 配置 +BINARY_NAME="linkmaster-node" +INSTALL_DIR="/usr/local/bin" +SERVICE_NAME="linkmaster-node" +SOURCE_DIR="/opt/linkmaster-node" +CONFIG_FILE="${SOURCE_DIR}/config.yaml" +LOG_FILE="${SOURCE_DIR}/node.log" +PID_FILE="${SOURCE_DIR}/node.pid" + +# 检查是否已安装 +check_installed() { + local installed=false + + # 检查服务文件是否存在 + if [ -f "/etc/systemd/system/${SERVICE_NAME}.service" ]; then + installed=true + fi + + # 检查二进制文件是否存在 + if [ -f "$INSTALL_DIR/$BINARY_NAME" ]; then + installed=true + fi + + # 检查源码目录是否存在 + if [ -d "$SOURCE_DIR" ]; then + installed=true + fi + + if [ "$installed" = false ]; then + return 1 + fi + return 0 +} + +# 停止服务 +stop_service() { + echo -e "${BLUE}停止服务...${NC}" + + # 停止 systemd 服务 + if systemctl is-active --quiet ${SERVICE_NAME} 2>/dev/null; then + echo -e "${BLUE} 正在停止 systemd 服务...${NC}" + sudo systemctl stop ${SERVICE_NAME} 2>/dev/null || true + sleep 2 + fi + + # 清理残留进程 + if pgrep -f "$BINARY_NAME" > /dev/null 2>&1; then + echo -e "${BLUE} 清理残留进程...${NC}" + sudo pkill -f "$BINARY_NAME" 2>/dev/null || true + sleep 1 + + # 再次检查,如果还有进程则强制杀死 + if pgrep -f "$BINARY_NAME" > /dev/null 2>&1; then + echo -e "${YELLOW} 强制清理残留进程...${NC}" + sudo pkill -9 -f "$BINARY_NAME" 2>/dev/null || true + sleep 1 + fi + fi + + # 如果使用 run.sh 启动的进程(通过 PID 文件) + if [ -f "$PID_FILE" ]; then + local pid=$(cat "$PID_FILE" 2>/dev/null || echo "") + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + echo -e "${BLUE} 停止通过 run.sh 启动的进程 (PID: $pid)...${NC}" + kill "$pid" 2>/dev/null || true + sleep 1 + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null || true + fi + fi + fi + + echo -e "${GREEN}✓ 服务已停止${NC}" +} + +# 禁用服务 +disable_service() { + echo -e "${BLUE}禁用服务...${NC}" + + if systemctl is-enabled --quiet ${SERVICE_NAME} 2>/dev/null; then + sudo systemctl disable ${SERVICE_NAME} 2>/dev/null || true + echo -e "${GREEN}✓ 服务已禁用${NC}" + else + echo -e "${BLUE} 服务未启用,跳过${NC}" + fi +} + +# 删除服务文件 +remove_service_files() { + echo -e "${BLUE}删除服务文件...${NC}" + + local removed=false + + # 删除 systemd 服务文件 + if [ -f "/etc/systemd/system/${SERVICE_NAME}.service" ]; then + sudo rm -f /etc/systemd/system/${SERVICE_NAME}.service + echo -e "${GREEN}✓ 已删除服务文件: /etc/systemd/system/${SERVICE_NAME}.service${NC}" + removed=true + fi + + # 删除可能的 override 配置目录 + if [ -d "/etc/systemd/system/${SERVICE_NAME}.service.d" ]; then + sudo rm -rf /etc/systemd/system/${SERVICE_NAME}.service.d + echo -e "${GREEN}✓ 已删除服务配置目录: /etc/systemd/system/${SERVICE_NAME}.service.d${NC}" + removed=true + fi + + if [ "$removed" = true ]; then + # 重新加载 systemd daemon + sudo systemctl daemon-reload + echo -e "${GREEN}✓ systemd daemon 已重新加载${NC}" + else + echo -e "${BLUE} 未找到服务文件,跳过${NC}" + fi +} + +# 删除二进制文件 +remove_binary() { + echo -e "${BLUE}删除二进制文件...${NC}" + + if [ -f "$INSTALL_DIR/$BINARY_NAME" ]; then + sudo rm -f "$INSTALL_DIR/$BINARY_NAME" + echo -e "${GREEN}✓ 已删除二进制文件: $INSTALL_DIR/$BINARY_NAME${NC}" + else + echo -e "${BLUE} 未找到二进制文件,跳过${NC}" + fi +} + +# 删除源码目录和配置文件 +remove_source_directory() { + echo -e "${BLUE}删除源码目录和配置文件...${NC}" + + if [ -d "$SOURCE_DIR" ]; then + # 显示将要删除的内容 + echo -e "${BLUE} 源码目录: $SOURCE_DIR${NC}" + + # 删除整个源码目录 + sudo rm -rf "$SOURCE_DIR" + echo -e "${GREEN}✓ 已删除源码目录: $SOURCE_DIR${NC}" + else + echo -e "${BLUE} 未找到源码目录,跳过${NC}" + fi + + # 额外检查配置文件(如果单独存在) + if [ -f "$CONFIG_FILE" ]; then + sudo rm -f "$CONFIG_FILE" + echo -e "${GREEN}✓ 已删除配置文件: $CONFIG_FILE${NC}" + fi +} + +# 清理防火墙规则(可选,默认不删除) +remove_firewall_rules() { + local remove_firewall="${1:-false}" + + if [ "$remove_firewall" != "true" ]; then + echo -e "${BLUE}跳过防火墙规则清理(默认保留)${NC}" + echo -e "${YELLOW} 如需删除防火墙规则,请使用: ./uninstall.sh --remove-firewall${NC}" + return + fi + + echo -e "${BLUE}清理防火墙规则(开放2200端口)...${NC}" + + PORT=2200 + FIREWALL_REMOVED=false + + # 检测 firewalld (CentOS/RHEL 7+, Fedora) + if command -v firewall-cmd > /dev/null 2>&1; then + if sudo systemctl is-active --quiet firewalld 2>/dev/null; then + echo -e "${BLUE} 从 firewalld 删除端口规则...${NC}" + if sudo firewall-cmd --permanent --remove-port=${PORT}/tcp > /dev/null 2>&1; then + sudo firewall-cmd --reload > /dev/null 2>&1 + echo -e "${GREEN}✓ firewalld 规则已删除${NC}" + FIREWALL_REMOVED=true + fi + fi + fi + + # 检测 ufw (Ubuntu/Debian) + if command -v ufw > /dev/null 2>&1; then + if sudo ufw status > /dev/null 2>&1; then + echo -e "${BLUE} 从 ufw 删除端口规则...${NC}" + if sudo ufw delete allow ${PORT}/tcp > /dev/null 2>&1; then + echo -e "${GREEN}✓ ufw 规则已删除${NC}" + FIREWALL_REMOVED=true + fi + fi + fi + + # 检测 iptables(较老的系统) + if command -v iptables > /dev/null 2>&1 && [ "$FIREWALL_REMOVED" = false ]; then + if sudo iptables -C INPUT -p tcp --dport ${PORT} -j ACCEPT > /dev/null 2>&1; then + echo -e "${BLUE} 从 iptables 删除端口规则...${NC}" + if sudo iptables -D INPUT -p tcp --dport ${PORT} -j ACCEPT > /dev/null 2>&1; then + echo -e "${GREEN}✓ iptables 规则已删除${NC}" + # 尝试保存规则 + if command -v iptables-save > /dev/null 2>&1; then + if [ -f /etc/redhat-release ]; then + sudo iptables-save > /etc/sysconfig/iptables 2>/dev/null || true + elif [ -f /etc/debian_version ]; then + sudo iptables-save > /etc/iptables/rules.v4 2>/dev/null || true + fi + fi + FIREWALL_REMOVED=true + fi + fi + fi + + if [ "$FIREWALL_REMOVED" = false ]; then + echo -e "${YELLOW}⚠ 未找到防火墙规则或防火墙未启用${NC}" + fi +} + +# 显示卸载摘要 +show_summary() { + echo "" + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} 卸载完成!${NC}" + echo -e "${GREEN}========================================${NC}" + echo "" + echo -e "${BLUE}已删除的内容:${NC}" + echo " - systemd 服务文件" + echo " - 二进制文件: $INSTALL_DIR/$BINARY_NAME" + echo " - 源码目录: $SOURCE_DIR" + echo "" + echo -e "${YELLOW}注意:${NC}" + echo " - 防火墙规则已保留(如需删除请使用 --remove-firewall 参数)" + echo " - 如果手动修改过系统配置,请手动清理" + echo "" +} + +# 主卸载流程 +main() { + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN} LinkMaster 节点端卸载程序${NC}" + echo -e "${GREEN}========================================${NC}" + echo "" + + # 检查是否已安装 + if ! check_installed; then + echo -e "${YELLOW}未检测到已安装的 LinkMaster 节点端${NC}" + echo -e "${YELLOW}无需卸载${NC}" + exit 0 + fi + + # 检查是否需要删除防火墙规则 + REMOVE_FIREWALL=false + if [ "$1" = "--remove-firewall" ]; then + REMOVE_FIREWALL=true + fi + + # 确认卸载 + echo -e "${YELLOW}即将卸载 LinkMaster 节点端,此操作将:${NC}" + echo " - 停止并禁用服务" + echo " - 删除 systemd 服务文件" + echo " - 删除二进制文件" + echo " - 删除源码目录和配置文件" + echo "" + + # 如果在非交互式环境中,自动确认 + if [ -t 0 ]; then + read -p "是否继续?(y/N): " -n 1 -r + echo "" + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${YELLOW}已取消卸载${NC}" + exit 0 + fi + else + echo -e "${BLUE}非交互式环境,自动确认卸载${NC}" + fi + + echo "" + + # 执行卸载步骤 + stop_service + disable_service + remove_service_files + remove_binary + remove_source_directory + remove_firewall_rules "$REMOVE_FIREWALL" + + # 最终检查 + echo "" + echo -e "${BLUE}最终检查...${NC}" + + local still_installed=false + if check_installed; then + still_installed=true + fi + + if [ "$still_installed" = false ]; then + show_summary + exit 0 + else + echo -e "${YELLOW}⚠ 部分文件可能未完全删除,请手动检查${NC}" + exit 1 + fi +} + +# 执行卸载 +main "$@" +