12. Docker 日志管理与监控:ELK 日志收集 + Prometheus 性能监控

12. Docker 日志管理与监控:ELK 日志收集 + Prometheus 性能监控

容器跑着跑着突然挂了,你慌忙打开终端------日志在哪看?10 个容器同时出问题,你要一个一个 docker logs 去翻?服务器 CPU 飙到 90%,到底是哪个容器在作妖?搞容器,不看日志和监控,就等于闭着眼睛开车。 本文手把手带你搭建两套"生产级"方案:ELK 集中收集日志 + Prometheus/Grafana 实时监控容器性能,看完你就是团队里的"容器运维担当"。

▲ 不看日志和监控,等于闭着眼睛开车;这套组合拳让你对集群里每个容器的状况一目了然。


一、Docker 日志基础:你至少得会这几招

1.1 docker logs 命令速查

这是最基础、用得最多的命令,先把常用参数记牢:

复制代码
# 查看容器全部日志
docker logs my-container
​
# 实时跟踪日志输出(类似 tail -f)
docker logs -f my-container
​
# 只看最后 100 行
docker logs --tail 100 my-container
​
# 显示时间戳
docker logs -t my-container
​
# 查看某个时间点之后的日志
docker logs --since "2025-01-01T00:00:00" my-container
​
# 组合使用:实时跟踪 + 只看最后 50 行 + 带时间戳
docker logs -f --tail 50 -t my-container

小技巧 :排查问题时,先用 --tail 看最近的日志,别一上来就全量输出------容器跑了几天的话,日志量可能有好几个 G。

1.2 日志驱动:Docker 的日志往哪存?

Docker 支持多种日志驱动(Logging Driver),决定了容器日志的"归宿":

日志驱动 存储位置 适用场景 优缺点
json-file(默认) 容器宿主机本地 JSON 文件 单机开发/测试 ✅ 简单直接 ❌ 不支持集中收集,日志文件会越来越大
syslog 系统 syslog 服务 已有 syslog 基础设施的环境 ✅ 复用现有系统 ❌ 配置略复杂
journald systemd journal CentOS/RHEL 等 systemd 系统 ✅ 与系统日志统一管理 ❌ 仅 Linux
gelf Graylog / Logstash 等 需要集中收集日志 ✅ 原生支持远程发送 ❌ 需要额外部署接收端
fluentd Fluentd 聚合器 大规模日志收集 ✅ 功能强大、插件丰富 ❌ 部署复杂
none 不记录任何日志 安全敏感或性能极致场景 ✅ 零开销 ❌ 出问题了完全没线索

查看当前容器的日志驱动

复制代码
docker inspect my-container --format='{{.HostConfig.LogConfig.Type}}'
# 输出:json-file

1.3 日志轮转:别让磁盘被日志撑爆

默认的 json-file 驱动会把日志一直往文件里追加,不做任何轮转。跑上几个月,一个容器的日志文件轻松突破几个 G,最终把磁盘吃满,整个服务器宕机------这是生产环境最常见的"低级故障"之一。

解决方案:在 Docker 的 daemon 配置里全局设置日志轮转:

编辑 /etc/docker/daemon.json(没有就创建):

复制代码
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  }
}
参数 含义 推荐值
max-size 单个日志文件的最大大小 50m ~ 100m
max-file 最多保留几个日志文件 3 ~ 5

上面这个配置的意思是:单个日志文件最大 50MB,保留最近 3 份,超过后自动轮转删除旧的。最多占 50×3=150MB 磁盘空间。

配置完重启 Docker 生效:

复制代码
sudo systemctl restart docker

注意daemon.json 的全局配置只对新建容器 生效。已运行的容器需要删除重建,或者在 docker run / docker-compose.yml 里单独指定 log-opts

在 docker-compose.yml 里单独配置

复制代码
services:
  my-app:
    image: my-app:latest
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "3"

二、docker stats:一秒看清容器资源消耗

在搭建重量级监控之前,先认识一个轻量级但超实用的命令:

复制代码
# 查看所有运行中容器的资源使用情况
docker stats
​
# 只看指定容器
docker stats nginx mysql redis
​
# 非持续模式,采样一次就退出(适合脚本调用)
docker stats --no-stream

输出示例:

复制代码
CONTAINER ID   NAME     CPU %   MEM USAGE / LIMIT     MEM %   NET I/O          BLOCK I/O        PIDS
a1b2c3d4e5f6   nginx    0.05%   12.5MiB / 7.78GiB     0.16%   1.2kB / 650B     0B / 0B          5
b2c3d4e5f6a1   mysql    1.23%   356.2MiB / 7.78GiB    4.47%   15.6MB / 8.3MB   45.1MB / 120MB   38
c3d4e5f6a1b2   redis    0.02%   8.3MiB / 7.78GiB      0.10%   520kB / 310kB    0B / 4.1kB       4
列名 含义 关注点
CPU % 容器占用的 CPU 百分比 持续超过 80% 就该警惕了
MEM USAGE / LIMIT 当前内存使用量 / 内存上限 接近 LIMIT 说明要 OOM 了
MEM % 内存使用百分比 ---
NET I/O 网络输入/输出 突然飙升可能有异常流量
BLOCK I/O 磁盘读写量 持续高 I/O 说明在做大量磁盘操作
PIDS 容器内进程数 异常增多可能有进程泄漏

实战建议 :日常巡检时 docker stats --no-stream 跑一次就够了,把结果存进日志文件,方便事后对比。


三、实战一:ELK Stack 集中收集 Docker 日志

3.1 为什么需要 ELK?

单机时代 docker logs 够用。但当你的服务拆成 10 个、20 个微服务,分布在 3 台服务器上时,你不可能 SSH 到每台机器上一个个翻日志

ELK Stack 就是来解决这个问题的:

复制代码
容器A日志 ──┐
容器B日志 ──┼──▶ Logstash(收集+过滤)──▶ Elasticsearch(存储+索引)──▶ Kibana(可视化查询)
容器C日志 ──┘

▲ 从"到处翻日志"变成"一个页面搜全部"------这就是 ELK 的意义。

组件 角色 通俗解释
Elasticsearch 搜索引擎 + 存储 日志的"大仓库",支持全文检索
Logstash 日志收集 + 过滤 + 转发 日志的"快递员",从各容器收件、整理、送进仓库
Kibana 可视化仪表盘 日志的"浏览器",在网页上搜索、过滤、画图

3.2 docker-compose.yml 一键部署 ELK

创建目录 elk-stack/,写入以下文件:

docker-compose.yml

复制代码
version: '3.8'
​
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.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:
      - elk
​
  logstash:
    image: docker.elastic.co/logstash/logstash:8.12.0
    container_name: logstash
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - "5044:5044"
      - "5000:5000/tcp"
      - "5000:5000/udp"
    depends_on:
      - elasticsearch
    networks:
      - elk
​
  kibana:
    image: docker.elastic.co/kibana/kibana:8.12.0
    container_name: kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - elk
​
volumes:
  es_data:
​
networks:
  elk:
    driver: bridge

logstash.conf(Logstash 管道配置,放在同级目录):

复制代码
input {
  # 监听 TCP 5000 端口,接收容器发来的日志
  tcp {
    port => 5000
    codec => json
  }
​
  # 也可以直接读取 Docker 的 JSON 日志文件
  file {
    path => "/var/lib/docker/containers/*/*.log"
    start_position => "beginning"
    codec => json
  }
}
​
filter {
  # 如果是 Docker JSON 日志格式,解析字段
  if [log] {
    json {
      source => "log"
    }
  }
​
  # 添加时间戳
  date {
    match => ["time", "ISO8601"]
    target => "@timestamp"
  }
​
  # 删除不需要的字段,减少存储
  mutate {
    remove_field => ["host", "agent", "ecs", "input", "@version"]
  }
}
​
output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "docker-logs-%{+YYYY.MM.dd}"
  }
​
  # 调试用:同时在控制台输出
  stdout {
    codec => rubydebug
  }
}

启动

复制代码
cd elk-stack
docker compose up -d
​
# 等待 30 秒左右让 Elasticsearch 初始化完成
# 查看状态
docker compose ps

3.3 在 Kibana 里查看日志

  1. 打开浏览器访问 http://你的服务器IP:5601

  2. 左侧菜单 → Stack ManagementIndex PatternsCreate index pattern

  3. 输入 docker-logs-*,时间字段选 @timestamp

  4. 创建完成后,左侧菜单 → Discover,就能看到所有容器的日志了

Kibana 的查询语法非常强大,几个常用的:

复制代码
# 搜索包含 "error" 的日志
log: "error"
​
# 搜索指定容器的日志
container_name: "my-app"
​
# 搜索最近 5 分钟内的 ERROR 级别日志
level: "ERROR" AND @timestamp:[now-5m TO now]
​
# 排除健康检查日志
NOT log: "healthcheck"

生产建议 :Elasticsearch 至少分配 2GB 堆内存(ES_JAVA_OPTS=-Xms2g -Xmx2g),并配置 ILM(Index Lifecycle Management)策略自动清理 30 天前的旧索引,否则磁盘会持续增长。


