Docker Compose 部署 Elasticsearch(单节点)

前言

Elasticsearch 用来做全文检索、日志检索、以及聚合分析时非常方便。

为了让本地开发、测试环境一键可复现,最省心的方式通常是用 docker-compose 管起来。

本文以单节点为目标,给出一份可直接运行的 docker-compose.yml,并补齐持久化与常见报错的处理方式。

准备

你需要先确认本机已经安装 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 compose-es
cd compose-es

编写 Dockerfile.elasticsearch

官方 Elasticsearch 镜像不包含 IK 分词器,需要在镜像构建阶段执行 elasticsearch-plugin install
下面 Dockerfile 基于与 STACK_VERSION 相同的官方镜像,安装 Infinilabs 发布的 analysis-ik(原 IK 分词插件),安装地址与官方说明一致。
插件版本必须与 ES 版本一致;若构建失败,可到 analysis-ik 稳定包目录 核对是否已有对应 elasticsearch-analysis-ik-{版本}.zip,必要时把 STACK_VERSION 调整为已有包的小版本号。

1
2
3
4
5
6
FROM docker.elastic.co/elasticsearch/elasticsearch:8.13.4

ARG STACK_VERSION=8.13.4

RUN bin/elasticsearch-plugin install --batch "https://get.infini.cloud/elasticsearch/analysis-ik/${STACK_VERSION}" \
|| bin/elasticsearch-plugin install --batch "https://release.infinilabs.com/analysis-ik/stable/elasticsearch-analysis-ik-${STACK_VERSION}.zip"

编写 docker-compose.yml

下面这份 Compose 会拉起一个单节点 Elasticsearch,并把数据目录持久化到宿主机。
Elasticsearch 服务通过上一节的 Dockerfile 构建带 IK 的镜像;Kibana 仍使用官方镜像。
你只需要把 STACK_VERSION 改成你要的 ES 版本即可,建议用同一个大版本在团队内统一。
如果你希望开启安全认证,并且让 elastic 用户的默认密码来自 .env,可以使用 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
41
42
43
44
45
services:
elasticsearch:
build:
context: .
dockerfile: Dockerfile.elasticsearch
args:
STACK_VERSION: ${STACK_VERSION}
image: local/elasticsearch-ik:${STACK_VERSION}
container_name: es-server
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: es-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

Docker Compose 会为你创建一个名为 esdata 的持久化存储空间。当你执行 docker-compose down 命令时,默认行为是:

  1. 停止并移除容器。
  2. 移除为服务创建的网络。
  3. 保留所有由 volumes 声明的命名卷。

因此,你的数据会安全地保存在 esdata 这个卷中。

当你再次执行 docker-compose up -d 时,Docker 会创建新的容器,并重新将这个包含旧数据的 esdata 卷挂载进去,你的数据自然就回来了。

如果要删除命名卷

1
docker-compose down --volumes

或者只删除某个命名卷

1
docker volume rm compose-es_esdata

注意创建的命名卷的名称不是esdata

编写 .env(推荐)

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

1
2
3
STACK_VERSION=8.13.4
ELASTIC_PASSWORD=makeshuo
KIBANA_PASSWORD=kibanapwd123!

如果你开启了安全认证,并且想在已初始化后修改密码,可以进入容器执行交互式重置。

默认只创建了elastic的密码,是没有设置kibana_system的密码的。

下面命令把 kibana_system 用户的密码重置为你输入的新值,然后把同样的值写到 .envKIBANA_PASSWORD 中即可。

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

如果要修改elastic的密码。

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

调整内核参数 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。
首次启动会拉取镜像,速度取决于网络情况。

先构建 Elasticsearch 镜像

1
DOCKER_BUILDKIT=0 COMPOSE_DOCKER_CLI_BUILD=0 docker-compose build elasticsearch

再启动容器。

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"

下面请求使用 _analyze 接口,确认 IK 插件已加载且 ik_max_word 能正常分词。
返回里应出现若干 token 条目;若报 Unknown analyzer [ik_max_word],说明当前运行的镜像未安装插件或版本不匹配。

1
2
3
curl -u elastic:${ELASTIC_PASSWORD} -s "http://localhost:9200/_analyze?pretty" \
-H "Content-Type: application/json" \
-d "{\"analyzer\":\"ik_max_word\",\"text\":\"中华人民共和国国歌\"}"

如果你也启动了 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. 需要 IK 时准备 Dockerfile.elasticsearch,在构建阶段安装与 STACK_VERSION 一致的插件包。
  2. 写好 docker-compose.yml,Elasticsearch 用 build 生成带 IK 的镜像,并用 volumes 做持久化。
  3. 调整 vm.max_map_countnofile,解决 ES 启动最常见的系统限制问题。
  4. curl_cluster/health_analyze 验证服务与分词,必要时查看 docker logs 定位问题。