返回首页返回书籍《Docker 从入门到实践》
目录

目录 · CONTENTS

  1. 01前言
  2. 02修订记录
  3. 03如何贡献
  4. 04第一章 Docker 简介
  5. 051.1 快速上手
  6. 061.2 什么是 Docker
  7. 071.3 为什么要用 Docker
  8. 08本章小结
  9. 09第二章 基本概念
  10. 102.1 镜像
  11. 112.2 容器
  12. 122.3 仓库
  13. 13本章小结
  14. 14第三章 安装 Docker
  15. 153.1 Ubuntu
  16. 163.2 Debian
  17. 173.3 Fedora
  18. 183.4 CentOS
  19. 193.5 Raspberry Pi
  20. 203.6 Linux 离线安装
  21. 213.7 macOS
  22. 223.8 Windows 10/11
  23. 233.9 镜像加速器
  24. 243.10 开启实验特性
  25. 25本章小结
  26. 26第四章 使用镜像
  27. 274.1 获取镜像
  28. 284.2 列出镜像
  29. 294.3 删除本地镜像
  30. 304.4 利用 commit 理解镜像构成
  31. 314.5 使用 Dockerfile 定制镜像
  32. 324.6 其他制作镜像的方式
  33. 334.7 实现原理
  34. 34本章小结
  35. 35第五章 操作容器
  36. 365.1 启动
  37. 375.2 守护态运行
  38. 385.3 终止
  39. 395.4 进入容器
  40. 405.5 导出和导入
  41. 415.6 删除
  42. 42本章小结
  43. 43第六章 访问仓库
  44. 446.1 Docker Hub
  45. 456.2 私有仓库
  46. 466.3 私有仓库高级配置
  47. 476.4 Nexus 3
  48. 48本章小结
  49. 49第七章 Dockerfile 指令详解
  50. 507.1 RUN 执行命令
  51. 517.2 COPY 复制文件
  52. 527.3 ADD 更高级的复制文件
  53. 537.4 CMD 容器启动命令
  54. 547.5 ENTRYPOINT 入口点
  55. 557.6 ENV 设置环境变量
  56. 567.7 ARG 构建参数
  57. 577.8 VOLUME 定义匿名卷
  58. 587.9 EXPOSE 暴露端口
  59. 597.10 WORKDIR 指定工作目录
  60. 607.11 USER 指定当前用户
  61. 617.12 HEALTHCHECK 健康检查
  62. 627.13 ONBUILD 为他人作嫁衣裳
  63. 637.14 LABEL 为镜像添加元数据
  64. 647.15 SHELL 指令
  65. 657.16 参考文档
  66. 667.17 多阶段构建
  67. 677.18 实战多阶段构建 Laravel 镜像
  68. 68本章小结
  69. 69第八章 数据管理
  70. 708.1 数据卷
  71. 718.2 挂载主机目录
  72. 728.3 tmpfs 挂载
  73. 73本章小结
  74. 74第九章 网络配置
  75. 759.1 配置 DNS
  76. 769.2 网络类型
  77. 779.3 自定义网络
  78. 789.4 容器互联
  79. 799.5 外部访问容器
  80. 809.6 网络隔离
  81. 819.7 容器网络高级特性
  82. 82本章小结
  83. 83第十章 Docker Buildx
  84. 8410.1 BuildKit
  85. 8510.2 使用 buildx 构建镜像
  86. 8610.3 使用 buildx 构建多种系统架构支持的 Docker 镜像
  87. 87本章小结
  88. 88第十一章 Docker Compose
  89. 8911.1 简介
  90. 9011.2 安装与卸载
  91. 9111.3 使用
  92. 9211.4 命令说明
  93. 9311.5 Compose 模板文件
  94. 9411.6 实战 Django
  95. 9511.7 实战 Rails
  96. 9611.8 实战 WordPress
  97. 9711.9 实战 LNMP
  98. 98本章小结
  99. 99第十二章 底层实现
  100. 10012.1 基本架构
  101. 10112.2 命名空间
  102. 10212.3 控制组
  103. 10312.4 联合文件系统
  104. 10412.5 容器格式
  105. 10512.6 网络
  106. 106本章小结
  107. 107第十三章 容器编排基础
  108. 10813.1 简介
  109. 10913.2 基本概念
  110. 11013.3 架构设计
  111. 11113.4 高级特性
  112. 11213.5 实战练习
  113. 113本章小结
  114. 114第十四章 部署 Kubernetes
  115. 11514.1 使用 kubeadm 部署 Kubernetes
  116. 11614.2 使用 kubeadm 部署 Kubernetes:使用 Docker
  117. 11714.3 在 Docker Desktop 使用
  118. 11814.4 Kind - Kubernetes IN Docker
  119. 11914.5 K3s - 轻量级 Kubernetes
  120. 12014.6 一步步部署 Kubernetes 集群
  121. 12114.7 可视化管理界面
  122. 12214.8 Kubernetes 命令行 kubectl
  123. 123本章小结
  124. 124第十五章 Etcd 项目
  125. 12515.1 简介
  126. 12615.2 安装
  127. 12715.3 集群
  128. 12815.4 使用 etcdctl
  129. 129本章小结
  130. 130第十六章 容器与云计算
  131. 13116.1 简介
  132. 13216.2 腾讯云
  133. 13316.3 阿里云
  134. 13416.4 亚马逊云
  135. 13516.5 多云部署策略
  136. 136本章小结
  137. 137第十七章 容器其他生态
  138. 13817.1 Fedora CoreOS 简介
  139. 13917.2 Fedora CoreOS 安装
  140. 14017.3 Podman - 下一代 Linux 容器工具
  141. 14117.4 Buildah - 容器镜像构建工具
  142. 14217.5 Skopeo - 容器镜像管理工具
  143. 14317.6 containerd - 核心容器运行时
  144. 14417.7 安全容器运行时
  145. 14517.8 WebAssembly 与容器
  146. 146本章小结
  147. 147第十八章 安全
  148. 14818.1 内核命名空间
  149. 14918.2 控制组
  150. 15018.3 服务端防护
  151. 15118.4 内核能力机制
  152. 15218.5 其他安全特性
  153. 15318.6 容器镜像安全扫描与供应链安全
  154. 154本章小结
  155. 155第十九章 容器监控与日志
  156. 15619.1 Prometheus
  157. 15719.2 ELK 套件
  158. 15819.3 容器性能优化与故障诊断
  159. 159本章小结
  160. 160第二十章 实战案例 - 操作系统
  161. 16120.1 Busybox
  162. 16220.2 Alpine
  163. 16320.3 Debian Ubuntu
  164. 16420.4 CentOS Fedora
  165. 165本章小结
  166. 166第二十一章 实战案例 - DevOps
  167. 16721.1 DevOps 完整工作流
  168. 16821.2 GitHub Actions
  169. 16921.3 Drone
  170. 17021.4 Drone Demo
  171. 17121.5 在 IDE 中使用 Docker
  172. 17221.6 VS Code
  173. 17321.7 实战案例:Go/Rust/数据库/微服务
  174. 174本章小结
  175. 175附录
  176. 176附录一:常见问题与错误速查
  177. 177常见错误处理
  178. 178附录二:热门镜像介绍
  179. 179Ubuntu
  180. 180CentOS
  181. 181Nginx
  182. 182PHP
  183. 183Node.js
  184. 184MySQL
  185. 185WordPress
  186. 186MongoDB
  187. 187Redis
  188. 188Minio
  189. 189附录三:Docker 命令查询
  190. 190客户端命令 - docker
  191. 191服务端命令 - dockerd
  192. 192附录四:Dockerfile 最佳实践
  193. 193附录五:如何调试 Docker
  194. 194附录六:资源链接
  195. 195附录七:术语表
  196. 196附录八:Docker 学习路线图与知识体系
