diff --git a/src/metric/.gitignore b/src/metric/.gitignore index 09d33d4..8a209a5 100644 --- a/src/metric/.gitignore +++ b/src/metric/.gitignore @@ -1,6 +1,5 @@ /prometheus/data/ /client-plugins/dcgm-exporter-installer/ -/client-plugins/node-exporter-installer/ /client-plugins/demo-all-in-one/artifact/ /client-plugins/demo-all-in-one/publish/ /client-plugins/demo-all-in-one/checklist diff --git a/src/metric/client-plugins/node-exporter-installer/bin/node_exporter b/src/metric/client-plugins/node-exporter-installer/bin/node_exporter new file mode 100755 index 0000000..66c3e4a Binary files /dev/null and b/src/metric/client-plugins/node-exporter-installer/bin/node_exporter differ diff --git a/src/metric/client-plugins/node-exporter-installer/check_health.sh b/src/metric/client-plugins/node-exporter-installer/check_health.sh new file mode 100755 index 0000000..ed168e3 --- /dev/null +++ b/src/metric/client-plugins/node-exporter-installer/check_health.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# Node Exporter 健康检查脚本 +# 输出 JSON 格式结果 + +set -e + +# 检查 Node Exporter 健康状态 +check_health() { + local url="http://localhost:9100" + local metrics_url="$url/metrics" + local name="node-exporter" + local status="unhealth" + local reason="" + + # 检查 curl 是否可用 + if ! command -v curl &> /dev/null; then + reason="curl 命令不可用,无法进行健康检查" + echo "{\"name\": \"$name\", \"status\": \"$status\", \"reason\": \"$reason\"}" + exit 1 + fi + + # 测试根路径连接 + local http_code=$(curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null || echo "000") + + if [[ "$http_code" == "200" ]]; then + # 测试 metrics 端点 + local metrics_code=$(curl -s -o /dev/null -w "%{http_code}" "$metrics_url" 2>/dev/null || echo "000") + + if [[ "$metrics_code" == "200" ]]; then + status="health" + reason="success" + echo "{\"name\": \"$name\", \"status\": \"$status\", \"reason\": \"$reason\"}" + exit 0 + else + reason="Metrics 端点异常 (HTTP $metrics_code)" + echo "{\"name\": \"$name\", \"status\": \"$status\", \"reason\": \"$reason\"}" + exit 1 + fi + else + reason="HTTP 服务异常 (HTTP $http_code),请检查 Node Exporter 是否正在运行在端口 9100" + echo "{\"name\": \"$name\", \"status\": \"$status\", \"reason\": \"$reason\"}" + exit 1 + fi +} + +# 主函数 +main() { + check_health +} + +# 脚本入口 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/src/metric/client-plugins/node-exporter-installer/install.sh b/src/metric/client-plugins/node-exporter-installer/install.sh new file mode 100755 index 0000000..31a3a66 --- /dev/null +++ b/src/metric/client-plugins/node-exporter-installer/install.sh @@ -0,0 +1,297 @@ +#!/bin/bash + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 显示帮助信息 +show_help() { + echo "Node Exporter 安装脚本" + echo + echo "用法: $0 [选项]" + echo + echo "选项:" + echo " --help 显示此帮助信息" + echo + echo "示例:" + echo " $0 # 安装 Node Exporter" + echo +} + +# 解析命令行参数 +for arg in "$@"; do + case $arg in + --help|-h) + show_help + exit 0 + ;; + *) + log_error "未知参数: $arg" + show_help + exit 1 + ;; + esac +done + +# 检查是否为 root 用户 +check_root() { + if [[ $EUID -ne 0 ]]; then + log_error "此脚本需要 root 权限运行" + log_info "请使用: sudo $0" + exit 1 + fi +} + +# 检查系统要求 +check_system() { + log_info "检查系统要求..." + + # 检查操作系统 + if [[ ! -f /etc/os-release ]]; then + log_error "无法检测操作系统版本" + exit 1 + fi + + source /etc/os-release + log_info "检测到操作系统: $NAME $VERSION" + + # 检查是否为 Linux 系统 + if [[ "$ID" != "ubuntu" && "$ID" != "debian" && "$ID" != "centos" && "$ID" != "rhel" && "$ID" != "fedora" ]]; then + log_warning "此脚本主要针对常见 Linux 发行版,其他系统可能需要调整" + fi + + # 检查系统架构 + local arch=$(uname -m) + log_info "系统架构: $arch" + + if [[ "$arch" != "x86_64" && "$arch" != "amd64" ]]; then + log_warning "当前架构为 $arch,node_exporter 主要支持 x86_64/amd64" + fi +} + +# 停止可能运行的服务 +stop_existing_service() { + log_info "检查并停止可能运行的服务..." + + local pid_file="/var/run/node-exporter.pid" + + # 检查并停止通过 PID 文件管理的服务 + if [[ -f "$pid_file" ]]; then + local pid=$(cat "$pid_file") + if kill -0 "$pid" 2>/dev/null; then + log_info "发现正在运行的 Node Exporter 服务 (PID: $pid),正在停止..." + kill "$pid" + sleep 2 + if kill -0 "$pid" 2>/dev/null; then + log_warning "进程未响应,强制终止..." + kill -9 "$pid" 2>/dev/null || true + fi + rm -f "$pid_file" + log_success "服务已停止" + else + log_warning "发现过期的 PID 文件,正在清理..." + rm -f "$pid_file" + fi + fi + + # 查找并停止所有 node_exporter 和 node-exporter 进程 + local pids=$(pgrep -f "node_exporter\|node-exporter" 2>/dev/null || true) + if [[ -n "$pids" ]]; then + log_info "发现 node_exporter 或 node-exporter 进程,正在停止..." + for pid in $pids; do + log_info "停止进程 PID: $pid" + kill "$pid" 2>/dev/null || true + done + sleep 2 + + # 检查是否还有进程在运行,如果有则强制终止 + local remaining_pids=$(pgrep -f "node_exporter\|node-exporter" 2>/dev/null || true) + if [[ -n "$remaining_pids" ]]; then + log_warning "进程未响应,强制终止..." + for pid in $remaining_pids; do + log_info "强制终止进程 PID: $pid" + kill -9 "$pid" 2>/dev/null || true + done + sleep 1 + fi + + # 最终检查 + if pgrep -f "node_exporter\|node-exporter" > /dev/null; then + log_error "无法停止所有 node_exporter 进程" + else + log_success "所有 node_exporter 进程已停止" + fi + fi +} + +# 安装 Node Exporter 二进制文件 +install_node_exporter() { + log_info "安装 Node Exporter..." + + local binary_file="bin/node_exporter" + local install_dir="/usr/local/bin" + + if [[ ! -f "$binary_file" ]]; then + log_error "找不到 Node Exporter 二进制文件: $binary_file" + exit 1 + fi + + # 停止可能运行的服务 + stop_existing_service + + # 复制二进制文件并重命名为统一格式 + cp "$binary_file" "$install_dir/node-exporter" + chmod +x "$install_dir/node-exporter" + + log_success "Node Exporter 二进制文件安装完成" +} + +# 创建用户和组 +create_user() { + log_info "创建 node_exporter 用户..." + + # 检查用户是否已存在 + if id "node_exporter" &>/dev/null; then + log_info "用户 node_exporter 已存在" + else + useradd --no-create-home --shell /bin/false node_exporter + log_success "用户 node_exporter 创建完成" + fi +} + +# 安装配置文件 +install_config() { + log_info "安装配置文件..." + + local config_dir="/etc/node_exporter" + + # 创建配置目录 + mkdir -p "$config_dir" + + # 创建文本文件收集器目录 + mkdir -p "/var/lib/node_exporter/textfile_collector" + chown node_exporter:node_exporter "/var/lib/node_exporter/textfile_collector" +} + +# 启动 Node Exporter 服务 +start_node_exporter() { + log_info "启动 Node Exporter 服务..." + + local binary_path="/usr/local/bin/node-exporter" + local log_file="/var/log/node-exporter.log" + local pid_file="/var/run/node-exporter.pid" + + # 检查服务是否已经在运行 + if [[ -f "$pid_file" ]]; then + local pid=$(cat "$pid_file") + if kill -0 "$pid" 2>/dev/null; then + log_info "Node Exporter 服务已在运行 (PID: $pid)" + return 0 + else + log_warning "发现过期的 PID 文件,正在清理..." + rm -f "$pid_file" + fi + fi + + # 检查端口是否被占用 + if netstat -tuln 2>/dev/null | grep -q ":9100 "; then + log_warning "端口 9100 已被占用,请检查是否有其他服务在运行" + return 1 + fi + + # 启动服务 + log_info "正在启动 Node Exporter..." + nohup "$binary_path" --web.listen-address=:9100 > "$log_file" 2>&1 & + local pid=$! + + # 保存 PID + echo "$pid" > "$pid_file" + + # 等待服务启动 + sleep 2 + + # 检查服务是否成功启动 + if kill -0 "$pid" 2>/dev/null; then + log_success "Node Exporter 服务启动成功 (PID: $pid)" + log_info "日志文件: $log_file" + log_info "PID 文件: $pid_file" + else + log_error "Node Exporter 服务启动失败" + rm -f "$pid_file" + return 1 + fi +} + + + +# 显示安装信息 +show_install_info() { + log_success "Node Exporter 安装完成!" + echo + echo "安装信息:" + echo " 二进制文件: /usr/local/bin/node-exporter" + echo " 运行用户: node_exporter" + echo " 配置目录: /etc/node_exporter/" + echo " 默认端口: 9100" + echo + echo "使用方法:" + echo " 手动启动: /usr/local/bin/node-exporter --web.listen-address=:9100" + echo " 后台启动: nohup /usr/local/bin/node-exporter --web.listen-address=:9100 &" + echo + echo "测试连接:" + echo " curl http://localhost:9100/metrics" + echo " curl http://localhost:9100" + echo + echo "Prometheus 配置示例:" + echo " - job_name: 'node_exporter'" + echo " static_configs:" + echo " - targets: ['localhost:9100']" + echo +} + +# 主函数 +main() { + echo "==========================================" + echo " Node Exporter 安装脚本 v1.0" + echo "==========================================" + echo + + check_root + check_system + + log_info "开始安装 Node Exporter..." + + install_node_exporter + create_user + install_config + start_node_exporter + + show_install_info +} + +# 脚本入口 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/src/metric/client-plugins/node-exporter-installer/package.sh b/src/metric/client-plugins/node-exporter-installer/package.sh new file mode 100755 index 0000000..04cf207 --- /dev/null +++ b/src/metric/client-plugins/node-exporter-installer/package.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +set -e + +# 颜色定义 +GREEN='\033[0;32m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +# 获取当前目录 +CURRENT_DIR=$(pwd) +PACKAGE_NAME="node-exporter-installer-$(date +%Y%m%d-%H%M%S)" +PACKAGE_FILE="${PACKAGE_NAME}.tar.gz" + +log_info "开始打包 Node Exporter 安装包..." + +# 检查必要文件 +log_info "检查必要文件..." + +required_files=( + "install.sh" + "uninstall.sh" + "bin/node_exporter" + "check_health.sh" +) + +missing_files=() +for file in "${required_files[@]}"; do + if [[ ! -f "$file" ]]; then + missing_files+=("$file") + fi +done + +if [[ ${#missing_files[@]} -gt 0 ]]; then + echo "缺少以下文件:" + for file in "${missing_files[@]}"; do + echo " - $file" + done + exit 1 +fi + +log_success "所有必要文件检查完成" + +# 创建临时目录 +TEMP_DIR=$(mktemp -d) +log_info "创建临时目录: $TEMP_DIR" + +# 复制文件到临时目录 +cp -r . "$TEMP_DIR/$PACKAGE_NAME" + +# 进入临时目录 +cd "$TEMP_DIR" + +# 创建压缩包 +log_info "创建压缩包: $PACKAGE_FILE" +tar -czf "$PACKAGE_FILE" "$PACKAGE_NAME" + +# 移动压缩包到原目录 +mv "$PACKAGE_FILE" "$CURRENT_DIR/" + +# 清理临时目录 +rm -rf "$TEMP_DIR" + +# 返回原目录 +cd "$CURRENT_DIR" + +# 显示结果 +log_success "打包完成!" +echo +echo "安装包文件: $PACKAGE_FILE" +echo "文件大小: $(du -h "$PACKAGE_FILE" | cut -f1)" +echo +echo "使用方法:" +echo "1. 将 $PACKAGE_FILE 传输到目标服务器" +echo "2. 解压: tar -xzf $PACKAGE_FILE" +echo "3. 进入目录: cd $PACKAGE_NAME" +echo "4. 运行安装: sudo ./install.sh" +echo +echo "注意: 请确保所有必要文件都存在" diff --git a/src/metric/client-plugins/node-exporter-installer/uninstall.sh b/src/metric/client-plugins/node-exporter-installer/uninstall.sh new file mode 100755 index 0000000..14801c1 --- /dev/null +++ b/src/metric/client-plugins/node-exporter-installer/uninstall.sh @@ -0,0 +1,239 @@ +#!/bin/bash + +# Node Exporter 卸载脚本 +# 版本: 1.0 +# 作者: AIOps Team +# 日期: $(date +%Y-%m-%d) + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 日志函数 +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 检查是否为 root 用户 +check_root() { + if [[ $EUID -ne 0 ]]; then + log_error "此脚本需要 root 权限运行" + log_info "请使用: sudo $0" + exit 1 + fi +} + +# 停止运行中的进程 +stop_processes() { + log_info "停止 Node Exporter 进程..." + + local pid_file="/var/run/node-exporter.pid" + local stopped=false + + # 首先尝试通过 PID 文件停止服务 + if [[ -f "$pid_file" ]]; then + local pid=$(cat "$pid_file") + if kill -0 "$pid" 2>/dev/null; then + log_info "通过 PID 文件停止服务 (PID: $pid)..." + kill "$pid" + sleep 3 + + # 检查进程是否已停止 + if kill -0 "$pid" 2>/dev/null; then + log_warning "进程未响应,强制终止..." + kill -9 "$pid" 2>/dev/null || true + fi + log_success "Node Exporter 进程已停止" + stopped=true + else + log_warning "PID 文件存在但进程已不存在,清理 PID 文件" + rm -f "$pid_file" + fi + fi + + # 查找并杀死所有 node_exporter 和 node-exporter 进程 + local pids=$(pgrep -f "node_exporter\|node-exporter" 2>/dev/null || true) + if [[ -n "$pids" ]]; then + log_info "发现 node_exporter 或 node-exporter 进程,正在停止..." + for pid in $pids; do + log_info "停止进程 PID: $pid" + kill "$pid" 2>/dev/null || true + done + sleep 2 + + # 检查是否还有进程在运行,如果有则强制终止 + local remaining_pids=$(pgrep -f "node_exporter\|node-exporter" 2>/dev/null || true) + if [[ -n "$remaining_pids" ]]; then + log_warning "进程未响应,强制终止..." + for pid in $remaining_pids; do + log_info "强制终止进程 PID: $pid" + kill -9 "$pid" 2>/dev/null || true + done + sleep 1 + fi + + # 最终检查 + if pgrep -f "node_exporter\|node-exporter" > /dev/null; then + log_error "无法停止所有 node_exporter 进程" + else + log_success "所有 Node Exporter 进程已停止" + stopped=true + fi + else + log_info "Node Exporter 进程未运行" + fi + + # 清理 PID 文件 + rm -f "$pid_file" + + if [[ "$stopped" == "false" ]]; then + log_warning "未发现需要停止的 Node Exporter 进程" + fi +} + +# 删除二进制文件 +remove_binary() { + log_info "删除 Node Exporter 二进制文件..." + + local binary_files=( + "/usr/local/bin/node-exporter" + "/usr/local/bin/node_exporter" + ) + + local deleted=false + for binary_file in "${binary_files[@]}"; do + if [[ -f "$binary_file" ]]; then + rm -f "$binary_file" + log_success "二进制文件已删除: $binary_file" + deleted=true + fi + done + + if [[ "$deleted" == "false" ]]; then + log_info "二进制文件不存在" + fi +} + +# 删除配置文件 +remove_config() { + log_info "删除配置文件..." + + local config_dir="/etc/node_exporter" + + if [[ -d "$config_dir" ]]; then + rm -rf "$config_dir" + log_success "配置目录已删除" + else + log_info "配置目录不存在" + fi +} + +# 删除数据目录 +remove_data_dir() { + log_info "删除数据目录..." + + local data_dir="/var/lib/node_exporter" + + if [[ -d "$data_dir" ]]; then + rm -rf "$data_dir" + log_success "数据目录已删除" + else + log_info "数据目录不存在" + fi +} + +# 检查用户状态(可选) +check_user_status() { + log_info "检查 node_exporter 用户状态..." + + if id "node_exporter" &>/dev/null; then + log_info "检测到 node_exporter 用户存在" + log_warning "node_exporter 是系统用户,可能被其他服务使用" + log_info "为了系统稳定性,将保留 node_exporter 用户" + log_info "如需手动删除,请运行: sudo userdel node_exporter" + else + log_info "node_exporter 用户不存在" + fi +} + +# 清理日志文件 +cleanup_logs() { + log_info "清理日志文件..." + + # 清理 journal 日志 + journalctl --vacuum-time=1s --quiet || true + + # 删除安装脚本创建的日志文件 + rm -f /var/log/node-exporter.log + + log_success "日志文件已清理" +} + +# 显示卸载信息 +show_uninstall_info() { + log_success "Node Exporter 卸载完成!" + echo + echo "已删除的内容:" + echo " - 二进制文件: /usr/local/bin/node-exporter" + echo " - 配置目录: /etc/node_exporter" + echo " - 数据目录: /var/lib/node_exporter" + echo " - 相关日志文件" + echo + echo "注意:" + echo " - node_exporter 用户已保留(系统用户,可能被其他服务使用)" + echo " - 如需完全清理,请手动检查并删除相关文件" + echo +} + +# 主函数 +main() { + echo "==========================================" + echo " Node Exporter 卸载脚本 v1.0" + echo "==========================================" + echo + + check_root + + log_warning "此操作将完全卸载 Node Exporter" + read -p "确认继续?(y/N): " confirm + + if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then + log_info "取消卸载操作" + exit 0 + fi + + log_info "开始卸载 Node Exporter..." + + stop_processes + remove_binary + remove_config + remove_data_dir + cleanup_logs + + # 检查用户状态 + check_user_status + + show_uninstall_info +} + +# 脚本入口 +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi