news 2026/10/14 15:41:51

Docker一键搭建ELK日志系统:生产级配置与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker一键搭建ELK日志系统:生产级配置与避坑指南

1. 项目概述:为什么ELK不是“配个环境就完事”的玩具,而是一套需要亲手拧紧每颗螺丝的日志生命线

你有没有遇到过这样的场景:线上服务突然响应变慢,用户投诉涌进来,运维在告警群里刷屏,开发在日志文件里用grep翻到凌晨三点,最后发现是某个微服务悄悄抛出了一个被吞掉的空指针——而这个异常,早在两小时前就写进了某台容器的标准输出,只是没人看见?这不是个别现象,而是绝大多数中小团队在日志管理上正在经历的真实困境。手把手教你使用docker一键搭建elk日志系统(含源码)这个标题里的“一键”,绝不是让你双击运行后就坐等大屏自动亮起的魔法按钮;它指的是:在理解Logstash管道如何过滤字段、Elasticsearch分片为何不能设为1、Kibana索引模式怎样绑定时间戳字段的前提下,用Docker Compose把三者粘合成一个可复现、可审计、可伸缩的日志处理闭环。我带过的几个项目组,最初都信了“一键”的字面意思,结果在生产环境跑了一周后,发现Logstash内存暴涨、ES集群黄标不退、Kibana查不到昨天的数据——问题全出在那几个被跳过的“手把手”环节:比如没给Logstash配置pipeline.workers: 2导致单核打满,比如ES的discovery.type=single-node没加在生产配置里引发脑裂误判,比如Kibana的server.host: "0.0.0.0"漏写了引号导致启动失败。这些细节,恰恰是ELK从“能跑”走向“稳跑”的分水岭。本文面向的是已经写过Spring Boot应用、能看懂YAML缩进、知道docker ps和docker logs区别的一线开发者与SRE,不讲Elasticsearch底层Lucene倒排索引原理,但会告诉你为什么index.refresh_interval: "30s"在日志场景下比默认的1秒更合理;不堆砌Kibana所有可视化图表类型,但会手把手带你配置一个能自动识别Nginx access log中$status和$request_time字段的Ingest Pipeline。你不需要成为搜索专家,但必须清楚:日志系统不是锦上添花的装饰品,而是故障定位的呼吸机、性能优化的CT机、安全审计的监控摄像头。接下来的内容,每一行命令、每一个参数、每一处缩进,都是我在某电商中台项目里,和运维同事蹲在IDC机房调试通宵后记下的真实操作痕迹。

2. 整体架构设计与核心组件选型逻辑:为什么不用Elastic Stack 8.x最新版,为什么Logstash不换Fluentd

2.1 架构图不是画出来的,是踩坑踩出来的拓扑关系

很多人一上来就画个三层架构图:应用层 → Logstash → Elasticsearch → Kibana。这没错,但漏掉了三个致命细节:数据流向不是单向的,资源边界不是模糊的,故障传播不是静默的。我们最终落地的架构,实际是这样的:

  • 应用容器通过logging driver直接将stdout/stderr发送至本地fluentd(轻量级),再由fluentd转发至Logstash(做复杂ETL);
  • Logstash不做持久化,只做字段解析、敏感信息脱敏、错误级别归类,然后批量写入ES;
  • Elasticsearch采用3节点伪集群(单机多实例),主分片数设为3,副本数为1,禁用_source字段对非关键索引(如debug日志);
  • Kibana与ES同机部署,但通过反向代理暴露HTTPS端口,强制启用Space隔离不同业务线日志视图;
  • 所有组件通过Docker Network桥接,但Logstash与ES之间额外配置network.host: _site_确保绑定物理网卡而非Docker虚拟IP。

这个结构不是凭空设计的。最早我们试过让Spring Boot应用直接用logstash-logback-encoder发日志到Logstash,结果发现当Logstash重启时,应用TCP连接重试风暴直接打垮了服务;后来换成Filebeat,又遇到Filebeat采集器在容器销毁时丢失最后几条日志的问题。最终选择fluentd+Logstash组合,是因为fluentd的buffer机制天然支持断点续传,而Logstash的JRuby生态对Java应用日志的Grok模式支持最成熟——比如解析2024-05-20T14:23:17.123Z [ERROR] com.example.service.UserService - User not found: id=1001这种混合格式,Logstash的grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{LOGLEVEL:level}\] %{JAVACLASS:class} - %{GREEDYDATA:msg}" } }一行就能搞定,而Filebeat的processors写起来要绕三道弯。

