19_observability/19.2_elk.md
ELK (Elasticsearch,Logstash,Kibana) 是目前业界最流行的开源日志解决方案。而在容器领域,由于 Fluentd 更加轻量级且对容器支持更好,EFK (Elasticsearch,Fluentd,Kibana) 组合也变得非常流行。
我们将采用以下架构:
我们将使用 Docker Compose 来一键部署整个日志堆栈。
compose.yaml (或 docker-compose.yml) 配置如下。版本提示:本示例使用 Elasticsearch 9.x、Kibana 9.x、Fluentd 等组件的特定版本号,仅作为参考。生产环境部署前,请查阅 Elastic 官方文档 和 Fluentd 官方文档 确认最新版本与配置兼容性。services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:9.3.3
container_name: elasticsearch
environment:
- "discovery.type=single-node"
- "xpack.security.enabled=false"
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- logging
kibana:
image: docker.elastic.co/kibana/kibana:9.3.3
container_name: kibana
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
links:
- elasticsearch
networks:
- logging
fluentd:
# elasticsearch8 插件通过 REST API 与 ES 9.x 兼容
image: fluent/fluentd-kubernetes-daemonset:v1.17-debian-elasticsearch8-1
container_name: fluentd
environment:
- "FLUENT_ELASTICSEARCH_HOST=elasticsearch"
- "FLUENT_ELASTICSEARCH_PORT=9200"
- "FLUENT_ELASTICSEARCH_SCHEME=http"
- "FLUENT_UID=0"
ports:
- "24224:24224"
- "24224:24224/udp"
links:
- elasticsearch
volumes:
- ./fluentd/conf:/fluentd/etc
networks:
- logging
volumes:
es_data:
networks:
logging:
创建 fluentd/conf/fluent.conf:
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
<match *.**>
@type copy
<store>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix docker
logstash_dateformat %Y%m%d
include_tag_key true
tag_key @log_name
flush_interval 1s
</store>
<store>
@type stdout
</store>
</match>
启动一个测试容器,指定日志驱动为 fluentd:
docker run -d \
--log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag=nginx-test \
--name nginx-test \
nginx
注意:确保 fluentd 容器已经启动并监听在 localhost:24224。在生产环境中,如果你是在不同机器上,需要将 localhost 替换为运行 fluentd 的主机 IP。
http://localhost:5601。docker-* (我们在 fluent.conf 中配置的前缀)。@timestamp 作为时间字段。首次接入 EFK/ELK 时,“Elasticsearch 有数据但 Kibana 看不到”很常见,通常是 Kibana 配置或时间窗口问题:
_cat/indices 查看真实索引名。@timestamp,一般选择它;如果选择了错误的字段,会导致 Discover 无法按时间筛选。当你在 Kibana 看不到日志时,建议先跳过 UI,从存储端直接验证“日志是否入库”。
查看索引是否创建:
curl -s http://localhost:9200/_cat/indices?v
如果 Fluentd 使用了 logstash_format true 且 logstash_prefix docker,通常会看到形如 docker-YYYY.MM.DD 的索引。
查看最近一段时间的日志文档:
curl -s -H 'Content-Type: application/json' \
http://localhost:9200/docker-*/_search \
-d '{"size":1,"sort":[{"@timestamp":"desc"}]}'
如果 Elasticsearch 中已经有文档,但 Kibana 仍然为空,常见原因是:
docker-* 但实际索引前缀不同)。通过 Docker 的日志驱动机制,结合 ELK/EFK 强大的收集和分析能力,我们可以轻松构建一个能够处理海量日志的监控平台,这对于排查生产问题至关重要。
在生产环境中,日志系统往往比监控系统更容易因为“容量与写入压力”出问题,建议特别关注:
ES_JAVA_OPTS 外,生产环境需要结合节点内存、分片规模、查询压力做评估。trace_id、request_id、service、env),以便快速过滤与关联分析。无论是 EFK 还是 ELK,生产上都需要回答两个问题:
建议按环境与业务重要性对日志分层,并制定不同的保留周期,例如:
实现方式通常有两类:
docker-YYYY.MM.DD,再定期删除过期索引。对于中小规模集群,先把“按天滚动 + 过期删除”做扎实,往往就能解决 80% 的容量问题;当日志量上来、查询压力变大后,再逐步引入 ILM、分层存储与更精细的分片规划。
如果你采用按天滚动索引 (例如 docker-YYYY.MM.DD),可以通过 Elasticsearch API 定期清理过期索引。
下面示例仅用于演示思路:获取所有 docker- 前缀索引并删除指定索引。生产环境建议基于日期计算、灰度验证与权限控制后再执行自动化清理。
列出索引:
curl -s http://localhost:9200/_cat/indices/docker-*?v
删除某个过期索引 (示例):
curl -X DELETE http://localhost:9200/docker-2026.02.01
如果你希望更自动化的治理能力,可以进一步使用 ILM 为索引配置滚动与删除策略。