Files
notes/resource/组件/Ubuntu 24.04 LTS ELK 8 安装指南.md
2026-03-01 01:43:46 +08:00

26 KiB

1. 环境准备

# 更新系统包
sudo apt update && sudo apt full-upgrade -y

# 安装必要的依赖
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg

# 提高文件描述符限制
sudo vim /etc/security/limits.conf

# 提高文件描述符限制,在 limits.conf 文件末尾添加
sudo vim /etc/security/limits.conf
elasticsearch soft nofile 65535
elasticsearch hard nofile 65535

2. Elasticsearch

添加 Elastic 官方仓库

# 添加 Elastic GPG 密钥
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg

# 添加 Elastic 仓库
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

安装 Elasticsearch

sudo apt update && sudo apt install -y elasticsearch=8.13.*

Elasticsearch 会自动生成密码和令牌。

调整启动内存

# ES 8.x+ 推荐的内存配置方式是在 jvm.options.d 目录下创建覆盖文件,文件名可以是任意 .options 后缀的文件
sudo vim /etc/elasticsearch/jvm.options

-Xms512m
-Xmx512m

3. Kibana

sudo apt install -y kibana=8.13.*

4. Logstash

sudo apt install -y logstash=1:8.13.*

5. Filebeat

sudo apt install -y filebeat=8.13.*

6. 基本配置

Elasticsearch 配置

sudo vim /etc/elasticsearch/elasticsearch.yml

修改以下配置

# ======================== Elasticsearch 配置 (单机测试版) =========================

# ---------------------------------- 集群与节点 -----------------------------------
# 集群名称
cluster.name: my-elk-stack
# 节点名称
node.name: node-1

# ----------------------------------- 路径 ------------------------------------
# 数据存储目录
path.data: /var/lib/elasticsearch
# 日志文件目录
path.logs: /var/log/elasticsearch

# ---------------------------------- 网络 -----------------------------------
# 监听所有网络接口的请求,这样Kibana和Logstash才能连接到它
# 如果你只想在本机访问,可以设置为 localhost
network.host: 0.0.0.0
# HTTP端口
http.port: 9200

# --------------------------------- 发现 ----------------------------------
# 对于单节点集群,这是最简单的发现配置
discovery.type: single-node

# ---------------------------------- 安全 -----------------------------------
# 完全禁用安全功能,方便测试
xpack.security.enabled: false
xpack.security.enrollment.enabled: false
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false

Kibana 配置

sudo vim /etc/kibana/kibana.yml

修改以下配置

# /etc/kibana/kibana.yml

# ---------------------------------- 服务器设置 -----------------------------------
# Kibana 服务端口
server.port: 5601

# 监听所有网络接口,这样你可以从任何地方访问 Kibana UI
# 如果你只想在本机通过 localhost:5601 访问,可以设置为 "localhost"
server.host: "0.0.0.0"

# 给你的 Kibana 实例起个名字,会显示在浏览器标签页上
server.name: "My Nginx Logs Dashboard"

# -------------------------------- Elasticsearch 连接 ---------------------------------
# 指定 Elasticsearch 的地址。因为安全功能已禁用,所以使用 http 协议。
# 如果 Kibana 和 Elasticsearch 在同一台服务器上,使用 localhost 是最佳选择。
elasticsearch.hosts: ["http://localhost:9200"]

# (可选) 设置请求超时时间,单位毫秒
# elasticsearch.requestTimeout: 30000

# ---------------------------------- 日志 -----------------------------------
# (可选) 如果你不想让日志打印到控制台,可以取消注释
# logging.dest: /var/log/kibana/kibana.log
# logging.quiet: true

# ---------------------------------- 语言 -----------------------------------
i18n.locale: "zh-CN"

Logstash 配置

创建一个简单的 Logstash 配置

sudo vim /etc/logstash/conf.d/01-test.conf

添加以下内容

# /etc/logstash/conf.d/02-nginx-pipeline.conf

# ============================ 输入 (Input) =============================
# 定义一个输入,监听来自 Beats (Filebeat) 的数据
input {
  beats {
    # Filebeat 连接到 Logstash 的端口
    port => 5044
  }
}

# ============================ 过滤器 (Filter) ============================
# Filebeat 的 Nginx 模块已经对日志进行了预处理和解析。
# 所以在这里,我们通常不需要再用 grok 等复杂插件进行解析。
# 这个 filter 块可以保持为空,或者用于添加一些自定义的字段。
filter {
  # 例如,可以添加一个标签
  # mutate {
  #   add_tag => [ "from_logstash" ]
  # }
}

# ============================ 输出 (Output) ==============================
# 定义数据发送到哪里
output {
  # 发送到 Elasticsearch
  elasticsearch {
    # Elasticsearch 的地址,同样使用 http
    hosts => ["http://localhost:9200"]
    
    # 索引名称。Filebeat 模块通常会自带 index 字段,
    # Logstash 会优先使用它。这里设置一个备用格式。
    # 变量 `[@metadata][beat]` 来自 Filebeat,通常是 "filebeat"。
    index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
  }
  
  # (可选, 用于调试) 在 Logstash 的控制台打印日志,方便查看数据是否正常接收
  # stdout {
  #   codec => rubydebug
  # }
}

Filebeat 配置

sudo vim /etc/filebeat/filebeat.yml

配置为收集系统日志

配置一

filebeat.inputs:

- type: filestream

  id: my-filestream-id

  enabled: false

  paths:
    - /var/log/*.log

filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml

  reload.enabled: false


setup.template.settings:
  index.number_of_shards: 1

# setup.kibana:

output.elasticsearch:
  hosts: ["localhost:9200"]
  preset: balanced
  indices:
    - index: "ibs-portal-%{+yyyy.MM.dd}"
      when.equals:
        fields.log_index: "ibs-portal"

processors:
  - add_host_metadata:
      when.not.contains.tags: forwarded
  - add_cloud_metadata: ~
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~


filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /opt/MyLogs/monitorJsonLog.log
    - /opt/MyLogs/noticeAlarmLog.log
  fields:
    log_index: "ibs-portal"

setup.kibana:
  host: "localhost:5601"

配置二(Ng 采集)

filebeat 模块启用查询

sudo filebeat modules list

启用 Nginx 模块

sudo filebeat modules enable nginx

配置 Nginx 模块

sudo vim /etc/filebeat/modules.d/nginx.yml

修改文件内容如下:

# /etc/filebeat/modules.d/nginx.yml

- module: nginx
  # Nginx access log
  access:
    enabled: true
    # !! 重要:修改为你服务器上 Nginx access 日志的实际路径 !!
    # 使用 * 通配符可以匹配日志轮转后的文件,如 access.log, access.log.1
    var.paths: ["/var/log/nginx/access.log*"]

  # Nginx error log
  error:
    enabled: true
    # !! 重要:修改为你服务器上 Nginx error 日志的实际路径 !!
    var.paths: ["/var/log/nginx/error.log*"]

配置 Filebeat 主文件,让 Filebeat 把数据发送给 Logstash,而不是直接发给 Elasticsearch。

sudo vim /etc/filebeat/filebeat.yml

找到 output 部分,进行如下修改:

# /etc/filebeat/filebeat.yml

# ... (其他 filebeat.inputs 部分可以保持默认或注释掉) ...
# filebeat.inputs:
# - type: filestream
# ...

# ================================== Outputs ===================================

# ---------------------------- Elasticsearch Output ----------------------------
# !! 重要:注释掉整个 Elasticsearch output 部分 !!
# 我们不希望 Filebeat 直接连接 Elasticsearch,而是通过 Logstash。
# output.elasticsearch:
#   hosts: ["localhost:9200"]

# ------------------------------ Logstash Output -------------------------------
# !! 重要:取消注释并配置 Logstash output 部分 !!
output.logstash:
  # Logstash 服务器的地址和端口 (与 Logstash input 配置中一致)
  hosts: ["localhost:5044"]

# ... (其他设置保持默认) ...

测试配置和运行

# 测试配置文件
sudo filebeat test config

# 测试 Elasticsearch 连接(如果使用 ES 输出)
sudo filebeat test output

# 加载索引模板
sudo filebeat setup --index-management -E output.logstash.enabled=false -E 'output.elasticsearch.hosts=["localhost:9200"]'

加载索引模板主要功能说明:

  1. --index-management - 设置索引生命周期管理 (ILM) 策略
  2. 创建索引模板 - 定义字段映射和设置
  3. 创建 Kibana 仪表板 - 预制的可视化界面
  4. 设置采集端点 - 配置数据采集管道

7. 启动服务并验证

启动

sudo systemctl enable elasticsearch kibana logstash filebeat

sudo systemctl start elasticsearch

sudo systemctl start kibana

sudo systemctl start logstash

sudo systemctl start filebeat

验证

# 检查每个服务的状态
sudo systemctl status elasticsearch
sudo systemctl status kibana
sudo systemctl status logstash
sudo systemctl status filebeat

# 检查 Elasticsearch 是否正常运行
curl -X GET http://localhost:9200

访问 Kibana

在浏览器中访问:http://192.168.126.100:5601

如果启用了安全功能,使用 elastic 用户和安装时提供的密码登录。

8. Elasticsearch 命令参考

获取所有索引

GET /_cat/indices?v

查询特定索引中的所有文档

GET ibs/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "@timestamp": {
        "order": "desc"
      }
    }
  ],
  "size": 20
}

搜索消息中包含特定关键词的文档

GET ibs-portal-2025.04.18/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "message": "话单" }},
        { "match": { "message": "查询" }},
        { "match": { "message": "通话记录" }},
        { "match": { "message": "CDR" }},
        { "match": { "message": "billing" }}
      ]
    }
  },
  "sort": [{ "@timestamp": { "order": "desc" }}],
  "size": 20
}

从特定日志文件中搜索文档

GET ibs-portal-2025.04.18/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "terms": {
            "log.file.path.keyword": [ "/opt/MyLogs/noticeAlarmLog.log" ]
          }
        }
      ]
    }
  },
  "sort": [
    {
      "@timestamp": {
        "order": "desc"
      }
    }
  ],
  "size": 20
}

创建具有特定设置和映射的新索引

PUT /ibs-portal
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "field1": {
        "type": "text"
      },
      "field2": {
        "type": "keyword"
      },
      "@timestamp": {
        "type": "date"
      }
    }
  }
}

9. 生成测试的 Nginx 日志

创建测试脚本来生成各种 HTTP 状态码的请求:

# 创建测试脚本
sudo tee /tmp/generate_nginx_test_logs.sh << 'EOF'
#!/bin/bash
NGINX_LOG_DIR="/var/log/nginx"
NGINX_ACCESS_LOG="$NGINX_LOG_DIR/access.log"

# 确保日志目录存在
sudo mkdir -p $NGINX_LOG_DIR

# 生成测试日志条目的函数
generate_log_entry() {
    local method=$1
    local status=$2
    local path=$3
    local timestamp=$(date '+%d/%b/%Y:%H:%M:%S %z')
    local ip="192.168.1.$((RANDOM % 255))"
    local user_agent="Mozilla/5.0 (Test User Agent)"
    local response_size=$((RANDOM % 5000 + 100))
    
    # Nginx 标准日志格式
    echo "$ip - - [$timestamp] \"$method $path HTTP/1.1\" $status $response_size \"-\" \"$user_agent\""
}

# 清空现有日志(可选)
# sudo truncate -s 0 $NGINX_ACCESS_LOG

# 生成各种测试日志
echo "生成测试 Nginx 访问日志..."

# 正常请求 (200)
for i in {1..5}; do
    generate_log_entry "GET" "200" "/index.html" | sudo tee -a $NGINX_ACCESS_LOG
    generate_log_entry "POST" "200" "/api/login" | sudo tee -a $NGINX_ACCESS_LOG
    generate_log_entry "GET" "200" "/images/logo.png" | sudo tee -a $NGINX_ACCESS_LOG
done

# 404 错误
for i in {1..3}; do
    generate_log_entry "GET" "404" "/nonexistent-page.html" | sudo tee -a $NGINX_ACCESS_LOG
    generate_log_entry "POST" "404" "/api/invalid-endpoint" | sudo tee -a $NGINX_ACCESS_LOG
done

# 500 错误
for i in {1..2}; do
    generate_log_entry "GET" "500" "/api/crash" | sudo tee -a $NGINX_ACCESS_LOG
    generate_log_entry "POST" "500" "/api/error" | sudo tee -a $NGINX_ACCESS_LOG
done

# 其他状态码
generate_log_entry "GET" "301" "/old-page" | sudo tee -a $NGINX_ACCESS_LOG
generate_log_entry "GET" "403" "/admin" | sudo tee -a $NGINX_ACCESS_LOG

echo "测试日志生成完成!"
echo "日志文件位置: $NGINX_ACCESS_LOG"
echo "内容示例:"
sudo tail -5 $NGINX_ACCESS_LOG
EOF

# 给脚本执行权限并运行
sudo chmod +x /tmp/generate_nginx_test_logs.sh
sudo /tmp/generate_nginx_test_logs.sh

10. ELK 脚本

#!/bin/bash

# ==============================================================================
# ELK Stack (Elasticsearch, Kibana, Logstash, Filebeat) 一键安装脚本
#
# 支持系统: Ubuntu 24.04 LTS
# 目标版本: ELK v8.7.*
#
# 使用方法:
# 1. 保存此脚本为 install_elk_stack.sh
# 2. chmod +x install_elk_stack.sh
# 3. sudo ./install_elk_stack.sh
# ==============================================================================

# --- 配置段 ---
ELK_VERSION="8.7.*"
LOGSTASH_VERSION="1:8.7.*"

# --- 脚本设置 ---
# -e: 当命令失败时,立即退出脚本
# -u: 当使用未定义的变量时,立即退出脚本
# -o pipefail: 管道中的任何命令失败,整个管道都视为失败
set -euo pipefail

# --- 颜色定义 ---
readonly C_RESET='\033[0m'
readonly C_RED='\033[0;31m'
readonly C_GREEN='\033[0;32m'
readonly C_YELLOW='\033[0;33m'
readonly C_BLUE='\033[0;34m'

# --- 日志函数 ---
log_info() {
    echo -e "${C_BLUE}[INFO] $1${C_RESET}"
}

log_success() {
    echo -e "${C_GREEN}[SUCCESS] $1${C_RESET}"
}

log_warn() {
    echo -e "${C_YELLOW}[WARNING] $1${C_RESET}"
}

log_error() {
    echo -e "${C_RED}[ERROR] $1${C_RESET}" >&2
    exit 1
}

# --- 权限检查 ---
check_root() {
    if [ "$(id -u)" -ne 0 ]; then
        log_error "此脚本需要以 root 权限运行。请使用 'sudo ./install_elk_stack.sh'"
    fi
}

# --- 1. 环境准备 ---
prepare_environment() {
    log_info "1. 开始准备系统环境..."

    log_info "安装必要的依赖..."
    apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg

    log_info "提高 Elasticsearch 的文件描述符限制..."
    local limits_conf="/etc/security/limits.conf"
    if ! grep -q "elasticsearch soft nofile 65535" "$limits_conf"; then
        echo "elasticsearch soft nofile 65535" >> "$limits_conf"
        echo "elasticsearch hard nofile 65535" >> "$limits_conf"
        log_success "文件描述符限制已设置。"
    else
        log_info "文件描述符限制已存在,跳过设置。"
    fi
}

# --- 2. 添加 Elastic 官方仓库 ---
add_elastic_repo() {
    log_info "2. 添加 Elastic 官方 APT 仓库..."
    
    local key_path="/usr/share/keyrings/elasticsearch-keyring.gpg"
    local repo_path="/etc/apt/sources.list.d/elastic-8.x.list"

    if [ ! -f "$key_path" ]; then
        log_info "添加 Elastic GPG 密钥..."
        curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor -o "$key_path"
    else
        log_info "Elastic GPG 密钥已存在,跳过。"
    fi

    if [ ! -f "$repo_path" ]; then
        log_info "添加 Elastic 仓库源..."
        echo "deb [signed-by=$key_path] https://artifacts.elastic.co/packages/8.x/apt stable main" | tee "$repo_path" > /dev/null
    else
        log_info "Elastic 仓库源已存在,跳过。"
    fi

    log_info "更新 APT 软件包列表..."
    apt update
}

# --- 3. 安装和配置组件 ---
install_components() {
    log_info "3. 开始安装 ELK 组件..."

    # 安装 Elasticsearch
    log_info "正在安装 Elasticsearch v${ELK_VERSION}..."
    apt install -y "elasticsearch=${ELK_VERSION}"
    log_success "Elasticsearch 安装完成。"

    log_warn "=========================== 重要提示 ==========================="
    log_warn "Elasticsearch 安装过程已自动生成密码和令牌。"
    log_warn "================================================================"
    # 增加一个短暂的暂停,让用户有时间看到这个重要信息
    sleep 5

    log_info "调整 Elasticsearch JVM 堆内存为 512m..."
    local jvm_options_dir="/etc/elasticsearch/jvm.options.d"
    mkdir -p "$jvm_options_dir"
    cat <<EOF > "${jvm_options_dir}/heap_size.options"
-Xms512m
-Xmx512m
EOF
    log_success "JVM 堆内存已配置。"

    # 安装 Kibana
    log_info "正在安装 Kibana v${ELK_VERSION}..."
    apt install -y "kibana=${ELK_VERSION}"
    log_success "Kibana 安装完成。"

    # 安装 Logstash
    log_info "正在安装 Logstash v${LOGSTASH_VERSION}..."
    apt install -y "logstash=${LOGSTASH_VERSION}"
    log_success "Logstash 安装完成。"

    # 安装 Filebeat
    log_info "正在安装 Filebeat v${ELK_VERSION}..."
    apt install -y "filebeat=${ELK_VERSION}"
    log_success "Filebeat 安装完成。"
}

# --- 4. 配置 Elasticsearch ---
configure_elasticsearch() {
    log_info "4. 配置 Elasticsearch..."

    local es_config="/etc/elasticsearch/elasticsearch.yml"
    local es_backup="${es_config}.backup.$(date +%Y%m%d_%H%M%S)"

    # 备份原配置文件
    if [ -f "$es_config" ]; then
        log_info "备份原配置文件到: ${es_backup}"
        cp "$es_config" "$es_backup"
    fi

    # 写入新的配置文件(完全覆盖)
    log_info "写入 Elasticsearch 配置..."
    cat > "$es_config" <<'EOF'
# ======================== Elasticsearch 配置 (单机测试版) =========================

# ---------------------------------- 集群与节点 -----------------------------------
# 集群名称
cluster.name: my-elk-stack
# 节点名称
node.name: node-1

# ----------------------------------- 路径 ------------------------------------
# 数据存储目录
path.data: /var/lib/elasticsearch
# 日志文件目录
path.logs: /var/log/elasticsearch

# ---------------------------------- 网络 -----------------------------------
# 监听所有网络接口的请求,这样Kibana和Logstash才能连接到它
# 如果你只想在本机访问,可以设置为 localhost
network.host: 0.0.0.0
# HTTP端口
http.port: 9200

# --------------------------------- 发现 ----------------------------------
# 对于单节点集群,这是最简单的发现配置
discovery.type: single-node

# ---------------------------------- 安全 -----------------------------------
# 完全禁用安全功能,方便测试
xpack.security.enabled: false
xpack.security.enrollment.enabled: false
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false
EOF

    log_success "Elasticsearch 配置完成。备份文件: ${es_backup}"
}

# --- 5. 配置 Kibana ---
configure_kibana() {
    log_info "5. 配置 Kibana..."

    local kibana_config="/etc/kibana/kibana.yml"
    local kibana_backup="${kibana_config}.backup.$(date +%Y%m%d_%H%M%S)"

    # 备份原配置文件
    if [ -f "$kibana_config" ]; then
        log_info "备份原配置文件到: ${kibana_backup}"
        cp "$kibana_config" "$kibana_backup"
    fi

    # 写入新的配置文件(完全覆盖)
    log_info "写入 Kibana 配置..."
    cat > "$kibana_config" <<'EOF'
# /etc/kibana/kibana.yml

# ---------------------------------- 服务器设置 -----------------------------------
# Kibana 服务端口
server.port: 5601

# 监听所有网络接口,这样你可以从任何地方访问 Kibana UI
# 如果你只想在本机通过 localhost:5601 访问,可以设置为 "localhost"
server.host: "0.0.0.0"

# 给你的 Kibana 实例起个名字,会显示在浏览器标签页上
server.name: "My Nginx Logs Dashboard"

# -------------------------------- Elasticsearch 连接 ---------------------------------
# 指定 Elasticsearch 的地址。因为安全功能已禁用,所以使用 http 协议。
# 如果 Kibana 和 Elasticsearch 在同一台服务器上,使用 localhost 是最佳选择。
elasticsearch.hosts: ["http://localhost:9200"]

# (可选) 设置请求超时时间,单位毫秒
# elasticsearch.requestTimeout: 30000

# ---------------------------------- 日志 -----------------------------------
# (可选) 如果你不想让日志打印到控制台,可以取消注释
# logging.dest: /var/log/kibana/kibana.log
# logging.quiet: true

# ---------------------------------- 语言 -----------------------------------
i18n.locale: "zh-CN"
EOF

    log_success "Kibana 配置完成。备份文件: ${kibana_backup}"
}

# --- 6. 配置 Logstash ---
configure_logstash() {
    log_info "6. 配置 Logstash..."

    local logstash_conf_dir="/etc/logstash/conf.d"
    local logstash_pipeline="${logstash_conf_dir}/02-nginx-pipeline.conf"

    # 确保配置目录存在
    mkdir -p "$logstash_conf_dir"

    # 创建 Logstash pipeline 配置文件(新建,无需备份)
    log_info "创建 Logstash pipeline 配置文件..."
    cat > "$logstash_pipeline" <<'EOF'
# /etc/logstash/conf.d/02-nginx-pipeline.conf

# ============================ 输入 (Input) =============================
# 定义一个输入,监听来自 Beats (Filebeat) 的数据
input {
  beats {
    # Filebeat 连接到 Logstash 的端口
    port => 5044
  }
}

# ============================ 过滤器 (Filter) ============================
# Filebeat 的 Nginx 模块已经对日志进行了预处理和解析。
# 所以在这里,我们通常不需要再用 grok 等复杂插件进行解析。
# 这个 filter 块可以保持为空,或者用于添加一些自定义的字段。
filter {
  # 例如,可以添加一个标签
  # mutate {
  #   add_tag => [ "from_logstash" ]
  # }
}

# ============================ 输出 (Output) ==============================
# 定义数据发送到哪里
output {
  # 发送到 Elasticsearch
  elasticsearch {
    # Elasticsearch 的地址,同样使用 http
    hosts => ["http://localhost:9200"]

    # 索引名称。Filebeat 模块通常会自带 index 字段,
    # Logstash 会优先使用它。这里设置一个备用格式。
    # 变量 `[@metadata][beat]` 来自 Filebeat,通常是 "filebeat"。
    index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
  }

  # (可选, 用于调试) 在 Logstash 的控制台打印日志,方便查看数据是否正常接收
  # stdout {
  #   codec => rubydebug
  # }
}
EOF

    log_success "Logstash 配置完成。配置文件: ${logstash_pipeline}"
}

# --- 7. 启动和启用服务 ---
enable_and_start_services() {
    log_info "7. 启动和启用 ELK 服务..."

    # 启用开机自启动
    log_info "设置服务开机自启动..."
    systemctl enable elasticsearch.service
    systemctl enable kibana.service
    systemctl enable logstash.service
    log_success "服务已设置为开机自启动。"

    # 启动服务
    log_info "启动 Elasticsearch..."
    systemctl start elasticsearch.service
    log_success "Elasticsearch 已启动。"

    log_info "启动 Kibana..."
    systemctl start kibana.service
    log_success "Kibana 已启动。"

    log_info "启动 Logstash..."
    systemctl start logstash.service
    log_success "Logstash 已启动。"

    # 等待服务启动
    log_info "等待服务完全启动(15秒)..."
    sleep 15
}

# --- 8. 检查服务状态 ---
check_services_status() {
    log_info "8. 检查服务状态..."

    echo ""
    log_info "========== Elasticsearch 状态 =========="
    systemctl status elasticsearch.service --no-pager -l || true

    echo ""
    log_info "========== Kibana 状态 =========="
    systemctl status kibana.service --no-pager -l || true

    echo ""
    log_info "========== Logstash 状态 =========="
    systemctl status logstash.service --no-pager -l || true

    echo ""
    log_info "========== Elasticsearch 健康检查 =========="
    if curl -s http://localhost:9200 > /dev/null 2>&1; then
        curl -s http://localhost:9200
        log_success "Elasticsearch HTTP 接口响应正常。"
    else
        log_warn "Elasticsearch HTTP 接口未响应,可能还在启动中。"
    fi
}

# --- 9. 显示最终信息 ---
show_final_message() {
    echo ""
    echo ""
    log_success "=========================================="
    log_success "  ELK Stack 安装和配置完成!"
    log_success "=========================================="
    echo ""
    log_info "已安装组件:"
    echo "  - Elasticsearch ${ELK_VERSION}"
    echo "  - Kibana ${ELK_VERSION}"
    echo "  - Logstash ${LOGSTASH_VERSION}"
    echo "  - Filebeat ${ELK_VERSION}"
    echo ""
    log_info "服务访问地址:"
    echo "  - Elasticsearch: http://localhost:9200"
    echo "  - Kibana UI:     http://localhost:5601"
    echo "  - Logstash Beats: localhost:5044"
    echo ""
    log_info "配置文件位置:"
    echo "  - Elasticsearch: /etc/elasticsearch/elasticsearch.yml"
    echo "  - Kibana:        /etc/kibana/kibana.yml"
    echo "  - Logstash:      /etc/logstash/conf.d/02-nginx-pipeline.conf"
    echo ""
    log_info "备份文件位置:"
    echo "  - 原配置文件已备份到 *.backup.YYYYMMDD_HHMMSS"
    echo ""
    log_info "常用管理命令:"
    echo "  - 查看服务状态: sudo systemctl status elasticsearch|kibana|logstash"
    echo "  - 重启服务:     sudo systemctl restart elasticsearch|kibana|logstash"
    echo "  - 查看日志:     sudo journalctl -u elasticsearch|kibana|logstash -f"
    echo ""
    log_warn "注意事项:"
    echo "  1. 所有服务已设置为开机自启动"
    echo "  2. 安全功能已禁用,仅适用于测试环境"
    echo "  3. 生产环境请务必启用安全功能"
    echo ""
}

# --- 主函数 ---
main() {
    check_root
    prepare_environment
    add_elastic_repo
    install_components
    configure_elasticsearch
    configure_kibana
    configure_logstash
    enable_and_start_services
    check_services_status
    show_final_message
}

# --- 脚本执行入口 ---
main "$@"