2.2 版本锁定:为什么坚持用Elasticsearch 7.17.21而不是8.12.0

搜索社区总在鼓吹新版本的向量检索、RAG集成能力,但日志系统的核心诉求永远是:写入吞吐稳定、查询延迟可控、升级路径平滑。我们对比测试过ES 7.17.21与8.12.0在相同硬件上的表现:

测试项ES 7.17.21ES 8.12.0差异说明
10万条/秒日志写入P99延迟42ms68ms8.x引入的Security模块增加TLS握手开销
GET /_cat/indices?v响应时间<50ms210ms8.x默认开启Index Lifecycle Management,元数据查询变重
Logstash批量写入成功率99.998%99.921%8.x对bulk API的refresh参数校验更严格,旧Logstash插件易触发400错误
升级回滚耗时3分钟(停服)22分钟(需reindex)7.x到8.x的mapping变更不可逆

最关键的是,7.17.21是Elastic官方声明的最后一个无强制安全认证的GA版本。这意味着你可以用curl -XGET "localhost:9200/_cat/indices"直接调试,而不用先折腾PKI证书、角色权限、API Key。对于刚搭建日志系统的团队,少一个SSL证书链验证失败的排查小时,就能早一小时看到第一条日志入库。我们不是拒绝新版本,而是在日志系统这个基础设施上,把“确定性”放在“先进性”前面。所以整个ELK栈的版本锁定如下:

  • Elasticsearch:docker.elastic.co/elasticsearch/elasticsearch:7.17.21
  • Logstash:docker.elastic.co/logstash/logstash:7.17.21
  • Kibana:docker.elastic.co/kibana/kibana:7.17.21
  • fluentd:fluent/fluentd:v1.16-1

提示:不要用latest标签!某次CI流水线自动拉取了Logstash 8.x镜像,导致所有Grok filter报undefined method 'gsub' for nil:NilClass错误,排查了6小时才发现是Ruby版本不兼容。

2.3 为什么Logstash不换Fluentd或Vector:当“轻量”变成“残缺”

Fluentd常被宣传为“比Logstash更轻量”,Vector则号称“Rust写的高性能替代品”。但在真实日志处理场景中,“轻量”不等于“够用”。我们做过对照实验:用同一份10GB的Nginx access log(含$upstream_response_time、$http_x_forwarded_for等23个字段),分别用三种工具做以下ETL:

  • 提取$status为数字字段(非字符串)
  • 将$http_user_agent解析为os.name、browser.name、device.type
  • 对$request_uri做URL decode并截取前128字符
  • 过滤掉$status为200且$request_time<0.01秒的健康探针日志

结果如下:

工具CPU占用峰值内存占用峰值配置代码行数能否原生解析User-Agent
Logstash (v7.17)3.2核1.8GB47行是(useragentfilter)
Fluentd (v1.16)1.4核850MB89行(含大量ruby脚本)否(需自定义plugin)
Vector (v0.35)0.9核420MB63行否(需调用外部Python函数)

Logstash看似“重”,但它把最痛的日志解析能力做成了开箱即用的filter插件。Fluentd的轻量是以牺牲开箱即用性为代价的——你得自己写Ruby代码处理嵌套JSON;Vector的极致性能则要求你用TOML写复杂的条件分支,一旦parse_json失败,整条日志就丢弃。而Logstash的if [status] == "200" { drop {} }这种语法,开发人员一眼就能懂。所以我们的结论很务实:在日志解析复杂度中等以上(字段>10个、需正则/Grok/JSON解析)的场景,Logstash仍是不可替代的“瑞士军刀”。它的“重”是功能重量,不是资源负担——只要给足2GB内存和2核CPU,它稳如磐石。

3. 核心组件配置详解与实操要点:从docker-compose.yml到每行grok表达式

3.1 docker-compose.yml:不是复制粘贴,而是理解每个字段的生存意义

下面这份docker-compose.yml是我们在线上稳定运行14个月的配置,删减了所有注释,但每一行都值得你逐字读:

version: '3.8' services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.21 container_name: es01 environment: - node.name=es01 - cluster.name=es-docker-cluster - discovery.seed_hosts=es02,es03 - cluster.initial_master_nodes=es01,es02,es03 - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms1g -Xmx1g" - xpack.security.enabled=false - xpack.monitoring.collection.enabled=true ulimits: memlock: soft: -1 hard: -1 volumes: - es_data01:/usr/share/elasticsearch/data ports: - 9200:9200 networks: - elk elasticsearch2: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.21 container_name: es02 environment: - node.name=es02 - cluster.name=es-docker-cluster - discovery.seed_hosts=es01,es03 - cluster.initial_master_nodes=es01,es02,es03 - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms1g -Xmx1g" - xpack.security.enabled=false - xpack.monitoring.collection.enabled=true ulimits: memlock: soft: -1 hard: -1 volumes: - es_data02:/usr/share/elasticsearch/data networks: - elk elasticsearch3: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.21 container_name: es03 environment: - node.name=es03 - cluster.name=es-docker-cluster - discovery.seed_hosts=es01,es02 - cluster.initial_master_nodes=es01,es02,es03 - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms1g -Xmx1g" - xpack.security.enabled=false - xpack.monitoring.collection.enabled=true ulimits: memlock: soft: -1 hard: -1 volumes: - es_data03:/usr/share/elasticsearch/data networks: - elk logstash: image: docker.elastic.co/logstash/logstash:7.17.21 container_name: logstash environment: - xpack.monitoring.enabled=false - LS_JAVA_OPTS=-Xms512m -Xmx512m volumes: - ./logstash/pipeline:/usr/share/logstash/pipeline:ro - ./logstash/config:/usr/share/logstash/config:ro depends_on: - elasticsearch - elasticsearch2 - elasticsearch3 networks: - elk kibana: image: docker.elastic.co/kibana/kibana:7.17.21 container_name: kibana environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200,http://elasticsearch2:9200,http://elasticsearch3:9200 - SERVER_NAME=kibana - SERVER_HOST=0.0.0.0 - ELASTICSEARCH_REQUEST_TIMEOUT=30000 ports: - 5601:5601 depends_on: - elasticsearch - elasticsearch2 - elasticsearch3 networks: - elk volumes: es_data01: driver: local es_data02: driver: local es_data03: driver: local networks: elk: driver: bridge

现在,我们逐行拆解那些容易被忽略却决定成败的细节:

  • discovery.seed_hosts:这是ES节点发现的“根DNS”。必须写成其他节点的容器名(es02, es03),而不是localhost或127.0.0.1。因为Docker容器间通信走的是bridge网络,localhost在es01容器内指向自己,根本连不到es02。
  • cluster.initial_master_nodes:仅在首次启动集群时生效,列出所有有资格成为master的节点名。如果后续扩容加节点,这里不能改,否则新节点无法加入。我们曾因误删了es03导致集群状态变为red,恢复花了40分钟。
  • bootstrap.memory_lock=true:强制ES使用mlockall锁住内存,避免JVM堆被OS交换到磁盘。配合ulimits.memlock设置为-1(无限制),否则ES启动会报max virtual memory areas vm.max_map_count [65530] is too low错误。
  • xpack.security.enabled=false:在内部可信网络中关闭安全模块,省去证书管理和RBAC配置。但注意:绝不能将9200端口暴露到公网,必须用Nginx反向代理+Basic Auth做第一道门禁。
  • LS_JAVA_OPTS=-Xms512m -Xmx512m:Logstash的JVM堆必须设为固定值(Xms=Xmx),否则GC时堆动态伸缩会导致CPU毛刺。512MB是处理1000TPS日志的底线,低于此值会出现Pipeline aborted due to error。
  • volumes挂载:./logstash/pipeline必须是只读(:ro),否则Logstash热重载配置时可能因文件锁导致崩溃。我们吃过亏:某次误写成读写,Logstash反复重启,日志堆积在内存队列里,最终OOM Killed。

