Docker Compose 部署 Elasticsearch(单节点)

前言

Elasticsearch 用来做全文检索、日志检索、以及聚合分析时非常方便。
为了让本地开发、测试环境一键可复现,最省心的方式通常是用 docker compose 管起来。
本文以单节点为目标,给出一份可直接运行的 docker-compose.yml,并补齐持久化与常见报错的处理方式。
如果你只需要一个能用的 ES 来跑 demo 或联调接口,照着做就能很快跑起来。

准备

你需要先确认本机已经安装 Docker Desktop,并且 docker compose 可用。
下面命令用于确认 Docker 与 Compose 插件可正常工作。

1
2
docker version
docker compose version

如果你在 Windows 上使用 Docker Desktop,推荐使用 WSL2 后端。
后面涉及的内核参数调整,在 WSL2 与 Linux 主机上写法不同,我会分别给出。

实现

创建目录

先准备一个独立目录,用于存放 docker-compose.yml 与持久化数据目录。
下面给出一个示例目录结构,你也可以按自己习惯调整。

1
2
mkdir -p es-compose
cd es-compose

编写 docker-compose.yml

下面这份 Compose 会拉起一个单节点 Elasticsearch,并把数据目录持久化到宿主机。
你只需要把 STACK_VERSION 改成你要的 ES 版本即可,建议用同一个大版本在团队内统一。
如果你希望开启安全认证,并且让 elastic 用户的默认密码来自 .env,可以使用 ELASTIC_PASSWORD
需要注意的是,这个密码通常只在数据目录为空的首次初始化时生效。
如果你已经挂载了 ./data 并启动过,再修改 ELASTIC_PASSWORD 一般不会自动修改已有密码,这时需要清空数据重新初始化或执行重置密码命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
container_name: es
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms1g -Xmx1g
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=false
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- esdata:/usr/share/elasticsearch/data
ports:
- "9200:9200"
- "9300:9300"
restart: unless-stopped

kibana:
image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
container_name: kibana
depends_on:
- elasticsearch
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
- SERVER_HOST=0.0.0.0
ports:
- "5601:5601"
restart: unless-stopped

volumes:
esdata:

上面配置里我开启了安全认证,并关闭了 HTTPS,方便开发环境直接访问。
默认用户名是 elastic,密码就是 ELASTIC_PASSWORD 的值。
如果你要用于公网或准生产环境,建议开启 HTTPS,并配合反向代理与访问控制。

这里也补充一下端口的作用,方便你按需暴露端口与做防火墙策略。
9200 是 Elasticsearch 的 HTTP 接口端口,curl 调用、Kibana 访问、以及业务服务的 REST 客户端通常都连这个端口。
9300 是 Elasticsearch 节点之间的传输端口,集群内部通信、节点加入集群等会用到它,单节点模式下通常不需要对外网暴露。
5601 是 Kibana 的 Web UI 端口,用浏览器访问 Kibana 控制台时会用到它,如果你不部署 Kibana 就不需要暴露。

如果你希望把数据目录挂载到宿主机目录(例如 ./data:/usr/share/elasticsearch/data),需要确保宿主机目录对容器内的 elasticsearch 用户可写。
在官方镜像里通常是以 uid 1000 运行,所以你可以在启动前执行下面命令修正权限。

1
2
3
mkdir -p ./data
sudo chown -R 1000:0 ./data
sudo chmod -R ug+rwX ./data

编写 .env(推荐)

为了避免在 compose 文件里写死版本,你可以用 .env 来管理变量。
下面给一个示例,版本号与默认密码按你项目实际需要调整。
开启安全认证后,默认用户名是 elastic,密码就是 ELASTIC_PASSWORD
Kibana 连接 Elasticsearch 建议使用内置用户 kibana_system,并在 .env 中配置 KIBANA_PASSWORD

