文章目录
- [容器化应用实战:ElasticSearch + Kibana](#容器化应用实战:ElasticSearch + Kibana)
-
- [一、ElasticSearch 部署](#一、ElasticSearch 部署)
-
- [1. 下载 ES 镜像](#1. 下载 ES 镜像)
- [2. 准备目录与配置文件](#2. 准备目录与配置文件)
- [3. 启动容器](#3. 启动容器)
- [二、Kibana 部署](#二、Kibana 部署)
-
- [1. 下载 Kibana 镜像](#1. 下载 Kibana 镜像)
- [2. 启动容器,指向 ES 位置](#2. 启动容器,指向 ES 位置)
- 三、自定义网络方案(推荐)
-
- [1. 创建自定义网络](#1. 创建自定义网络)
- [2. 启动 ElasticSearch,加入自定义网络 es-net](#2. 启动 ElasticSearch,加入自定义网络 es-net)
- [3. 启动 Kibana,同样加入 es-net 网络](#3. 启动 Kibana,同样加入 es-net 网络)
- [4. 两种方案对比](#4. 两种方案对比)
- [5. 调试小技巧](#5. 调试小技巧)
- 四、报错复盘:单文件挂载坑
-
- [1. 现象](#1. 现象)
- [2. 故障根因](#2. 故障根因)
- [3. 本次排障里的错误操作](#3. 本次排障里的错误操作)
- [4. 完整正确处理流程](#4. 完整正确处理流程)
- [5. 经验教训](#5. 经验教训)
- [6. 可选规避方案](#6. 可选规避方案)
容器化应用实战:ElasticSearch + Kibana
!note 核心摘要
- ES 单节点 :必须加
discovery.type=single-node,低配机器用ES_JAVA_OPTS限制 JVM 堆内存- 版本一致:ES 与 Kibana 版本必须完全一致(本例均为 7.17.0)
- 容器互联 :ES 与 Kibana 加入同一自定义网络,
ELASTICSEARCH_HOSTS直接写容器名,不依赖宿主机 IP- 高频坑 :bind-mount 挂载单个文件 前必须提前手动创建文件,否则 docker 会生成同名目录导致启动失败
一、ElasticSearch 部署
1. 下载 ES 镜像
bash
[root@localhost ~]# docker pull elasticsearch:7.17.0
7.17.0: Pulling from library/elasticsearch
ea362f368469: Pull complete
49618e7bd315: Pull complete
ef2c6f195245: Pull complete
c32ac7edc3c3: Pull complete
85e392fc2cc0: Pull complete
4aff618a9264: Pull complete
795bd33f4eb3: Pull complete
ab1c10cef766: Pull complete
1cf47933dd34: Pull complete
Digest: sha256:332c6d416808f6e9a2cbcbe0170d9a9bb14bfe772180d37de5084c223dd8948b
Status: Downloaded newer image for elasticsearch:7.17.0
docker.io/library/elasticsearch:7.17.0
2. 准备目录与配置文件
创建配置文件目录、数据文件目录:
bash
[root@localhost ~]# mkdir -p /opt/es/config
[root@localhost ~]# mkdir -p /opt/es/data
创建监听端口资源(写入 ES 配置文件):
bash
[root@localhost ~]# echo "http.host: 0.0.0.0" >> /opt/es/config/elasticsearch.yml
开启权限(ES 容器内用户 uid=1000,防止权限拒绝):
bash
[root@localhost ~]# chmod -R 777 /opt/es/
3. 启动容器
bash
[root@localhost ~]# docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
> -e "discovery.type=single-node" \
> -e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
> -v /opt/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
> -v /opt/es/data:/usr/share/elasticsearch/data \
> -v /opt/es/plugins:/usr/share/elasticsearch/plugins \
> -d elasticsearch:7.17.0
e6d5b38f691861cc39c7ec944e29c01ff758aeb8e423e7a4936a2419f4ebb58a
查看容器:
bash
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e6d5b38f6918 elasticsearch:7.17.0 "/bin/tini -- /usr/l..." 4 seconds ago Up 2 seconds 0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 0.0.0.0:9300->9300/tcp, :::9300->9300/tcp elasticsearch
参数简单说明
discovery.type=single-node:单节点模式,不需要集群,本地测试必加ES_JAVA_OPTS="-Xms512m -Xmx512m":JVM 堆内存,最小最大都设 512M,低配机器防止占满内存-v:挂载配置、数据、插件目录到宿主机- 9200:ES HTTP 访问端口;9300:ES 集群内部通信端口
验证访问:curl http://127.0.0.1:9200,返回 json 代表启动成功。
二、Kibana 部署
1. 下载 Kibana 镜像
bash
[root@localhost ~]# docker pull kibana:7.17.0
7.17.0: Pulling from library/kibana
ea362f368469: Already exists
94aca20bb05b: Pull complete
65ae9e597e86: Pull complete
d29743d928b1: Pull complete
23891b890413: Pull complete
8bf7af96af27: Pull complete
014dfb291cad: Pull complete
8bf3742fc390: Pull complete
7b0e9c8dbcb7: Pull complete
4dab17aa5385: Pull complete
807090e8d21f: Pull complete
87d0ac3cb26e: Pull complete
ed92e0cf24d4: Pull complete
Digest: sha256:a98b0797fd5357ba8a64c32df0e2e24dc7ad2df3320891b090a1f713124f1c95
Status: Downloaded newer image for kibana:7.17.0
docker.io/library/kibana:7.17.0
2. 启动容器,指向 ES 位置
bash
[root@localhost ~]# docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.100.152:9200 -p 5601:5601 -d kibana:7.17.0
8cd2108ffe49cd6dd7eac21b93b4204beb1ca0ab6b45a2bedd1a7d980e7ea4b1
参数说明:
ELASTICSEARCH_HOSTS:指定 Kibana 连接 ES 的地址,这里要填宿主机真实 IP,不要写 127.0.0.1(容器内部 127.0.0.1 代表容器自己)- 5601:Kibana 网页访问端口,浏览器访问
http://宿主机IP:5601
!warning 版本一致性
ES 和 Kibana 版本必须完全一致,这里都是 7.17.0。
三、自定义网络方案(推荐)
上面脚本里的方式 ELASTICSEARCH_HOSTS=http://192.168.100.152:9200,是 Kibana 容器走宿主机物理 IP 访问 ES。
缺点:要写死宿主机 IP,换机器、IP 一变就要改启动命令;还要防火墙放行 9200 端口。
!note 更推荐的方案
自定义 docker 网络:两个容器接入同一个自定义网络,直接用容器名字当域名互相访问,不用写宿主机 IP。
1. 创建自定义网络
bash
# 创建 es-net 网络
docker network create es-net
2. 启动 ElasticSearch,加入自定义网络 es-net
把原来的 run 命令加上 --network es-net:
bash
docker run --name elasticsearch \
--network es-net \
-p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
-v /opt/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /opt/es/data:/usr/share/elasticsearch/data \
-v /opt/es/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.17.0
3. 启动 Kibana,同样加入 es-net 网络
ELASTICSEARCH_HOSTS 直接写容器名 elasticsearch 作为域名,docker 内部 DNS 自动解析,不用写宿主机 IP:
bash
docker run --name kibana \
--network es-net \
-e ELASTICSEARCH_HOSTS=http://elasticsearch:9200 \
-p 5601:5601 \
-d kibana:7.17.0
关键点:
- 同一个自定义网络内,容器名就是主机名 ,kibana 内部访问
http://elasticsearch:9200就能连通 ES - 不再依赖宿主机局域网 IP,宿主机 IP 怎么变,容器之间通信不受影响
- 不需要宿主机防火墙开放 9200 端口给外部,9200 只需要宿主机本地访问调试用,kibana 走 docker 内部网络
4. 两种方案对比
| 方式 | 配置写法 | 优点 | 缺点 |
|---|---|---|---|
| 宿主机 IP 访问 | http://192.168.100.152:9200 |
简单,不用新建网络 | IP 写死,IP 变更要改配置,需要防火墙放行 9200 |
| 自定义 docker 网络 | http://elasticsearch:9200 |
容器名做域名,不依赖宿主机 IP,网络隔离,生产推荐 | 需要提前创建网络 |
5. 调试小技巧
进入 kibana 容器内部测试连通性:
bash
docker exec -it kibana curl http://elasticsearch:9200
能返回 ES 的 json 信息,代表网络通信正常。
!warning 容易踩坑
bridge默认网络不支持容器名 DNS 解析,必须自己 create 的自定义网络才支持容器名域名解析,这点很容易踩坑。
四、报错复盘:单文件挂载坑
1. 现象
执行 docker run 启动 elasticsearch,命令返回一串 OCI runtime 报错,容器创建出来但启动失败 ,docker ps -a 看到状态为 Created,无法 up 运行。
报错核心提示:
text
Are you trying to mount a directory onto a file (or vice-versa)?
not a directory
2. 故障根因
使用 bind-mount 挂载单个文件:
bash
-v /opt/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
宿主机上 /opt/es/config/elasticsearch.yml 文件没有提前手动创建。
Docker bind-mount 底层限制:mount --bind 只能绑定已经存在的对象,不能凭空生成文件。
👉 宿主机该路径不存在时,Docker 会自动 mkdir,生成一个名字叫 elasticsearch.yml 的文件夹,并不是 yml 配置文件。
于是冲突出现:
- 宿主机:
elasticsearch.yml→ 文件夹(docker 自动创建) - 容器内部目标:
elasticsearch.yml→ 普通配置文件
试图把宿主机目录挂载覆盖容器内文件,直接抛出挂载异常。
!warning 迷惑点
ls /opt/es/config/能看到这个名字,肉眼分不清是文件还是文件夹,必须ls -l看第一位,d代表目录,-代表普通文件。
3. 本次排障里的错误操作
看到挂载报错后,去删除 /opt/es/data/nodes/ 数据目录。
- 这个报错发生在容器初始化挂载阶段,ES 程序还没有启动,根本还没访问 data 数据目录
- 删除 nodes 属于无效操作,解决不了本次挂载问题
- 同时残留了状态为
Created的失败容器,如果不删除,下次 run 会报容器名称已存在
4. 完整正确处理流程
- 校验对象真实类型:
bash
ls -l /opt/es/config/elasticsearch.yml
- 如果它是目录(d 开头),删除这个错误目录:
bash
rm -rf /opt/es/config/elasticsearch.yml
- 手动真正生成 yml 配置文件:
bash
echo "http.host: 0.0.0.0" > /opt/es/config/elasticsearch.yml
- 给目录权限(ES 内部用户 uid=1000,防止后续权限拒绝):
bash
chmod -R 777 /opt/es
- 清理残留的 Created 状态旧容器:
bash
docker rm -f elasticsearch
- 重新执行 docker run 启动容器。
5. 经验教训
-v绑定宿主机单个文件 时,文件必须提前手动创建;宿主机不存在,docker 会错误生成目录,这是高频坑。-v绑定目录时,宿主机不存在,docker 自动创建目录,行为正常。Created容器状态:代表容器对象创建成功,但启动失败,不会自动删除,需要手动 rm 清理。- 看类型不要只看文件名,用
ls -l分辨是文件还是文件夹。 - 报错要看准报错栈:报错信息写哪个路径,问题就出在哪个路径,不要去操作无关目录。
6. 可选规避方案
学习环境,不挂载单个 yml,改为挂载整个 config 目录,规避该坑:
bash
-v /opt/es/config:/usr/share/elasticsearch/config
!warning 注意
该方式要求宿主机 config 目录内要有 ES 完整配置文件,不能只放一个 yml。