一、Docker 日志驱动:选对工具事半功倍

容器日志就像快递单号,没选对记录方式,查问题时就可能抓瞎。Docker 默认的 json-file 驱动把日志存在本地 JSON 文件里,适合开发调试,但生产环境会遇到磁盘爆炸的风险。比如一个高频服务跑一天可能产生 10GB 日志,用默认配置的容器分分钟能把硬盘写满。

这时候就该看看其他日志驱动了。syslog 驱动直接把日志扔给系统日志服务,适合传统运维体系;journald 则是 Systemd 生态的专属方案。如果是云原生环境,awslogsgcplogs 能无缝对接云服务。最灵活的是 fluentd,它能像乐高积木一样对接各种存储。

举个实际配置例子(技术栈:Docker + Fluentd):

# 启动容器时指定 fluentd 驱动
docker run --log-driver=fluentd \
           --log-opt fluentd-address=192.168.1.100:24224 \
           --log-opt tag="app.{{.Name}}" \
           nginx:alpine

# 对应 fluentd 配置(/etc/fluent/fluent.conf)
<source>
  @type forward  # 接收 Docker 日志
  port 24224
</source>

<match app.nginx*>  # 按容器名路由日志
  @type elasticsearch  # 输出到 ES
  host 192.168.1.101
  port 9200
  logstash_format true
</match>

:这里用 tag 参数实现日志分类,{{.Name}} 会自动替换为容器名,就像给快递贴分类标签。

二、日志轮转:给日志装上自动删除按钮

不控制日志体积的运维就像不关水龙头接水,迟早要淹了机房。Docker 的 json-file 驱动支持本地日志轮转,关键配置看这两个参数:

  • max-size:单个日志文件最大尺寸(如 10m)
  • max-file:保留的旧日志文件数量

实战配置示例:

# 限制每个日志文件 10MB,最多保留 3 个
docker run --log-driver=json-file \
           --log-opt max-size=10m \
           --log-opt max-file=3 \
           redis:6

:这个配置下,当 redis-json.log 超过 10MB 时会自动创建 redis-json.log.1,类似 Linux 的 logrotate 机制。

更复杂的场景可以用 logrotate 工具直接管理宿主机上的日志文件,比如每天切割并压缩旧日志:

# /etc/logrotate.d/docker 配置示例
/var/lib/docker/containers/*/*.log {
  daily        # 每天轮转
  rotate 7     # 保留7天
  compress     # 启用压缩
  delaycompress # 延迟压缩前一个文件
  missingok    # 文件不存在也不报错
  size 100M    # 超过100MB立即触发
}

三、集中式收集:让日志坐上高铁

当你有 20 台 Docker 主机时,登录每台机器查日志就像跑遍全市邮局找快递。这时候需要 ELK(Elasticsearch+Logstash+Kibana)或 EFK(Elasticsearch+Fluentd+Kibana)这样的集装车运输日志。

以 Fluentd 为例的完整管道配置(技术栈:Docker+Fluentd+ES):

# Step1: 启动 Fluentd 收集器(带 Elasticsearch 插件)
docker run -d -p 24224:24224 \
           -v /path/to/fluent.conf:/fluentd/etc/fluent.conf \
           fluent/fluentd:v1.14-1

# Step2: 业务容器日志定向到 Fluentd
docker run -d --log-driver=fluentd \
           --log-opt fluentd-address=fluentd-host:24224 \
           --log-opt tag="microservice.payment" \
           your-payment-service:1.0

# 对应的 Fluentd 配置片段
<filter microservice.**>  # 过滤支付服务日志
  @type parser            # 解析原始日志
  key_name log            # 解析的字段名
  <parse>
    @type json            # 按JSON格式解析
  </parse>
</filter>

<match **>               # 所有日志最终去向
  @type elasticsearch
  hosts es01:9200,es02:9200  # ES集群地址
  logstash_prefix docker-${tag_parts[0]} # 按服务名建索引
</match>

${tag_parts[0]} 会提取 tag 的第一段(如 microservice),实现按业务分类存储。

四、避坑指南与高阶玩法

  1. 时区问题:容器内默认 UTC 时间,可以在 Fluentd 里用 time_keytime_format 转换:

    <filter>
      @type record_transformer
      enable_ruby true
      <record>
        local_time "${Time.now.localtime}"
      </record>
    </filter>
    
  2. 敏感信息过滤:用 grep 插件屏蔽密码等数据:

    <filter **>
      @type grep
      exclude password .*[pP]assw(or)?d=.*
    </filter>
    
  3. 性能调优:高并发场景建议启用 Fluentd 的异步缓冲:

    <match **>
      @type elasticsearch
      # ...其他配置...
      <buffer>  # 缓冲设置
        @type file
        path /var/log/fluentd/buffer
        flush_interval 5s  # 5秒刷一次磁盘
        chunk_limit_size 8MB # 每个块最大8MB
      </buffer>
    </match>
    

对于需要实时报警的场景,可以结合 Grafana 的 AlertManager 设置规则,比如当 5 分钟内出现 10 次 "OutOfMemoryError" 就触发企业微信通知。

五、技术选型风向标

  • 中小团队:直接使用 Docker 内置的 local 日志驱动 + logrotate,成本最低
  • 混合云环境fluentd + Elasticsearch 组合最灵活,适配各种存储后端
  • K8s 生态:考虑 Loki,它的索引体积比 ES 小 10 倍,查询语法类似 PromQL

日志管理就像城市垃圾分类,初期觉得麻烦,但系统搭建好后,排障效率能提升 80%。曾经有个生产环境 CPU 飙高的问题,通过日志系统的关键字聚合,5 分钟就定位到是某个循环里的正则表达式失控,而传统逐台排查的方式可能需要两小时。