#!/bin/bash # 定义变量 CONTAINER_NAME="elasticsearch" IMAGE_NAME="elasticsearch:7.17.28" # 镜像版本 DATA_DIR="/docker-data/elasticsearch/data" # 数据目录 CONFIG_DIR="/docker-data/elasticsearch/config" # 配置目录 LOGS_DIR="/docker-data/elasticsearch/logs" # 日志目录 HTTP_PORT=9200 # HTTP端口 TRANSPORT_PORT=9300 # 内部通信端口 CLUSTER_NAME="es-single-cluster" # 集群名称 NODE_NAME="single-node" # 节点名称 ES_JAVA_OPTS="-Xms1g -Xmx1g" # JVM内存(根据主机内存调整) # 显示帮助信息 show_help() { echo "使用方法: $0 [操作类型]" echo "操作类型:" echo " deploy - 部署并启动单机模式Elasticsearch" echo " remove - 停止并删除容器及数据目录" echo " logs - 查看容器日志" echo " status - 查看容器状态" echo " help - 显示帮助信息" } # 准备环境(创建目录和配置文件) prepare_env() { # 创建数据、配置、日志目录并授权 for dir in "$DATA_DIR" "$CONFIG_DIR" "$LOGS_DIR"; do if [ ! -d "$dir" ]; then echo "创建目录: $dir" mkdir -p "$dir" fi chown -R 1000:1000 "$dir" # 匹配容器内用户UID/GID chmod 755 "$dir" done # 生成单机模式配置文件(若不存在) if [ ! -f "$CONFIG_DIR/elasticsearch.yml" ]; then echo "生成单机模式配置文件: $CONFIG_DIR/elasticsearch.yml" cat > "$CONFIG_DIR/elasticsearch.yml" << EOF cluster.name: es-single-cluster node.name: single-node network.host: 0.0.0.0 http.port: 9200 transport.port: 9300 discovery.type: single-node # 单机模式核心配置(必须保留) # 以下行必须删除或注释掉(与single-node冲突) # cluster.initial_master_nodes: ["single-node"] xpack.security.enabled: false http.cors.enabled: true http.cors.allow-origin: "*" bootstrap.memory_lock: true ingest.geoip.downloader.enabled: false EOF fi # 配置JVM参数(若不存在) if [ ! -f "$CONFIG_DIR/jvm.options" ]; then echo "生成JVM配置文件: $CONFIG_DIR/jvm.options" # 修正后代码(拆分参数为两行) cat > "$CONFIG_DIR/jvm.options" << EOF -Xms1g -Xmx1g # 保留其他默认配置(如下) -XX:+UseG1GC -XX:MaxGCPauseMillis=50 -XX:+HeapDumpOnOutOfMemoryError 8-13:-XX:+UseConcMarkSweepGC 8-13:-XX:CMSInitiatingOccupancyFraction=75 8-13:-XX:+UseCMSInitiatingOccupancyOnly 14-:-XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError 9-:-XX:+ExitOnOutOfMemoryError -XX:HeapDumpPath=data -XX:ErrorFile=logs/hs_err_pid%p.log 8:-XX:+PrintGCDetails 8:-XX:+PrintGCDateStamps 8:-XX:+PrintTenuringDistribution 8:-XX:+PrintGCApplicationStoppedTime 8:-Xloggc:logs/gc.log 8:-XX:+UseGCLogFileRotation 8:-XX:NumberOfGCLogFiles=32 8:-XX:GCLogFileSize=64m # JDK 9+ GC logging 9-:-Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m EOF fi } # 检查系统配置(解决vm.max_map_count问题) check_sys_config() { current_map_count=$(sysctl -n vm.max_map_count) if [ $current_map_count -lt 262144 ]; then echo "检测到vm.max_map_count值不足,需要调整..." if [ "$(id -u)" -ne 0 ]; then echo "请使用sudo权限运行脚本,或手动执行:" echo "sudo sysctl -w vm.max_map_count=262144" echo "并在/etc/sysctl.conf中添加:vm.max_map_count=262144" exit 1 fi # 临时调整 sysctl -w vm.max_map_count=262144 # 永久生效 if ! grep -q "vm.max_map_count=262144" /etc/sysctl.conf; then echo "vm.max_map_count=262144" >> /etc/sysctl.conf fi fi } # 部署启动 deploy_es() { check_sys_config # 先检查系统配置 prepare_env # 准备目录和配置 # 停止并删除现有容器 if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then echo "停止并删除现有容器: $CONTAINER_NAME" docker stop $CONTAINER_NAME docker rm $CONTAINER_NAME fi # 启动单机模式容器 echo "启动Elasticsearch单机模式..." docker run -d --privileged \ --name $CONTAINER_NAME \ --restart always \ --ulimit nofile=65536:65536 \ --ulimit nproc=4096:4096 \ --ulimit memlock=-1:-1 \ -p $HTTP_PORT:9200 \ -p $TRANSPORT_PORT:9300 \ -v $DATA_DIR:/usr/share/elasticsearch/data \ -v $CONFIG_DIR/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \ -v $LOGS_DIR:/usr/share/elasticsearch/logs \ -e TZ=Asia/Shanghai \ $IMAGE_NAME # 检查启动状态 if [ "$(docker ps -aq -f name=$CONTAINER_NAME -f status=running)" ]; then echo "Elasticsearch单机模式启动成功!" echo "访问地址: http://localhost:$HTTP_PORT" echo "集群名称: $CLUSTER_NAME" echo "JVM配置: $ES_JAVA_OPTS" else echo "启动失败,请查看日志: ./$0 logs" docker logs $CONTAINER_NAME fi } # 移除容器和数据 remove_es() { if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then echo "停止容器: $CONTAINER_NAME" docker stop $CONTAINER_NAME echo "删除容器: $CONTAINER_NAME" docker rm $CONTAINER_NAME else echo "容器 $CONTAINER_NAME 不存在" fi # 询问是否删除数据目录 for dir in "$DATA_DIR" "$CONFIG_DIR" "$LOGS_DIR"; do if [ -d "$dir" ]; then read -p "是否删除目录 $dir? (y/n) " confirm if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then echo "删除目录: $dir" rm -rf "$dir" else echo "保留目录: $dir" fi fi done } # 查看日志 show_logs() { if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then echo "查看Elasticsearch日志(按Ctrl+C退出)..." docker logs -f $CONTAINER_NAME else echo "容器 $CONTAINER_NAME 不存在" fi } # 查看状态 show_status() { echo "容器状态:" docker ps -f name=$CONTAINER_NAME --format "表格:{{.Names}} {{.Status}} {{.Ports}}" if [ "$(docker ps -aq -f name=$CONTAINER_NAME -f status=running)" ]; then echo "服务健康检查:" curl -s "http://localhost:$HTTP_PORT/_cluster/health" | jq . fi } # 主逻辑 if [ $# -ne 1 ]; then show_help exit 1 fi case "$1" in deploy) deploy_es ;; remove) remove_es ;; logs) show_logs ;; status) show_status ;; help) show_help ;; *) echo "无效操作: $1" show_help exit 1 ;; esac