第 157 / 196 节

第 157 节 · SECTION 157

19.2 ELK 套件

19.2 ELK 套件

ELK (Elasticsearch,Logstash,Kibana) 是目前业界最流行的开源日志解决方案。而在容器领域,由于 Fluentd 更加轻量级且对容器支持更好,EFK (Elasticsearch,Fluentd,Kibana) 组合也变得非常流行。

19.2.1 方案架构

我们将采用以下架构:

  1. Docker Container:容器将日志输出到标准输出 (stdout/stderr)。
  2. Fluentd:作为 Docker 的 Logging Driver 或运行为守护容器,收集容器日志。
  3. Elasticsearch:存储从 Fluentd 接收到的日志数据。
  4. Kibana:从 Elasticsearch 读取数据并进行可视化展示。

19.2.2 部署流程

我们将使用 Docker Compose 来一键部署整个日志堆栈。

1. 编写 Compose 文件

  1. 编写 compose.yaml(或 docker-compose.yml)配置如下。版本提示:本示例使用 Elasticsearch 9.x、Kibana 9.x、Fluentd 等组件的特定版本号,仅作为参考。生产环境部署前,请查阅 Elastic 官方文档 和 Fluentd 官方文档 确认最新版本与配置兼容性。
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:9.4.0
    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.4.0
    container_name: kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    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"
    volumes:
      - ./fluentd/conf:/fluentd/etc
    networks:
      - logging

volumes:
  es_data:

networks:
  logging:

2. 配置 Fluentd

创建 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>

3. 配置应用容器使用 fluentd 驱动

启动一个测试容器,指定日志驱动为 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。