四、实战二:Prometheus + Grafana + cAdvisor 容器监控

4.1 三件套各自干什么?

复制代码
cAdvisor(采集容器指标)──▶ Prometheus(存储时序数据)──▶ Grafana(可视化仪表盘)
组件 角色 通俗解释
cAdvisor Google 开源的容器监控代理 跑在每台宿主机上,自动采集所有容器的 CPU、内存、网络、磁盘指标
Prometheus 时序数据库 + 监控告警 定时"拉取"cAdvisor 暴露的指标,存成时间序列,支持 PromQL 查询和告警规则
Grafana 可视化仪表盘 把 Prometheus 里的数据画成漂亮的图表,一眼看清趋势

4.2 docker-compose.yml 一键部署监控三件套

创建目录 monitoring/,写入:

docker-compose.yml

复制代码
version: '3.8'
​
services:
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:v0.49.1
    container_name: cadvisor
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
      - /dev/disk/:/dev/disk:ro
    privileged: true
    devices:
      - /dev/kmsg:/dev/kmsg
    networks:
      - monitoring
​
  prometheus:
    image: prom/prometheus:v2.51.0
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=15d'
    depends_on:
      - cadvisor
    networks:
      - monitoring
​
  grafana:
    image: grafana/grafana:10.4.0
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin123
    volumes:
      - grafana_data:/var/lib/grafana
    depends_on:
      - prometheus
    networks:
      - monitoring
​
volumes:
  prometheus_data:
  grafana_data:
​
networks:
  monitoring:
    driver: bridge

prometheus.yml(Prometheus 配置,放在同级目录):

复制代码
global:
  scrape_interval: 15s        # 每 15 秒拉取一次指标
  evaluation_interval: 15s    # 每 15 秒评估一次告警规则
​
scrape_configs:
  # 采集 cAdvisor 暴露的容器指标
  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']
    metrics_path: '/metrics'
​
  # 采集 Prometheus 自身的指标(可选)
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

启动

复制代码
cd monitoring
docker compose up -d

4.3 验证各组件

复制代码
# 检查 cAdvisor 是否正常(浏览器也可以访问)
curl -s http://localhost:8080/containers/ | head -5

# 检查 Prometheus 是否采集到 cAdvisor 的指标
curl -s http://localhost:9090/api/v1/targets | python -m json.tool | grep cadvisor

# 检查 Grafana 是否启动
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000
# 输出 200 说明正常

4.4 在 Grafana 里看监控图表

  1. 打开 http://你的服务器IP:3000

  2. admin / admin123 登录(在 docker-compose.yml 里配置的)

  3. 添加数据源 :左侧菜单 → ConnectionsAdd new connection → 选 Prometheus → URL 填 http://prometheus:9090Save & Test

  4. 导入现成的 Docker 监控仪表盘(这才是重点!):

    • 左侧菜单 → DashboardsImport

    • 输入 Dashboard ID:193(这是社区最经典的 Docker 监控模板)

    • 选择刚才创建的 Prometheus 数据源

    • 点击 Import

导入后你就能看到:

  • 所有容器的 CPU 使用率折线图

  • 每个容器的内存占用柱状图

  • 网络收发流量的实时曲线

  • 磁盘 I/O 读写速率

  • 容器数量总览

其他推荐仪表盘 ID893(Docker 容器详细视图)、11600(Node Exporter + cAdvisor 综合面板)。在 Grafana 官网 grafana.com/grafana/dashboards 可以按关键词搜索更多。

4.5 配置告警规则(进阶)

prometheus.yml 同级创建 alert_rules.yml

复制代码
groups:
  - name: docker_alerts
    rules:
      # 容器 CPU 使用率超过 80%,持续 5 分钟
      - alert: HighCPUUsage
        expr: rate(container_cpu_usage_seconds_total{name!=""}[5m]) * 100 > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "容器 {{ $labels.name }} CPU 使用率过高"
          description: "{{ $labels.name }} 的 CPU 使用率在过去 5 分钟内超过 80%,当前值:{{ $value }}%"

      # 容器内存使用率超过 90%
      - alert: HighMemoryUsage
        expr: (container_memory_usage_bytes{name!=""} / container_spec_memory_limit_bytes{name!=""} * 100) > 90
        for: 3m
        labels:
          severity: critical
        annotations:
          summary: "容器 {{ $labels.name }} 内存即将耗尽"
          description: "{{ $labels.name }} 内存使用率超过 90%,当前值:{{ $value }}%"

      # 容器挂了
      - alert: ContainerDown
        expr: time() - container_last_seen{name!=""} > 60
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "容器 {{ $labels.name }} 已停止"