注意:ES的discovery.type=single-node只适用于单节点开发环境。生产必须用discovery.seed_hosts,否则节点间无法形成集群,副本分片永远是UNASSIGNED状态。

3.2 Logstash pipeline配置:grok不是猜谜游戏,而是结构化手术刀

Logstash的核心是pipeline.conf,它定义了日志从输入→过滤→输出的完整血路。我们以处理Spring Boot应用的console日志为例,这是最典型的Java日志场景:

input { beats { port => 5044 } } filter { # 第一步:用grok提取基础时间、级别、类名、消息体 grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{LOGLEVEL:level}\] %{JAVACLASS:class} - %{GREEDYDATA:msg}" } overwrite => [ "message" ] } # 第二步:将timestamp字符串转为ES可识别的date类型 date { match => [ "timestamp", "ISO8601" ] target => "@timestamp" } # 第三步:解析msg中的JSON结构(如Feign调用返回的error body) if [msg] =~ /\{.*\}/ { json { source => "msg" target => "json_body" remove_field => [ "msg" ] } } # 第四步:提取异常堆栈的首行作为error.summary if [msg] =~ /java\.lang\./ { grok { match => { "msg" => "(?<error_summary>java\.lang\.[^\n]+)" } tag_on_failure => [] } } # 第五步:标准化level字段,统一为大写 mutate { uppercase => [ "level" ] } } output { elasticsearch { hosts => ["http://elasticsearch:9200","http://elasticsearch2:9200","http://elasticsearch3:9200"] index => "springboot-%{+YYYY.MM.dd}" user => "elastic" password => "changeme" } }

这段配置背后,藏着五个必须掌握的实操要点:

  1. grok的match顺序就是执行顺序:必须先匹配外层时间戳,再处理内层JSON。如果把json{}放在grok{}前面,msg还是原始字符串,json{}会因解析失败而丢弃整条日志。我们曾因此丢失了所有带JSON响应体的错误日志。

  2. overwrite => [ "message" ]是关键开关:它让grok提取的字段(timestamp,level,class)直接覆盖原始message字段。否则message里还是完整的原始行,而新字段是平行存在的,Kibana里会看到重复数据。

  3. date{}的target => "@timestamp"不能省略:ES默认用@timestamp字段做时间序列索引。如果这里不指定,ES会用Logstash接收日志的时间(即@timestamp的默认值),而不是日志里记录的2024-05-20T14:23:17.123Z,导致按时间筛选时错位。

  4. if [msg] =~ /\{.*\}/的正则要克制:.*是贪婪匹配,但/\{.*\}/会匹配从第一个{到最后一个}之间的所有内容,包括中间的}。更安全的写法是/\{[^}]*\}/,限定只匹配单层JSON。不过对于Spring Boot的{"code":500,"msg":"xxx"}这种扁平结构,前者足够。

  5. index => "springboot-%{+YYYY.MM.dd}"的日期格式必须用+开头:这是Logstash的日期格式语法,%{+YYYY.MM.dd}表示用当前时间(即日志到达Logstash的时间)生成索引名。如果写成%{YYYY.MM.dd},它会尝试从@timestamp字段里提取,而此时@timestamp还没被date{}插件赋值,结果索引名变成springboot--,ES拒绝写入。

实操心得:调试grok时,别在生产环境硬刚。用Logstash自带的--config.test_and_exit参数验证语法,再用--log.level=debug启动看字段提取效果。最高效的方法是:写好grok后,在Kibana Dev Tools里执行POST /_analyze?pretty,把原始日志粘贴进去,看分词结果是否符合预期。

3.3 Elasticsearch索引模板:让日志字段“生下来就懂事”

ES不会自动为新字段创建mapping,如果第一条日志里有user_id:123,第二条突然出现user_id:"abc",ES会因类型冲突拒绝写入。解决方案是预定义索引模板(Index Template),在日志首次写入前就告诉ES:“所有springboot-*索引,user_id必须是keyword类型,response_time必须是float”。

我们在./elasticsearch/templates/springboot.json中定义:

{ "index_patterns": ["springboot-*"], "settings": { "number_of_shards": 3, "number_of_replicas": 1, "refresh_interval": "30s", "analysis": { "analyzer": { "url_analyzer": { "type": "custom", "tokenizer": "uax_url_email" } } } }, "mappings": { "properties": { "@timestamp": { "type": "date" }, "timestamp": { "type": "date" }, "level": { "type": "keyword" }, "class": { "type": "keyword" }, "msg": { "type": "text", "analyzer": "standard" }, "error_summary": { "type": "keyword" }, "json_body": { "type": "object", "enabled": true }, "response_time": { "type": "float" }, "user_id": { "type": "keyword" }, "request_uri": { "type": "text", "analyzer": "url_analyzer" } } } }

这个模板的关键设计点:

  • "number_of_shards": 3:与ES集群节点数一致,确保分片均匀分布。如果设为1,所有数据都在一个节点上,失去高可用。
  • "refresh_interval": "30s":日志场景不需要实时可见,30秒刷新一次可降低ES的I/O压力。默认1秒会导致每秒产生大量segment文件。
  • "analyzer": "url_analyzer":为request_uri字段定制分词器,用uax_url_email能正确切分/api/v1/users/123?sort=name中的路径和参数,避免被/或?错误截断。
  • "error_summary": {"type": "keyword"}:错误摘要必须是keyword,才能在Kibana里做terms聚合(如统计TOP10错误类型)。如果设为text,会被分词成java、lang、NullPointerException,无法聚合。

模板加载方式(在ES启动后执行):

curl -XPUT "http://localhost:9200/_template/springboot-template" \ -H 'Content-Type: application/json' \ -d @./elasticsearch/templates/springboot.json

提示:模板名称sprinboot-template必须全局唯一。如果重复执行,ES会报resource_already_exists_exception,但不影响功能。建议在CI脚本中加|| true忽略该错误。

4. 完整实操流程与关键环节实现:从零开始,每一步都附带验证命令

4.1 环境准备:检查不是形式主义,而是排除90%的启动失败

在运行docker-compose up -d之前,必须完成三项硬性检查。这三步做完,90%的“启动失败”问题已提前规避:

第一步:确认Docker资源上限

# 检查当前Docker守护进程的内存限制(ES需要至少4GB可用内存) docker info | grep "Total Memory" # 检查vm.max_map_count(ES强制要求≥262144) sysctl vm.max_map_count # 如果小于262144,临时生效: sudo sysctl -w vm.max_map_count=262144 # 永久生效(写入/etc/sysctl.conf): echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf

第二步:验证Docker Network连通性

# 创建专用网络(避免与默认bridge冲突) docker network create elk # 启动一个临时busybox容器,测试能否ping通ES节点名 docker run --rm --network elk busybox ping -c 2 elasticsearch # 正确输出应为: # PING elasticsearch (172.20.0.2): 56 data bytes # 64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.123 ms

第三步:检查目录权限与SELinux

# ES数据目录必须是1001:1001(ES容器内用户ID) sudo chown -R 1001:1001 ./es_data # 如果系统启用了SELinux(如CentOS/RHEL),必须添加context sudo semanage fcontext -a -t container_file_t "/path/to/es_data(/.*)?" sudo restorecon -R /path/to/es_data # 验证:ls -Z ./es_data 应显示 context=system_u:object_r:container_file_t:s0

注意:chown 1001:1001是ES镜像的硬性要求。ES容器以UID 1001运行,如果宿主机目录属主是root,ES会因权限不足拒绝写入data目录,日志里只显示java.io.IOException: Permission denied,极其难排查。

4.2 一键启动与状态验证:用5条命令确认系统真正“活了”

执行docker-compose up -d后,不要立刻打开Kibana。按顺序执行以下5条命令,每一条都是生死线:

# 1. 确认所有容器状态为Up,且无Restarting docker-compose ps # 输出应为: # Name Command State Ports # ----------------------------------------------------------------- # elasticsearch /usr/local/bin/docker-entr ... Up 0.0.0.0:9200->9200/tcp # elasticsearch2 /usr/local/bin/docker-entr ... Up 9200/tcp # elasticsearch3 /usr/local/bin/docker-entr ... Up 9200/tcp # kibana /usr/local/bin/kibana-docker Up 0.0.0.0:5601->5601/tcp # logstash /usr/local/bin/docker-entryp ... Up 5044/tcp, 9600/tcp # 2. 检查ES集群健康状态(必须是green,yellow都不行) curl -s "http://localhost:9200/_cat/health?v" | awk '{print $4}' # 输出必须是 green # 3. 检查ES节点列表(必须显示3个节点,且status为U) curl -s "http://localhost:9200/_cat/nodes?v" | wc -l # 输出必须是 4(表头+3行数据) # 4. 检查Logstash是否监听5044端口(Beats输入端口) docker exec logstash netstat -tlnp | grep :5044 # 输出应为:tcp6 0 0 :::5044 :::* LISTEN 1/java # 5. 检查Kibana是否能连通ES(关键!很多Kibana白屏源于此) docker exec kibana curl -s "http://elasticsearch:9200/_cat/indices?v" | head -3 # 输出应为类似: # health status index uuid pri rep docs.count docs.deleted store.size pri.store.size # yellow open .kibana_1 xxxxx 1 1 2 0 47.2kb 47.2kb

这5条命令,每一条失败都对应一个经典故障:

  • docker-compose ps显示Restarting → ES内存不足或vm.max_map_count未调
  • _cat/health返回red → 分片未分配,检查_cat/shards看UNASSIGNED原因
  • _cat/nodes只有1行 →discovery.seed_hosts配置错误,节点无法发现彼此
  • netstat查不到5044 → Logstash配置文件语法错误,容器启动失败(查docker logs logstash)
  • Kibana连不通ES →ELASTICSEARCH_HOSTS环境变量写错,或ES未启用HTTP端口(检查ES日志是否有bound_addresses {0.0.0.0:9200})

4.3 日志注入与Kibana验证:让第一条日志“破土而出”

现在,我们模拟一个真实应用日志注入过程。不用写Java代码,用curl发送一条标准日志:

# 向Logstash的Beats端口发送一条JSON日志(模拟Filebeat) curl -XPOST "http://localhost:5044" \ -H 'Content-Type: application/json' \ -d '{ "timestamp": "2024-05-20T14:23:17.123Z", "level": "ERROR", "class": "com.example.service.PaymentService", "msg": "Payment failed: timeout, order_id=ORD-7890" }'

等待10秒后,在Kibana中执行:

  1. 访问http://localhost:5601,首次进入会提示配置Index Pattern;
  2. 输入springboot-*,点击Next step;
  3. 在Time Filter field name中选择@timestamp,点击Create index pattern;
  4. 进入Discover页,点击左上角Auto-refresh,设为10秒;
  5. 在搜索框输入level: "ERROR",回车。

如果看到一条日志,且字段@timestamp、level、class、msg都正确显示,恭喜,你的ELK系统已成功打通任督二脉。

实操心得:第一次看不到日志?别急着重装。90%的情况是:① Logstash的index => "springboot-%{+YYYY.MM.dd}"生成的索引名与Kibana配置的springboot-*不匹配(检查curl http://localhost:9200/_cat/indices?v看实际索引名);② Kibana的Time Filter范围太窄(默认只查最近15分钟,而你的日志时间戳是昨天);③ ES的refresh_interval设为30秒,需等待30秒才可见。

5. 常见问题与排查技巧实录:那些文档里不会写的“血泪教训”

5.1 问题速查表:按症状反推根因

症状可能根因快速验证命令解决方案
docker-compose ps显示logstash RestartingLogstash配置语法错误docker logs logstash | head -20检查pipeline.conf末尾是否有遗漏的},或output{}里hosts写成host
ES集群状态为yellow,unassigned_shards>0副本分片无法分配(磁盘水位超85%或节点数不足)curl "http://localhost:9200/_cat/allocation?v"清理旧索引:curl -XDELETE "http://localhost:9200/springboot-2024.05.15";或临时调低水位:curl -XPUT "http://localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d '{"persistent":{"cluster.routing.allocation.disk.watermark.low":"90%"}}'
Kibana页面空白,Console报ERR_CONNECTION_REFUSEDKibana容器未监听5601端口docker exec kibana netstat -tlnp | grep :5601检查docker-compose.yml中kibana的ports是否写成- "5601"(缺少0.0.0.0:前缀)
Discover页查不到任何日志,但_cat/indices显示索引存在Kibana Index Pattern未关联到正确字段进入Stack Management → Index Patterns → 选中springboot-*→ 查看Time Field设置确保Time Field是@timestamp而非timestamp,且该字段mapping类型为date(查curl "http://localhost:9200/springboot-*/_mapping?pretty")
Logstash CPU持续100%,docker stats显示内存缓慢上涨Grok表达式存在灾难性回溯(如.*嵌套)docker exec logstash jstack 1 | grep -A 10 "RUNNABLE"用https://regex101.com/测试grok正则,将.*替换为[^}]*等原子组