4. 在 Kibana 中查看日志

  1. 访问 http://localhost:5601。
  2. 进入 Management->Kibana->Index Patterns。
  3. 创建新的 Index Pattern,输入 docker-*(我们在 fluent.conf 中配置的前缀)。
  4. 选择 @timestamp 作为时间字段。
  5. 去 Discover 页面,你就能看到 Nginx 容器的日志了。

Kibana 建索引模式常见坑

首次接入 EFK/ELK 时,“Elasticsearch 有数据但 Kibana 看不到”很常见,通常是 Kibana 配置或时间窗口问题:

  • Index Pattern 不匹配:确认 Kibana 的 Index Pattern 与实际索引前缀一致。可以先用 _cat/indices 查看真实索引名。
  • 时间字段选择错误:若索引里包含 @timestamp,一般选择它;如果选择了错误的字段,会导致 Discover 无法按时间筛选。
  • 时间窗口/时区:Discover 右上角的时间范围默认可能是最近 15 分钟,且时区可能影响显示。建议先把范围扩大到最近 24 小时再验证。
  • 数据解析失败:若日志是非结构化文本,仍可入库但字段不可用;生产环境建议输出 JSON 并在采集端解析。

5. 验证日志是否写入 Elasticsearch:生产排错必备

当你在 Kibana 看不到日志时,建议先跳过 UI,从存储端直接验证“日志是否入库”。

  1. 查看索引是否创建:

    curl -s http://localhost:9200/_cat/indices?v
    

    如果 Fluentd 使用了 logstash_format true 且 logstash_prefix docker,通常会看到形如 docker-YYYY.MM.DD 的索引。

  2. 查看最近一段时间的日志文档:

    curl -s -H 'Content-Type: application/json' \
      http://localhost:9200/docker-*/_search \
      -d '{"size":1,"sort":[{"@timestamp":"desc"}]}'
    

如果 Elasticsearch 中已经有文档,但 Kibana 仍然为空,常见原因是:

  • Index Pattern 没匹配到索引(例如写成了 docker-* 但实际索引前缀不同)。
  • 时间字段没选对或时区不一致,导致 Discover 时间窗口内看不到数据。

19.2.3 总结

通过 Docker 的日志驱动机制,结合 ELK/EFK 强大的收集和分析能力,我们可以轻松构建一个能够处理海量日志的监控平台,这对于排查生产问题至关重要。

19.2.4 生产要点

在生产环境中,日志系统往往比监控系统更容易因为“容量与写入压力”出问题,建议特别关注:

  • 容量规划:日志增长速度与磁盘占用直接相关。建议设置日志保留周期与索引生命周期策略 (ILM),避免 Elasticsearch 因磁盘水位触发只读或不可用。
  • 资源配置:Elasticsearch 对 JVM Heap 较敏感。除示例中的 ES_JAVA_OPTS 外,生产环境需要结合节点内存、分片规模、查询压力做评估。
  • 链路可靠性:采集端到存储端要考虑网络抖动、背压与重试策略;当 Elasticsearch 写入变慢时,采集端的缓冲与落盘策略决定了是否会丢日志。
  • 日志格式:推荐应用输出结构化日志 (JSON) 并包含关键字段(如 trace_id、request_id、service、env),以便快速过滤与关联分析。

索引与保留策略的落地建议

无论是 EFK 还是 ELK,生产上都需要回答两个问题:

  • 日志保留多久?
  • 保留期内的日志如何保证可查询、不过度占用存储?

建议按环境与业务重要性对日志分层,并制定不同的保留周期,例如:

  • 生产环境:7~30 天
  • 测试环境:1~7 天

实现方式通常有两类:

  • 按天滚动索引:如 docker-YYYY.MM.DD,再定期删除过期索引。
  • 使用 ILM:定义 Hot/Warm/Cold/删除阶段,按时间与容量自动滚动与回收。

对于中小规模集群,先把“按天滚动 + 过期删除”做扎实,往往就能解决 80% 的容量问题;当日志量上来、查询压力变大后,再逐步引入 ILM、分层存储与更精细的分片规划。

最小可用的“过期索引清理”示例

如果你采用按天滚动索引(例如 docker-YYYY.MM.DD),可以通过 Elasticsearch API 定期清理过期索引。

下面示例仅用于演示思路:获取所有 docker- 前缀索引并删除指定索引。生产环境建议基于日期计算、灰度验证与权限控制后再执行自动化清理。

  1. 列出索引:

    curl -s http://localhost:9200/_cat/indices/docker-*?v
    
  2. 删除某个过期索引(示例):

    curl -X DELETE http://localhost:9200/docker-2026.02.01
    

如果你希望更自动化的治理能力,可以进一步使用 ILM 为索引配置滚动与删除策略。