prometheus.yml 里加载告警规则:

复制代码
rule_files:
  - 'alert_rules.yml'

再在 docker-compose.yml 的 prometheus 服务里加一个 volumes 映射:

复制代码
    volumes:
      - ./alert_rules.yml:/etc/prometheus/alert_rules.yml:ro

重启后 Prometheus 就会按规则自动评估,触发告警时可以在 Grafana 的 Alerting 面板看到,也可以对接钉钉、企业微信、邮件等通知渠道。


五、日志最佳实践:五条铁律

5.1 应用日志必须输出到 stdout / stderr

这是 Docker 的"第一原则"。不要把日志写到容器内的文件里!

复制代码
# ❌ 错误示范:日志写到容器内文件
import logging
logging.basicConfig(filename='/app/logs/app.log')

# ✅ 正确示范:日志输出到 stdout
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO)

原因很简单:Docker 的日志驱动只能收集 stdout/stderr 的输出。如果你写到文件里,docker logs 什么都看不到,ELK 也收不到。

5.2 日志格式统一用 JSON

复制代码
# 用 structlog 或 python-json-logger 输出结构化 JSON 日志
import structlog
logger = structlog.get_logger()

logger.info("user_login", user_id=12345, ip="192.168.1.100", status="success")
# 输出:{"event": "user_login", "user_id": 12345, "ip": "192.168.1.100", "status": "success", "timestamp": "2025-06-15T10:30:00Z"}

JSON 格式的好处:ELK 能自动解析每个字段,你可以按 user_idipstatus 做精确过滤和聚合统计,比纯文本搜索效率高几个数量级。

5.3 五条铁律速查表

序号 铁律 原因
1 日志输出到 stdout/stderr Docker 日志驱动只收集标准输出
2 用 JSON 格式 方便 ELK 解析和结构化查询
3 配置日志轮转 防止磁盘被日志撑爆
4 不要在日志里打印敏感信息 密码、Token、身份证号等绝对不能出现在日志里
5 区分日志级别 DEBUG/INFO/WARN/ERROR 分级,生产环境只开 INFO 以上

六、总结:两套方案怎么选?

需求 推荐方案 资源消耗
单机开发调试 docker logs + docker stats 零开销
多台服务器日志集中查询 ELK Stack Elasticsearch 至少 2GB 内存
容器性能实时监控 + 告警 Prometheus + Grafana + cAdvisor Prometheus 按数据量,一般 512MB 起步
生产环境完整方案 ELK + Prometheus/Grafana 都上 建议独立监控服务器

本文要点回顾

  1. docker logs 是最基础的日志查看工具,配合 --tail-f--since 高效排查问题

  2. 日志轮转必须配置 ,否则磁盘迟早被撑爆,max-size + max-file 两条搞定

  3. ELK Stack 实现日志集中收集,告别 SSH 到每台机器翻日志的日子

  4. Prometheus + Grafana + cAdvisor 实现容器性能实时监控,配上告警规则,出问题第一时间通知

  5. 日志输出到 stdout/stderr + JSON 格式,这两条是 Docker 日志的铁律

下集预告 :容器跑起来了,日志监控也上了,但如果有人通过容器漏洞攻进你的服务器呢?下一篇我们聊聊 Docker 安全最佳实践------镜像扫描、最小权限、网络隔离、seccomp 配置,给你的容器穿上"防弹衣"。


参考资料

相关推荐
BullSmall10 小时前
第三方软件安全-Dependency‑Track Docker 部署
安全·docker·容器
harmony&11 小时前
Docker 容器技术从入门到实战:容器、网络、存储与监控全解析
docker·云原生
DevOps老兵11 小时前
AI Infra实战02:GPU监控实战,用DCGM+Prometheus+Grafana看清每一张卡
人工智能·grafana·prometheus·ai infra·gpu监控·dcgm
heimeiyingwang12 小时前
【Prometheus·入门篇】数据模型:Metric 类型、标签与时间序列
prometheus
IT大白鼠13 小时前
Docker 私有仓库管理:Harbor 企业级仓库搭建与镜像全生命周期管理
运维·docker·容器
bgy666616 小时前
从零上手 Docker,容器技术完整入门指南
运维·docker·容器
pride.li21 小时前
Docker教程-Docker安装与镜像配置
运维·docker·容器
bgy666621 小时前
Docker Swarm 容器编排实战指南
运维·docker·容器
heimeiyingwang21 小时前
【Prometheus·部署篇】配置详解:scrape_config、relabeling 与服务发现
prometheus