资讯动态

Docker Compose 部署 ElasticSearch + Kibana:从零搭建日志检索环境

发布时间:2026/10/22 3:13:07 来源:尧图企业网站定制
1. 为什么我把这套组合拳当作日志与检索的默认起手式但凡做过线上服务的人大概都经历过这样的场景半夜被告警叫醒登录服务器grep、tail、awk轮番上阵在几个 G 的日志文件里翻找一条报错。等你好不容易定位到问题天已经亮了。这种原始方式在单机、小流量阶段还能凑合一旦服务拆成十几个模块、每天产生几十 G 日志就彻底玩不转了。我最早接触 ElasticSearch下文简称 ES和 Kibana就是为了解决这个痛点。ES 负责把散落各处的日志、业务数据集中存起来并建立倒排索引Kibana 则提供一个可视化界面让你用鼠标点几下就能完成过去半小时的排查工作。这套组合在日志分析、全文检索、指标聚合这些场景里几乎是行业默认答案。但问题也随之而来ES 本身是个 Java 应用对内存、文件句柄、内核参数都有要求直接装在宿主机上配置繁琐、版本冲突、迁移困难。我见过太多人因为环境不一致在测试机上跑得好好的换台机器就起不来。Docker 部署 ElasticSearch Kibana这个标题本质上要解决的就是环境一致性和快速复现这两个核心诉求——把 ES 和 Kibana 连同它们的运行环境一起打包成镜像一条命令拉起换台机器照样跑。这篇文章适合谁看如果你是刚接触 ES 的后端或运维同学想快速搭一套能用的检索环境或者你已经用过 ES但每次部署都要重新查文档、踩一遍坑想找一份能直接抄作业的完整方案那接下来的内容应该能帮到你。我会从整体设计思路讲起把镜像选型、参数配置、内存分配、常见报错这些细节全部摊开尽量让你少走弯路。2. 整体设计与方案选型为什么是 Docker Compose 而不是单容器2.1 单容器 vs 编排工具我为什么选后者刚上手的人容易有个误区既然 ES 和 Kibana 是两个独立服务那我分别docker run两条命令不就行了理论上没错但实际操作中会碰到几个麻烦。第一两个容器需要网络互通你得手动创建自定义网络、指定容器名、处理 DNS 解析第二ES 的启动参数、数据卷挂载、环境变量一大堆命令行会写得又长又容易出错第三每次重启或迁移你都得把这两条命令重新敲一遍或者存成一个脚本文件。Docker Compose 的价值就在于把这些配置固化到一个docker-compose.yml文件里。服务定义、网络、数据卷、依赖关系、启动顺序全部声明式地写清楚。以后不管是重启、升级还是换机器docker compose up -d一条命令搞定。对于 ES Kibana 这种两个服务强关联的场景Compose 是最轻量、最直观的选择。至于 Kubernetes功能确实更强但对于本地开发、测试环境或者中小规模部署来说属于杀鸡用牛刀。K8s 的学习成本和运维复杂度摆在那里除非你已经有现成的集群否则没必要为了跑两个容器去搭一套 K8s。2.2 镜像版本怎么选这里有个大坑选镜像版本是第一个容易翻车的地方。ES 和 Kibana 的版本必须严格一致这是硬性要求。ES 8.x 的 Kibana 连不上 ES 7.x反过来也一样版本号差一个小版本都可能报兼容性错误。我一般建议直接用同一个大版本的最新小版本比如都选8.13.x。另一个坑是镜像来源。官方镜像在 Docker Hub 上有elasticsearch和kibana两个仓库直接拉官方的最省心。有些第三方镜像做了精简或预配置但版本更新不及时出了问题也不好排查。我个人的原则是能用官方镜像就用官方镜像除非有明确的定制需求。还有一点ES 从 7.x 开始默认开启了安全认证用户名密码 TLS8.x 更是强制要求。很多人图省事想关掉认证但我不建议在生产环境这么做。测试环境可以临时关闭但配置方式要清楚后面我会详细讲。2.3 内存分配ES 最容易被忽视的命门ES 是基于 Lucene 的而 Lucene 依赖操作系统的文件系统缓存来加速检索。这意味着 ES 对内存极其敏感。官方文档里反复强调一个原则JVM 堆内存不要超过物理内存的 50%且不要超过 31GB。为什么是 31GB因为 JVM 在堆内存超过 32GB 时会无法使用压缩普通对象指针Compressed Oops技术导致对象指针从 4 字节膨胀到 8 字节反而浪费内存。所以哪怕你机器有 128GB 内存堆内存也建议设在 31GB 以内剩下的留给文件系统缓存。对于本地开发或测试环境机器内存通常 8GB 到 16GB。我一般把 ES 堆内存设在 1GB 到 2GB通过ES_JAVA_OPTS环境变量控制。Kibana 相对轻量512MB 到 1GB 足够。这个数值不是拍脑袋定的你可以根据实际数据量和查询并发调整但起步阶段别设太大先跑起来再说。3. 核心细节解析配置文件里的每一个参数都有讲究3.1 docker-compose.yml 的骨架长什么样先上一份我常用的 Compose 配置骨架然后逐项拆解。这份配置针对的是单节点、关闭安全认证的测试环境适合本地开发和学习。生产环境的差异我会在后面单独说明。version: 3.8 services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.13.4 container_name: es-node environment: - discovery.typesingle-node - ES_JAVA_OPTS-Xms1g -Xmx1g - xpack.security.enabledfalse volumes: - es-data:/usr/share/elasticsearch/data ports: - 9200:9200 networks: - es-net kibana: image: docker.elastic.co/kibana/kibana:8.13.4 container_name: kibana-node environment: - ELASTICSEARCH_HOSTShttp://es-node:9200 ports: - 5601:5601 depends_on: - elasticsearch networks: - es-net volumes: es-data: networks: es-net: driver: bridge这份配置看起来简单但每一行都有它的道理。下面我挑几个关键点展开说。3.2 discovery.typesingle-node 到底做了什么ES 默认是以集群模式启动的它会尝试发现其他节点、参与选举。如果你只起一个节点又没配置集群发现相关参数它会一直卡在启动阶段日志里刷一堆master not discovered的警告最后超时退出。discovery.typesingle-node这个参数告诉 ES别找了就我一个节点直接以单节点模式启动。这是本地开发和测试环境的标配。生产环境如果要做集群就不能用这个参数得配置cluster.initial_master_nodes、discovery.seed_hosts等一整套发现机制。我见过有人图省事生产环境也用single-node结果数据量一上来单节点扛不住想扩容又发现集群配置没做只能推倒重来。所以这个参数要清楚它的适用边界。3.3 数据卷挂载别让容器一删数据就没了Docker 容器的文件系统是临时的容器删除后里面的数据就没了。ES 的数据默认存在/usr/share/elasticsearch/data目录下如果不做持久化每次重启容器都相当于全新安装之前建的索引全丢。配置里的volumes: - es-data:/usr/share/elasticsearch/data就是解决这个问题。es-data是一个命名卷由 Docker 管理即使容器删了卷还在下次启动新容器挂载同一个卷数据就回来了。这里有个细节要注意ES 对数据目录的权限有要求容器内的 ES 进程以非 root 用户运行如果挂载的是宿主机目录bind mount经常会出现权限不足导致启动失败。用命名卷named volume可以避开这个问题因为 Docker 会自动处理权限。如果你非要用宿主机目录记得提前chown成 UID 1000。3.4 网络配置Kibana 怎么找到 ESCompose 默认会给所有服务创建一个网络服务之间可以用服务名互相访问。但我在配置里显式定义了es-net网络并把两个服务都挂上去目的是让网络结构更清晰也方便以后加其他服务比如 Logstash。Kibana 的ELASTICSEARCH_HOSTShttp://es-node:9200这个环境变量用的是 ES 的容器名es-node而不是localhost或 IP。因为在同一个 Docker 网络里容器名会被 Docker 的内置 DNS 解析成对应的 IP。这就是为什么两个服务必须在同一个网络里——否则 Kibana 根本找不到 ES。提示如果你把 ES 的容器名改了Kibana 的ELASTICSEARCH_HOSTS也要同步改否则连不上。这个错误很隐蔽Kibana 日志里只会报连接超时不会直接告诉你容器名写错了。3.5 depends_on 能保证启动顺序吗depends_on只保证容器启动顺序不保证服务就绪顺序。也就是说Compose 会先启动 ES 容器再启动 Kibana 容器但 ES 容器启动不等于 ES 服务已经可以接受请求了。ES 启动需要几十秒这期间 Kibana 去连它会连接失败。好在 Kibana 有重试机制连不上会隔几秒重试最终 ES 就绪后就能连上。所以测试环境下depends_on够用了。但如果你追求更严谨的启动顺序可以用healthcheck配合depends_on的condition: service_healthy让 Kibana 等 ES 健康检查通过后再启动。这个配置稍微复杂一点后面讲生产环境优化时再说。4. 实操过程从零到能用的完整步骤4.1 环境准备与前置检查动手之前先确认几件事。第一Docker 和 Docker Compose 已经装好。用docker --version和docker compose version检查Compose 建议用 V2 版本命令是docker compose而不是docker-compose。第二确认机器内存。ES 加 Kibana 至少需要 4GB 可用内存低于这个数跑起来会很卡。第三检查 9200 和 5601 端口有没有被占用用lsof -i:9200或netstat -tlnp | grep 9200看一眼。还有一个容易被忽略的点Linux 系统需要调整vm.max_map_count参数。ES 在启动时会检查这个值如果太小默认可能是 65530会直接报错退出。解决办法是执行sudo sysctl -w vm.max_map_count262144这个值要持久化的话写到/etc/sysctl.conf里。为什么需要这个参数因为 Lucene 用了大量内存映射文件每个映射文件都消耗一个虚拟内存区域默认值不够用。这是 ES 部署里最经典的坑之一很多人第一次跑 ES 就是卡在这里。4.2 编写配置文件并启动新建一个目录比如es-kibana-demo在里面创建docker-compose.yml内容用上面那份骨架。然后执行docker compose up -d-d表示后台运行。第一次执行会拉取镜像ES 镜像大概 600MB 到 800MBKibana 也差不多网速慢的话要等一会儿。拉完之后容器启动你可以用docker compose ps看状态用docker compose logs -f elasticsearch跟踪 ES 日志。ES 启动成功的标志是日志里出现started字样类似[INFO ][o.e.n.Node] [es-node] started这时候访问http://localhost:9200应该能看到一段 JSON包含集群名、版本号、节点名等信息。如果看到这个说明 ES 起来了。4.3 验证 Kibana 是否连通ES 就绪后等一两分钟让 Kibana 完成启动。访问http://localhost:5601应该能看到 Kibana 的欢迎界面。第一次进入会让你选择是否加载示例数据可以跳过。如果 Kibana 页面打不开或者打开后提示Kibana server is not ready yet先看日志docker compose logs -f kibana常见原因是 Kibana 还在启动中它比 ES 慢或者连不上 ES。日志里如果有Unable to connect to Elasticsearch就回头检查ELASTICSEARCH_HOSTS配置和网络。4.4 用 Dev Tools 做第一次检索Kibana 起来后左侧菜单里有个 Dev Tools这是我最常用的功能。它提供了一个交互式的控制台可以直接向 ES 发 REST 请求。打开后左边输入请求右边看响应。先建一个测试索引PUT /test-index { settings: { number_of_shards: 1, number_of_replicas: 0 } }单节点环境下副本数设为 0因为副本分片不能和主分片在同一节点上设成 1 会导致集群状态变成 yellow副本未分配。这是单节点 ES 的常见现象不是错误但看着不舒服设成 0 就变 green 了。然后插入一条数据POST /test-index/_doc/1 { title: Docker 部署 ElasticSearch, content: 这是一条测试数据, timestamp: 2024-06-01T10:00:00 }再查一下GET /test-index/_search { query: { match: { content: 测试 } } }如果能看到返回的_source里有你插入的数据说明整条链路通了。到这里一套可用的 ES Kibana 环境就算搭好了。5. 常见问题与排查技巧实录5.1 启动失败类问题速查ES 启动失败的原因五花八门我整理了一张速查表覆盖我遇到过的高频问题。现象可能原因排查与解决容器启动后立即退出vm.max_map_count太小执行sysctl -w vm.max_map_count262144日志报max virtual memory areas同上同上并持久化到 sysctl.conf日志报Permission denied访问 data 目录挂载目录权限不对改用命名卷或chown -R 1000:1000宿主机目录启动卡住日志刷master not discovered没配discovery.type单节点加discovery.typesingle-node内存不足被 OOM Kill堆内存设太大调小ES_JAVA_OPTS或加机器内存端口被占用9200/5601 已被其他程序使用lsof -i:9200找到进程停掉或改端口映射这张表里的每一条我基本都踩过。尤其是vm.max_map_count和权限问题新手几乎必踩。记住一个原则ES 启动失败先看日志。docker compose logs elasticsearch会告诉你具体原因比瞎猜快得多。5.2 Kibana 连不上 ES 的三种典型情况Kibana 报连接错误通常有三种情况。第一种是 ES 还没启动完Kibana 重试几次就好了这种情况不用管。第二种是ELASTICSEARCH_HOSTS写错了比如写成了localhost:9200——在容器里localhost指的是 Kibana 自己不是 ES必须用容器名或服务名。第三种是网络不通两个容器不在同一个网络里或者网络配置有问题。排查方法很简单进 Kibana 容器里 ping 一下 ESdocker compose exec kibana curl http://es-node:9200如果这条命令能返回 ES 的 JSON说明网络没问题问题在 Kibana 配置如果返回连接失败就是网络或 ES 本身的问题。5.3 数据持久化的验证方法很多人配了数据卷但不确定到底有没有生效。验证方法很简单往 ES 里插一条数据然后docker compose down删掉容器再docker compose up -d重新启动看看数据还在不在。如果还在说明持久化生效了。这里要注意docker compose down和docker compose down -v的区别。前者只删容器和网络保留卷后者连卷一起删数据就真没了。我见过有人手滑用了-v把测试数据全清了。所以执行down之前想清楚要不要保留数据。5.4 性能调优的几个实操心得环境跑起来之后如果觉得查询慢或者写入慢可以从几个方向调。第一检查堆内存是否合理太小会导致频繁 GC太大会浪费。第二单节点环境下把副本数设为 0省掉不必要的副本同步开销。第三批量写入用_bulkAPI比一条条插快几十倍。第四查询时尽量用filter而不是must因为filter不计算相关性得分可以利用缓存。还有一个容易被忽视的点不要用 ES 存原始大文本。ES 擅长的是检索不是存储。如果你把几百 MB 的日志原文整条塞进去索引会膨胀得很快。合理的做法是只索引需要检索的字段原文存到对象存储或其他地方ES 里存个引用。6. 从测试环境到生产环境需要补哪些课6.1 安全认证不能省前面那份配置关掉了安全认证这在本地测试没问题但生产环境绝对不能这么干。ES 8.x 默认开启安全功能包括用户名密码认证和 TLS 加密传输。开启后Kibana 连接 ES 需要配置用户名密码浏览器访问 Kibana 也要登录。配置方式是在 ES 的环境变量里设置xpack.security.enabledtrue然后通过elasticsearch-setup-passwords工具生成初始密码。Kibana 那边则要配置ELASTICSEARCH_USERNAME和ELASTICSEARCH_PASSWORD。这套流程稍微繁琐但为了数据安全值得花时间配好。6.2 资源限制与健康检查生产环境的 Compose 配置里建议给每个服务加上资源限制防止某个服务吃光机器内存。比如deploy: resources: limits: memory: 4G reservations: memory: 2G同时加上健康检查让编排工具能感知服务状态healthcheck: test: [CMD-SHELL, curl -s http://localhost:9200/_cluster/health | grep -q green] interval: 30s timeout: 10s retries: 5这样配合depends_on的condition: service_healthy就能保证 Kibana 在 ES 真正就绪后才启动避免启动阶段的连接报错。6.3 备份与监控的初步思路生产环境还要考虑备份。ES 提供了快照snapshot功能可以把索引数据备份到共享存储。单节点环境下可以配置一个本地文件系统仓库做快照定期执行备份任务。虽然不如集群方案完善但至少能在误删数据时有个恢复手段。监控方面Kibana 自带的 Stack Monitoring 可以看集群健康度、节点资源使用、索引读写速率等指标。对于小规模部署这套内置监控够用了。如果规模再大可以考虑接入独立的监控系统。7. 我在实际部署中攒下的几条经验折腾 ES 和 Kibana 这几年有几个体会想单独拎出来说。第一版本一致性是底线ES 和 Kibana 版本必须完全一致镜像 tag 要写死别用latest否则哪天自动更新到新版本配置不兼容就麻烦了。第二日志是你的第一手资料ES 启动失败、Kibana 连不上别急着搜解决方案先看日志90% 的问题日志里写得清清楚楚。第三测试环境和生产环境的配置要分开管理可以用docker-compose.override.yml做环境差异化配置基础配置放docker-compose.yml生产特有的安全、资源限制放 override 文件避免改来改去改混了。最后分享一个小技巧如果你经常需要重建环境可以把常用的索引模板、初始数据导入脚本写成一个初始化脚本容器启动后自动执行。这样每次重建环境不用手动再建一遍索引省时省力。这个脚本可以用 Kibana 的 Dev Tools 手动跑也可以写成 shell 脚本通过curl调用 ES 的 API 执行。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