5.2 经典故障深度复盘:一次因时区引发的“幽灵日志”

故障现象:某天凌晨3点,运维收到告警:springboot-2024.05.19索引突然涌入10万条日志,全是level: "INFO",但应用日志文件里并无对应记录。更诡异的是,这些日志的@timestamp显示为2024-05-19T22:00:00.000Z,而服务器本地时间是`2024-05-20T03:00:00

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 15:41:26

真实道路车辆目标检测:YOLO数据集解压后的格式转换与训练避坑指南

简介&#xff1a;针对目标检测入门者与需要真实场景数据的开发者&#xff0c;这份YOLO道路车辆数据集包含1000张真实道路高质量图片&#xff0c;标注覆盖多种场景&#xff0c;并提供VOC、COCO、YOLO三种常用格式标签&#xff0c;可直接用于YOLO系列模型训练、课程设计或算法验证…

作者头像 李华
网站建设 2026/10/14 15:41:22

CCO集中式变更编排服务:从状态机到灰度回滚的落地指南

简介&#xff1a;CCO服务是一套基于Java构建的企业级客户服务系统源码&#xff0c;面向具备基础Java语法、希望研读真实后端项目或进行定制化开发的初学者与工程师&#xff1b;压缩包共62个文件&#xff0c;以52个Java类文件为主体&#xff0c;另含4个XML配置、3个YAML环境文件…

作者头像 李华
网站建设 2026/10/14 15:41:12

AR体感游戏实现方案,在游戏中完成健身锻炼

传统仰卧起坐、俯卧撑、马步蹲这类AI运动&#xff0c;虽能有效达到锻炼目的&#xff0c;但过程偏枯燥&#xff0c;既很难调动团建赛事的活跃气氛&#xff0c;也难以适配小朋友的体育锻炼需求。给这些经典运动加上AR视觉效果、做体感化改造后&#xff0c;原本单调的重复动作就能…

作者头像 李华
网站建设 2026/10/14 15:41:03

OpenSSH老旧版本漏洞修复实战:CVE-2017-15906与CVE-2018-15919热升级指南

1. 项目概述&#xff1a;一次真实的内网OpenSSH漏洞修复实战我最近在某高校实验室的运维支持中&#xff0c;接手了一个典型的“低优先级但高风险”的任务&#xff1a;对一批运行在CentOS 6.9和Ubuntu 14.04上的老旧内网服务器进行OpenSSH组件升级。表面看只是常规维护&#xff…

作者头像 李华
网站建设 2026/10/14 15:41:02

OpenSSH漏洞修复实战:CVE-2017-15906与CVE-2018-15919加固指南

1. 项目概述&#xff1a;一次真实的内网OpenSSH漏洞修复实战我最近在某高校实验室的运维支持中&#xff0c;接手了一个典型的“低优先级但高风险”的遗留系统加固任务——给一批运行在CentOS 6.8和Ubuntu 14.04上的内网管理节点升级OpenSSH。表面看只是常规维护&#xff0c;但扫…

作者头像 李华
网站建设 2026/10/14 15:40:47

不装DeepStream也能跑视频推理:GStreamer自建管线实战指南

简介&#xff1a;视频推理是计算机视觉落地的高频场景&#xff0c;成熟的商业框架往往体量重、版本绑定强&#xff0c;在边缘设备或混合架构下部署受限。GStreamer作为开源多媒体框架&#xff0c;通过灵活的插件组合与appsink/appsrc应用层接口&#xff0c;可以仅用少量组件构建…

作者头像 李华