Skip to content

日志管理

默认日志行为

Docker 容器的标准输出(stdout)和标准错误(stderr)默认会被捕获并存储。

bash
# 查看容器日志
docker logs mycontainer

# 实时跟踪(类似 tail -f)
docker logs -f mycontainer

# 最后 100 行
docker logs --tail 100 mycontainer

# 带时间戳
docker logs -t mycontainer

# 查看 1 小时内的日志
docker logs --since 1h mycontainer

应用日志最佳实践

容器内的应用应该将日志输出到 stdout/stderr,而不是写入文件:

javascript
// Node.js 示例
console.log('Info message');   // → stdout
console.error('Error message'); // → stderr
python
# Python 示例
import sys
print('Info message')            # → stdout
print('Error message', file=sys.stderr)  # → stderr

如果应用只支持文件日志,可以将日志文件链接到 stdout:

dockerfile
# Nginx 官方镜像的做法
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

日志驱动

Docker 支持多种日志驱动,在 /etc/docker/daemon.json 中全局配置,或每个容器单独配置。

常用日志驱动

驱动说明
json-file默认,将日志存储为 JSON 文件
local类似 json-file,但压缩存储,占用空间更小
syslog发送到 syslog 守护进程
journald发送到 systemd journal
fluentd发送到 Fluentd
gelf发送到 Graylog(GELF 格式)
awslogs发送到 AWS CloudWatch
none禁用日志

配置 json-file 日志(防止磁盘耗尽)

json
// /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3",
    "compress": "true"
  }
}
bash
# 单个容器配置
docker run -d \
  --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  nginx

日志存储位置

bash
# 查看容器的日志文件路径
docker inspect mycontainer --format '{{.LogPath}}'
# /var/lib/docker/containers/<id>/<id>-json.log

# 直接读取日志文件
sudo cat /var/lib/docker/containers/<container-id>/<container-id>-json.log

集中化日志收集

生产环境通常需要将多容器日志集中收集,推荐 EFK 或 Loki 方案。

方案一:EFK(Elasticsearch + Fluentd + Kibana)

yaml
# docker-compose.yml
services:
  elasticsearch:
    image: elasticsearch:8.12.0
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
    volumes:
      - es-data:/usr/share/elasticsearch/data

  fluentd:
    build: ./fluentd
    volumes:
      - /var/lib/docker/containers:/fluentd/log/containers:ro
    depends_on:
      - elasticsearch

  kibana:
    image: kibana:8.12.0
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

volumes:
  es-data:

将 Docker 日志驱动改为 fluentd:

json
{
  "log-driver": "fluentd",
  "log-opts": {
    "fluentd-address": "localhost:24224",
    "tag": "docker.{{.Name}}"
  }
}

方案二:Loki + Grafana(更轻量,推荐)

yaml
services:
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
    volumes:
      - loki-data:/loki

  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/log:/var/log:ro
      - ./promtail-config.yml:/etc/promtail/config.yml:ro

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana

volumes:
  loki-data:
  grafana-data:

Docker Compose 日志配置

yaml
services:
  api:
    image: myapi
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"
        labels: "service_name"
    labels:
      service_name: api

日志查看技巧

bash
# 搜索包含关键词的日志
docker logs mycontainer 2>&1 | grep "ERROR"

# 查看最近 5 分钟的日志
docker logs --since 5m mycontainer

# 查看指定时间段的日志
docker logs --since "2024-01-01T10:00:00" --until "2024-01-01T11:00:00" mycontainer

# 多服务日志对比(Compose)
docker compose logs -f api nginx

# 带颜色区分
docker compose logs --no-color api | grep ERROR

总结

日志管理要点:

  1. 应用输出到 stdout/stderr,让 Docker 统一管理
  2. 配置日志轮转max-size + max-file),防止磁盘耗尽
  3. 生产环境集中收集:Loki/EFK 等方案
  4. 添加结构化日志:便于检索和分析
  5. 不在容器内写日志文件:除非挂载到卷