1
2
3
STACK_VERSION=8.13.4
ELASTIC_PASSWORD=xhkjedud07
KIBANA_PASSWORD=ChangeMeForKibana123!

如果你开启了安全认证,并且想在已初始化后修改密码,可以进入容器执行交互式重置。
下面命令把 kibana_system 用户的密码重置为你输入的新值,然后把同样的值写到 .envKIBANA_PASSWORD 中即可。

1
2
docker exec -it es /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -i
docker exec -it es /usr/share/elasticsearch/bin/elasticsearch-reset-password -u kibana_system -i

注意

启动后要执行第二条命令设置kibana_system的密码,否则kibana无法登录

调整内核参数 vm.max_map_count

Elasticsearch 在 Linux 内核上通常要求 vm.max_map_count 至少为 262144
下面给出在 Linux 主机上一次性生效与持久化生效两种写法。

1
2
3
sudo sysctl -w vm.max_map_count=262144
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

如果你在 Windows 的 WSL2 里跑 Docker 后端,可以先在 WSL 发行版里执行同样命令。
如果你发现重启后失效,可以考虑在 WSL 的启动脚本或 wsl.conf 方案里做持久化,这部分不同发行版可能略有差异。

启动

下面命令会在后台启动 Elasticsearch 与 Kibana。
首次启动会拉取镜像,速度取决于网络情况。

1
2
docker compose up -d
docker compose ps

验证

查看日志

1
docker logs -f es

你可以先用 curl 验证 ES 是否能返回基本信息。
下面命令会请求 ES 根路径与集群健康状态。

1
2
curl -u elastic:${ELASTIC_PASSWORD} -s http://localhost:9200
curl -u elastic:${ELASTIC_PASSWORD} -s "http://localhost:9200/_cluster/health?pretty"

如果你也启动了 Kibana,可以用浏览器访问 http://localhost:5601
如果 Kibana 一直转圈或报错,优先看它自己的日志。

1
docker logs -f kibana

如果 Elasticsearch 开启了安全认证,而 Kibana 没有配置连接 Elasticsearch 的用户名密码,Kibana 通常无法正常启动或会持续重试。
你可以先用下面命令确认 Kibana 端口是否在监听,以及容器是否处于运行状态。

1
2
docker compose ps
curl -I http://localhost:5601

常见问题

vm.max_map_count 太小

如果日志里出现 vm.max_map_count [xxx] is too low,说明你的宿主机内核参数没调到位。
你可以按本文前面 vm.max_map_count 的步骤调整,然后重启容器。

1
docker compose restart elasticsearch

文件描述符 nofile 太小

如果日志里出现 max file descriptors [xxxx] for elasticsearch process is too low,说明 nofile 不够。
本文的 compose 已经通过 ulimits.nofile 做了常见修正,但某些环境可能仍需要在宿主机层面提高限制。
你可以先确认容器内当前限制值,再决定是否需要改宿主机配置。

1
docker exec -it es /bin/bash -lc "ulimit -n && ulimit -l"

内存不足或启动很慢

如果你机器内存比较小,ES_JAVA_OPTS-Xms/-Xmx 建议下调。
例如改成 -Xms512m -Xmx512m,更适合轻量 demo。

扩展

只启动 Elasticsearch

如果你只需要 ES,不需要 Kibana,可以把 kibana 服务从 compose 里删掉。
或者启动时只拉起指定服务。

1
docker compose up -d elasticsearch

清理与重置数据

如果你需要完全重置数据,先停服务,再删除本地 data 目录。
这会导致索引与数据全部丢失,请确认是你想要的效果。

1
2
docker compose down
rm -rf ./data

总结

用 Docker Compose 部署 Elasticsearch 的最小落地流程可以概括为三步。

  1. 写好 docker-compose.yml,用 volumes 做持久化。
  2. 调整 vm.max_map_countnofile,解决 ES 启动最常见的系统限制问题。
  3. curl 与健康检查验证服务状态,必要时查看 docker logs 定位问题。