在docker环境部署Elasticsearch + Kibana 9.5.1集群
# 注意 本文档由workbuddy+hy3生成,配置文件也是它改造,对官网原版做了部分优化。实现了单云主机场景部署Elasticsearch集群。排除了官网原版部署文件的缺陷。 感谢workbuddy和hy3的给力支持。 # Elasticsearch + Kibana Docker 生产部署说明 > 基于官方文档 [Install Elasticsearch with Docker](https://www.elastic.co/docs/deploy-manage/deploy/self-managed/install-elasticsearch-with-docker) 整理的生产级单主机部署方案。`docker-compose.yml` 不含注释,所有配置说明见下方「配置」一节。 --- ## 说明 本目录用于 **单台主机(云主机 / 物理机 / 本地 Docker 环境)** 部署 Elasticsearch 集群与 Kibana,包含三个文件: - `docker-compose.yml`:服务编排(纯配置,无注释) ```bash services: setup: image: ${ES_IMAGE} container_name: elk-setup volumes: - certs:/usr/share/elasticsearch/config/certs user: "0" command: > bash -c ' if [ x${ELASTIC_PASSWORD} == x ]; then echo "Set the ELASTIC_PASSWORD environment variable in the .env file"; exit 1; elif [ x${KIBANA_PASSWORD} == x ]; then echo "Set the KIBANA_PASSWORD environment variable in the .env file"; exit 1; fi; if [ ! -f config/certs/ca.zip ]; then echo "Creating CA"; bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip; unzip config/certs/ca.zip -d config/certs; fi; if [ ! -f config/certs/certs.zip ]; then echo "Creating certs"; echo -ne \ "instances:\n"\ " - name: es01\n"\ " dns:\n"\ " - es01\n"\ " - localhost\n"\ " ip:\n"\ " - 127.0.0.1\n"\ " - name: es02\n"\ " dns:\n"\ " - es02\n"\ " - localhost\n"\ " ip:\n"\ " - 127.0.0.1\n"\ " - name: es03\n"\ " dns:\n"\ " - es03\n"\ " - localhost\n"\ " ip:\n"\ " - 127.0.0.1\n"\ > config/certs/instances.yml; bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key; unzip config/certs/certs.zip -d config/certs; fi; echo "Setting file permissions"; chown -R root:root config/certs; find . -type d -exec chmod 750 \{\} \;; find . -type f -exec chmod 640 \{\} \;; echo "Waiting for Elasticsearch availability"; until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done; echo "Setting kibana_system password"; until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done; echo "All done!"; ' healthcheck: test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"] interval: 1s timeout: 5s retries: 120 networks: - elastic restart: "no" es01: depends_on: setup: condition: service_healthy image: ${ES_IMAGE} container_name: elk-es01 volumes: - certs:/usr/share/elasticsearch/config/certs - esdata01:/usr/share/elasticsearch/data ports: - ${ES_PORT}:9200 environment: - node.name=es01 - cluster.name=${CLUSTER_NAME} - cluster.initial_master_nodes=es01,es02,es03 - discovery.seed_hosts=es02,es03 - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - bootstrap.memory_lock=true - "ES_JAVA_OPTS=${ES_JAVA_OPTS}" - xpack.security.enabled=true - xpack.security.http.ssl.enabled=true - xpack.security.http.ssl.key=certs/es01/es01.key - xpack.security.http.ssl.certificate=certs/es01/es01.crt - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt - xpack.security.transport.ssl.enabled=true - xpack.security.transport.ssl.key=certs/es01/es01.key - xpack.security.transport.ssl.certificate=certs/es01/es01.crt - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt - xpack.security.transport.ssl.verification_mode=certificate - xpack.license.self_generated.type=${LICENSE} - xpack.ml.use_auto_machine_memory_percent=true mem_limit: ${MEM_LIMIT} ulimits: memlock: soft: -1 hard: -1 nofile: soft: 65535 hard: 65535 healthcheck: test: [ "CMD-SHELL", "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", ] interval: 10s timeout: 10s retries: 120 networks: - elastic restart: unless-stopped es02: depends_on: - es01 image: ${ES_IMAGE} container_name: elk-es02 volumes: - certs:/usr/share/elasticsearch/config/certs - esdata02:/usr/share/elasticsearch/data environment: - node.name=es02 - cluster.name=${CLUSTER_NAME} - cluster.initial_master_nodes=es01,es02,es03 - discovery.seed_hosts=es01,es03 - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - bootstrap.memory_lock=true - "ES_JAVA_OPTS=${ES_JAVA_OPTS}" - xpack.security.enabled=true - xpack.security.http.ssl.enabled=true - xpack.security.http.ssl.key=certs/es02/es02.key - xpack.security.http.ssl.certificate=certs/es02/es02.crt - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt - xpack.security.transport.ssl.enabled=true - xpack.security.transport.ssl.key=certs/es02/es02.key - xpack.security.transport.ssl.certificate=certs/es02/es02.crt - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt - xpack.security.transport.ssl.verification_mode=certificate - xpack.license.self_generated.type=${LICENSE} - xpack.ml.use_auto_machine_memory_percent=true mem_limit: ${MEM_LIMIT} ulimits: memlock: soft: -1 hard: -1 nofile: soft: 65535 hard: 65535 healthcheck: test: [ "CMD-SHELL", "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", ] interval: 10s timeout: 10s retries: 120 networks: - elastic restart: unless-stopped es03: depends_on: - es02 image: ${ES_IMAGE} container_name: elk-es03 volumes: - certs:/usr/share/elasticsearch/config/certs - esdata03:/usr/share/elasticsearch/data environment: - node.name=es03 - cluster.name=${CLUSTER_NAME} - cluster.initial_master_nodes=es01,es02,es03 - discovery.seed_hosts=es01,es02 - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - bootstrap.memory_lock=true - "ES_JAVA_OPTS=${ES_JAVA_OPTS}" - xpack.security.enabled=true - xpack.security.http.ssl.enabled=true - xpack.security.http.ssl.key=certs/es03/es03.key - xpack.security.http.ssl.certificate=certs/es03/es03.crt - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt - xpack.security.transport.ssl.enabled=true - xpack.security.transport.ssl.key=certs/es03/es03.key - xpack.security.transport.ssl.certificate=certs/es03/es03.crt - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt - xpack.security.transport.ssl.verification_mode=certificate - xpack.license.self_generated.type=${LICENSE} - xpack.ml.use_auto_machine_memory_percent=true mem_limit: ${MEM_LIMIT} ulimits: memlock: soft: -1 hard: -1 nofile: soft: 65535 hard: 65535 healthcheck: test: [ "CMD-SHELL", "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", ] interval: 10s timeout: 10s retries: 120 networks: - elastic restart: unless-stopped kibana: depends_on: es01: condition: service_healthy es02: condition: service_healthy es03: condition: service_healthy image: ${KIBANA_IMAGE} container_name: elk-kibana volumes: - certs:/usr/share/kibana/config/certs - kibanadata:/usr/share/kibana/data ports: - ${KIBANA_PORT}:5601 environment: - SERVERNAME=kibana - 'ELASTICSEARCH_HOSTS=["https://es01:9200","https://es02:9200","https://es03:9200"]' - ELASTICSEARCH_USERNAME=kibana_system - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD} - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt mem_limit: ${KIBANA_MEM_LIMIT} healthcheck: test: [ "CMD-SHELL", "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'", ] interval: 10s timeout: 10s retries: 120 networks: - elastic restart: unless-stopped volumes: certs: driver: local name: elk_certs esdata01: driver: local name: elk_esdata01 esdata02: driver: local name: elk_esdata02 esdata03: driver: local name: elk_esdata03 kibanadata: driver: local name: elk_kibanadata networks: elastic: driver: bridge name: elk_network ``` - `.env`:所有可调整变量 ```bash # ============================================================================= # Elasticsearch + Kibana 生产环境 — Docker Compose 变量定义 # 参考: https://www.elastic.co/docs/deploy-manage/deploy/self-managed/install-elasticsearch-with-docker # # 使用: 本文件与 docker-compose.yml 放在同一目录 (建议 ./docker) # 修改后重新执行: docker compose up -d # 注意: .env 含凭据占位符, 生产请替换为强密码, 且不要提交到公开仓库。 # ============================================================================= # ----------------------------------------------------------------------------- # 1) 安全凭据 (必填; 已预生成 24 位强密码, 生产可替换) # 复杂度: 混合大小写字母 + 数字 + 符号, 熵极高。 # 注意: 为避免 compose 内 setup 脚本与 curl 解析出错, 密码请勿含 # 单引号 ' 、双引号 " 、反引号 ` 、美元符 $ 、@ 、冒号 : 、反斜杠 \ 、# 与空格。 # ----------------------------------------------------------------------------- # elastic 超级用户密码 (用于登录 Kibana / 调用 ES REST API) ELASTIC_PASSWORD=WGneErgFV-mR+E&oC?~,%xU5 # kibana_system 用户密码 (Kibana 内部连接 ES 使用, 不要用于登录) KIBANA_PASSWORD=Sy2v_c0j=.O-3,ZlVP0M?%AC # ----------------------------------------------------------------------------- # 2) 镜像仓库 (完整镜像名, 含 registry/repository:tag) # ----------------------------------------------------------------------------- # 容器镜像地址完整定义在 .env, 切换仓库 / 镜像名 / tag 只改这两行, 无需动 docker-compose.yml。 # 生产务必固定具体版本号, 严禁使用 latest (避免不可控升级)。 ES_IMAGE=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/elasticsearch:9.5.1 KIBANA_IMAGE=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/kibana:9.5.1 # 集群名称 (同一网络内容器以此相互发现, 多集群隔离时可改不同名) CLUSTER_NAME=es-docker-cluster # 许可证类型: # basic = 免费基础版 (默认, 已含安全/TLS/监控) # trial = 30 天试用, 解锁全部商业特性 (高级机器学习、告警等) LICENSE=basic # ----------------------------------------------------------------------------- # 3) 端口映射 (格式: 宿主机地址:容器端口) # ----------------------------------------------------------------------------- # Elasticsearch HTTP API 暴露给宿主机的地址。 # 生产强烈建议改为 127.0.0.1:9200 仅允许本机访问, 再经反向代理对外, # 避免 9200 直接暴露在公网。当前保持官方默认 (暴露所有网卡 0.0.0.0)。 # 示例: ES_PORT=127.0.0.1:9200 ES_PORT=9200 # Kibana Web 界面端口 (浏览器访问 http://:5601) KIBANA_PORT=5601 # ----------------------------------------------------------------------------- # 4) 资源限制 (务必按真实主机内存调整, 这是生产最关键的一项) # ----------------------------------------------------------------------------- # 每个容器内存硬上限 (单位: 字节 bytes, 不是 MB/GB)。 # 经验值: 容器上限 ≈ 主机内存 * 0.75, 其余留给 OS 与文件系统页缓存。 # 常用取值: # 4 GB 主机 -> 1 GB = 1073741824 (建议改单节点) # 8 GB 主机 -> 2 GB = 2147483648 4 GB = 4294967296 # 32 GB 主机 -> 8 GB = 8589934592 MEM_LIMIT=2147483648 # JVM 堆内存 (通过 ES_JAVA_OPTS 传入每个 ES 节点)。 # 生产黄金法则: 堆 ≈ 容器内存的一半, 且单个节点堆 1g/1g ; 16GB->2g/2g ; 32GB->4g/4g ES_JAVA_OPTS=-Xms1g -Xmx1g # Kibana 容器内存上限 (Kibana 不吃 JVM 堆, 1~2 GB 足够, 切勿复用 ES 的 MEM_LIMIT)。 # 8/16 GB 主机 -> 1 GB = 1073741824 ; 32 GB+ -> 2 GB = 2147483648 KIBANA_MEM_LIMIT=1073741824 # ----------------------------------------------------------------------------- # 5) 宿主机内核参数 (在宿主机执行, 不是容器变量, 但部署前必须做) # ----------------------------------------------------------------------------- # 生产必须设置 vm.max_map_count=1048576, 否则 ES 启动即失败。 # Linux: # sudo sysctl -w vm.max_map_count=1048576 # echo 'vm.max_map_count=1048576' | sudo tee -a /etc/sysctl.conf # 持久化 # Windows Docker Desktop (WSL2 后端): # wsl -d docker-desktop -u root sysctl -w vm.max_map_count=1048576 # # 持久化: 在 %USERPROFILE%\.wslconfig 增加一行: # # [wsl2] # # kernelCommandLine = "sysctl.vm.max_map_count=1048576" # 另外建议宿主机尽量禁用 swap; 本 compose 已启用 bootstrap.memory_lock=true # 锁定容器内存, 防止被交换到磁盘导致性能骤降。 # ----------------------------------------------------------------------------- # 6) 项目命名空间 (可选) # ----------------------------------------------------------------------------- # 自定义后, 所有容器/卷/网络名会带此前缀, 便于同一台机器跑多套隔离环境。 #COMPOSE_PROJECT_NAME=elasticsearch ``` - `README.md`:本文档 集群为 3 节点单主机架构:`setup` 初始化服务 + `es01/es02/es03` 数据主节点 + `kibana`。各服务职责与全部配置项的说明集中在下方「配置」一节。 --- ## 配置 ### 1. 服务与架构 |**服务**|**镜像**|**角色**|**说明**| | --- | --- | --- | --- | |`setup`|elasticsearch|一次性初始化|生成 CA 与节点 TLS 证书,并设置 `kibana_system` 密码;完成后退出,幂等可重跑| |`es01` / `es02` / `es03`|elasticsearch|数据 + 主节点|3 节点集群,全链路 TLS + 安全认证| |`kibana`|kibana|可视化界面|通过 `kibana_system` 用户连接 ES| `setup` 通过 `elasticsearch-certutil` 生成 CA 与每个节点的证书,写入共享 `certs` 卷;随后等待 ES 就绪并设置 `kibana_system` 密码。证书已存在时不会重复生成,因此可安全重复执行 `docker compose up`。 ### 2. 镜像源 镜像地址完整定义在 `.env` 的 `ES_IMAGE` / `KIBANA_IMAGE`(registry + repository + tag 全包含),因此 **换镜像仓库、换镜像名或换 tag 都只改 **`.env`** 这两行,无需动 **`docker-compose.yml`: - `ES_IMAGE=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/elasticsearch:9.5.1` - `KIBANA_IMAGE=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/kibana:9.5.1` 当前为华为云 SWR 的 Docker Hub 代理。Kibana 镜像路径是按 Elasticsearch 同规律推断的,首次部署前请先 `docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/kibana:9.5.1` 验证 `9.5.1` tag 在镜像仓库中确实存在。 ### 3. 安全凭据(必填) ```javascript ELASTIC_PASSWORD=... # elastic 超级用户密码,用于登录 Kibana / 调用 ES API KIBANA_PASSWORD=... # kibana_system 用户密码,仅供 Kibana 内部连接,勿用于登录 ``` 已预生成 24 位强密码(混合大小写字母 + 数字 + 符号)。注意:为避免 compose 内 `setup` 脚本与 `curl` 解析出错,密码 **请勿含** 单引号 `'`、双引号 `"`、反引号 ```、美元符 `$`、`@`、冒号 `:`、反斜杠 `\`、`#` 与空格。 ### 4. 版本与集群 ```javascript CLUSTER_NAME=es-docker-cluster # 集群名,同网络内容器据此相互发现 LICENSE=basic # basic=免费基础版(含安全/TLS);trial=30天商用试用 ``` > 具体版本号(tag)已写入 §2 的镜像地址(`ES_IMAGE` / `KIBANA_IMAGE`),生产请勿使用 `latest`。 ### 5. 端口映射(宿主机:容器) ```javascript ES_PORT=9200 # 建议改为 127.0.0.1:9200 仅本机访问,再经反代对外 KIBANA_PORT=5601 # Kibana Web 端口 ``` ### 6. 资源限制(务必按真实主机内存调整) ```javascript MEM_LIMIT=2147483648 # 每个 ES 容器内存硬上限(字节)。容器上限 ≈ 主机内存 * 0.75 ES_JAVA_OPTS=-Xms1g -Xmx1g # JVM 堆:= 容器内存一半,单节点 ≤ 31GB;-Xms 与 -Xmx 必须相等 KIBANA_MEM_LIMIT=1073741824 # Kibana 容器内存上限(字节),切勿复用 ES 的 MEM_LIMIT ``` 注意:`MEM_LIMIT` 与 `ES_JAVA_OPTS` 是每个 **ES 节点** 的值,3 个节点会同时占用,因此必须按「主机内存 ÷ 节点数」摊薄(详见下表);`KIBANA_MEM_LIMIT` 是 Kibana 单独的上限,之前误用 `MEM_LIMIT` 会导致 Kibana 白白占掉一大块内存。 参考值(每个 ES 节点): |**主机内存**|`MEM_LIMIT`**(ES节点)**|`ES_JAVA_OPTS`**(堆)**|`KIBANA_MEM_LIMIT`|**合计占用**| | --- | --- | --- | --- | --- | |4 GB|1 GB(`1073741824`)|`512m/512m`|1 GB|超卖,**建议改单节点**| |**8 GB**|**2 GB(**`2147483648`**)**|`1g/1g`|**1 GB(**`1073741824`**)**|**7 GB ✅**| |16 GB|4 GB(`4294967296`)|`2g/2g`|2 GB|14 GB ✅| |32 GB+|8 GB(`8589934592`)|`4g/4g`|2 GB|26 GB ✅| ### 7. 宿主机内核参数(在宿主机执行,不是容器变量) ES 启动前 **必须** 设置 `vm.max_map_count=1048576`,否则直接失败: ```javascript # Linux sudo sysctl -w vm.max_map_count=1048576 echo 'vm.max_map_count=1048576' | sudo tee -a /etc/sysctl.conf # 持久化 # Windows Docker Desktop(WSL2 后端) wsl -d docker-desktop -u root sysctl -w vm.max_map_count=1048576 # 持久化:在 %USERPROFILE%\.wslconfig 增加 [wsl2] kernelCommandLine = "sysctl.vm.max_map_count=1048576" ``` ### 8. 项目命名空间(可选) ```javascript # COMPOSE_PROJECT_NAME=elasticsearch # 取消注释后,容器/卷/网络名带此前缀,便于单机多套环境 ``` ### 9. 生产加固说明 相对官方示例补齐的生产项(均已写入 `docker-compose.yml`): - 显式 JVM 堆(`ES_JAVA_OPTS`),不再依赖自动估算 - `nofile` ulimit `65535`(生产必备,官方示例缺失) - `memlock` ulimit + `bootstrap.memory_lock=true`(锁定内存,禁 swap 抖动) - `restart: unless-stopped`(容器异常自动拉起) - 全链路 TLS(`http` + `transport`)与账号密码认证 - 命名卷与网络显式命名(`elk_certs` / `elk_esdata0x` / `elk_kibanadata` / `elk_network`),不受 `COMPOSE_PROJECT_NAME` 影响,便于稳定引用 - 命名卷持久化数据,容器删除不丢数据 ### 10. 部署边界 - 这是 **单主机多节点**,不是跨多台云主机的高可用集群。整台主机宕机则集群整体不可用;需要跨主机 HA 应改用多机各自部署 + `discovery.seed_hosts` 互联,或 Kubernetes(ECK)/ Elastic Cloud。 - `.env` 中 `ES_PORT=9200` 默认绑定 `0.0.0.0`。云主机(尤其有公网 IP)上建议改为 `127.0.0.1:9200` 并前置反向代理,或用安全组/防火墙收敛端口。 --- ## 部署 ### 环境要求 - Docker Engine ≥ 20.10,且使用 Docker Compose **v2 插件**(`docker compose version` 可查;注意是 v2 子命令,不是旧版独立的 `docker-compose`) - 主机内存 ≥ 8 GB(默认 `.env` 按 8 GB 调优;4 GB 主机建议改单节点,见「配置 → 6」) - 已按「配置 → 7」设置 `vm.max_map_count=1048576`(未设置 ES 会启动失败) - 镜像仓库可达:首次 `up` 会自动拉取 `.env` 中的镜像;若仓库在内网或需代理,请先 `docker login` 或配置镜像加速器 ### 前置条件 - 已完成「配置 → 7」的 `vm.max_map_count` 设置 - 已在 `.env` 填写(或保留预生成)`ELASTIC_PASSWORD` 与 `KIBANA_PASSWORD` - 已确认 `.env` 中镜像 tag 在仓库中均存在(见「配置 → 2」的 `docker pull` 验证) ### 启动 ```javascript # 1) 进入本目录(v1: docker/v1;v2: docker/v2) cd docker/v1 # 或 docker/v2 # 2) (可选)先拉取镜像,提前暴露"tag 不存在 / 仓库不可达"等问题 docker compose pull # 3) 校验 compose 配置(无报错再继续) docker compose config > /dev/null && echo "config OK" # 4) 启动。`setup` 会作为栈的一部分自动先运行:生成 CA 与节点证书、设置 # kibana_system 密码,完成后退出;随后 es01/02/03 与 kibana 依次拉起 # (v2 还会等 kibana healthy 后再启动 nginx)。 docker compose up -d ``` 首次部署通常需要 1~3 分钟:等待 `setup` 变 `healthy`(证书就绪)→ `es01/02/03` 相继 `healthy` → `kibana`(→ `nginx`)`healthy`。用 `docker compose ps` 观察进度,`docker compose logs -f setup` 看初始化细节。 ### 查看状态与日志 ```javascript docker compose ps # 查看各服务状态(es/kibana 应为 healthy/running) docker compose logs -f setup # 观察初始化进度(出现 "All done!" 即完成) docker compose logs -f es01 # 观察某个节点日志 ``` ### 停止与清理 ```javascript docker compose down # 停止并移除容器/网络,数据卷保留(重启数据不丢) docker compose down -v # 额外删除所有数据卷(不可逆!仅用于彻底清空) ``` ### 常见问题与排错 |**现象**|**原因**|**处理**| | --- | --- | --- | |容器 `es0x` 反复重启,或 `docker inspect` 看到退出码 `137`|内存超卖(OOM Killer 杀进程)。默认按 8 GB 调优(3 节点×2 GB + Kibana 1 GB ≈ 7 GB),主机更小或同机跑其他服务会 OOM|按「配置 → 6」下调 `MEM_LIMIT` 与 `ES_JAVA_OPTS`;4 GB 主机建议改单节点(仅留 `es01`,删除 `es02/es03` 相关配置)| |ES 启动即失败,日志含 `vm.max_map_count [65530] is too low`|未设置 `vm.max_map_count`|按「配置 → 7」执行 `sysctl -w vm.max_map_count=1048576` 并持久化| |`setup` 一直 `starting` 不 `healthy`,或 es 节点卡在等待|证书未生成 / ES 未就绪(首次较慢,最多约 2 分钟);也可能是密码含禁用字符导致脚本中断|先看 `docker compose logs setup`;若 `ELASTIC_PASSWORD`/`KIBANA_PASSWORD` 含 `' " \` $ @ : #`或空格,改为安全字符后重新`up -d`| |Kibana 反复重启,日志报 `config validation of [elasticsearch].hosts` 之类错误|`ELASTICSEARCH_HOSTS` 必须是 **JSON 数组** 字符串,不能用逗号分隔的裸 URL|确认 `docker-compose.yml` 中该项为 `'ELASTICSEARCH_HOSTS=["https://es01:9200","https://es02:9200","https://es03:9200"]'`(本配置已是正确的数组写法)| |浏览器/客户端提示证书不受信任|ES/Kibana 启用 `setup` 生成的**自签** TLS 证书(CA 不在系统信任库)|预期行为;`curl` 用 `-k` 跳过。`setup` 管理的内部节点证书一般无需替换| |修改 `CLUSTER_NAME` / 节点名后,或重新生成证书后仍报 TLS 错误|旧 `certs` 卷残留|`docker compose down -v` 删除 `elk_certs` 卷后重新 `up -d`,让 `setup` 重新签证| |改了 `ELASTIC_PASSWORD` 后 `elastic` 登录仍用旧密码|ES 仅在集群**首次初始化**时按 `ELASTIC_PASSWORD` 设置超级用户密码,之后改 env 不生效|用 `docker exec elk-es01 bin/elasticsearch-reset-password -u elastic -i` 交互重置;而 `KIBANA_PASSWORD` 由 `setup` 每次重跑都会更新,改 env 后 `up -d` 即可生效| |宿主机端口被占用(`bind: address already in use`)|9200 / 5601(v2 另有 80 / 443)已被其他程序占用|在 `.env` 改对应端口(如 `ES_PORT=9201`、`KIBANA_PORT=5602`,v2 可改 `NGINX_HTTPS_PORT=8443`)后重新 `up -d`| |Kibana 页面能打开但无法连接 ES / 一直加载|Kibana 连 ES 的 `ELASTICSEARCH_HOSTS` 不可达或 `kibana_system` 密码与 ES 不一致|确认集群 `healthy`;若曾手动改过 `KIBANA_PASSWORD`,重跑 `docker compose up -d`(setup 会重新同步该密码)| --- ## 访问测试 ### 1. 集群健康(ES HTTPS,已启用 TLS) ES 的 HTTP 层已启用 SSL,因此用 `https` 访问并跳过证书校验(`-k`): ```javascript curl -k -u elastic:$ELASTIC_PASSWORD https://localhost:9200 curl -k -u elastic:$ELASTIC_PASSWORD https://localhost:9200/_cat/nodes?v curl -k -u elastic:$ELASTIC_PASSWORD https://localhost:9200/_cluster/health?pretty ``` 正常返回中包含 `"cluster_name" : "es-docker-cluster"` 与 `"status" : "green"/"yellow"`。 ### 2. Kibana Web 界面 浏览器打开:`http://localhost:5601` - 首次访问会 302 跳转到登录页 - 用 `elastic` 用户 + `.env` 中的 `ELASTIC_PASSWORD` 登录 快速探活(命令行): ```javascript curl -s -I http://localhost:5601 | head -1 # 期望 HTTP/1.1 302 Found ``` ### 3. 写入/查询冒烟测试 ```javascript # 写入一条测试文档 curl -k -u elastic:$ELASTIC_PASSWORD -X PUT https://localhost:9200/test-index/_doc/1 \ -H 'Content-Type: application/json' -d '{"hello":"world"}' # 查询 curl -k -u elastic:$ELASTIC_PASSWORD https://localhost:9200/test-index/_search?pretty # 清理 curl -k -u elastic:$ELASTIC_PASSWORD -X DELETE https://localhost:9200/test-index ``` --- > 提示:以上所有 `docker compose` 命令均在**目标部署主机**上执行(而非本地或其他机器)。首次部署前建议先 `docker compose config` 校验配置,确认无误再 `docker compose up -d`。