容器日志文件持续膨胀,是容器化部署中最容易被忽视却危害极大的运维隐患之一。当多个服务并行运行时,日志文件会以惊人的速度增长,几小时内就可能吃掉数GB磁盘空间。更糟糕的是,很多人只有在服务突然崩溃、排查半天之后才发现根本原因是磁盘被日志文件塞满了。

而在Docker Compose这种典型的编排方式下,日志策略往往是"想不起来配"或者"配了但配错了"的状态。很多开发者写docker-compose.yml的时候,把精力全放在了端口映射、环境变量、卷挂载这些配置上,对logging这块要么留空、要么抄一段不知道哪来的配置片段,从来没真正验证过日志轮转是否生效。结果就是:开发环境一切正常,上了生产就翻车。

这篇内容会从日志膨胀的根本原因讲起,逐步深入到Docker原生日志驱动的机制、配置方法的坑、以及针对不同场景的最佳实践方案,并给出可以直接拿来用的配置模板。不管你是刚接触Docker的新人,还是有几年经验的开发者,相信读完之后,你至少不会再遇到"日志把磁盘撑爆"这类低级但致命的事故。

一、问题根源:日志文件是怎么失控的

1.1 默认日志驱动的隐患

Docker默认使用的日志驱动是json-file,它把所有容器的标准输出和标准错误都写到一个JSON Lines格式的日志文件里。这个驱动在默认配置下没有任何大小限制,日志文件会一直增长,直到把磁盘空间吃光。

来看一个典型的场景:一个普通的Web服务,每秒产生约50条日志记录,每条大约200字节,那么一天就能产生大约4.3GB的日志文件。如果是高并发的服务,日志量轻松翻几倍。

# 查看某个容器的日志文件大小
ls -lh /var/lib/docker/containers/<container-id>/<container-id>-json.log

1.2 为什么开发者常常忽略这件事

有几个常见的原因让开发者忽略了日志膨胀问题:

开发环境磁盘通常够用。 开发机器一般有几百GB到几TB的存储空间,几十GB的日志增长根本不会引起注意。

测试环境跑的时间短。 测试环境通常跑几天就重新部署,日志还没来得及膨胀到危险程度。

不知道日志存储在哪里。 很多开发者根本不知道Docker的日志文件存储在/var/lib/docker/containers/目录下,自然也就不会定期检查。

1.3 一个简单的检测命令

如果你现在就想检查一下自己服务器的日志磁盘占用情况,可以运行这个命令:

# 查看Docker数据目录下的所有日志文件大小,按大小排序
du -sh /var/lib/docker/containers/*/*-json.log 2>/dev/null | sort -rh | head -20

运行之后你会看到一个排序好的列表,看看最大的那几个日志文件有多大。如果有任何一个超过100MB,那就说明需要尽快配置日志轮转了。

二、JSON File 日志驱动深度解析

2.1 技术栈说明

本节及后续所有内容统一使用以下技术栈:

技术栈:Docker Compose v3 + Docker Engine + json-file日志驱动

2.2 JSON File 驱动的工作机制

json-file驱动采用追加写入模式,每行日志是一个独立的JSON对象。它的工作流程非常简单:

  1. 容器启动时,Docker在/var/lib/docker/containers//目录下创建日志文件
  2. 容器内的进程往stdout/stderr输出内容时,Docker守护进程捕获这些输出
  3. 每一行输出被包装成JSON格式追加写入日志文件
  4. 达到轮转阈值时(如果配置了的话),创建新文件,旧文件被重命名
# 查看某个容器的日志内容(原始JSON格式)
cat /var/lib/docker/containers/$(docker inspect -f '{{.Id}}' myapp)/*-json.log | head -5

输出类似这样:

{"log":"2024-01-15 10:23:45.123 INFO  Application started\n","stream":"stdout","time":"2024-01-15T10:23:45.123456789Z"}
{"log":"2024-01-15 10:23:46.456 INFO  Health check passed\n","stream":"stdout","time":"2024-01-15T10:23:46.456789012Z"}
{"log":"2024-01-15 10:24:01.789 ERROR  Database connection failed\n","stream":"stderr","time":"2024-01-15T10:24:01.789012345Z"}

2.3 轮转机制触发条件

json-file驱动的轮转基于文件大小的阈值触发。当当前日志文件的大小达到配置的上限时,Docker会:

  1. 将当前日志文件重命名(添加时间戳后缀)
  2. 创建一个新的空日志文件
  3. 如果历史日志文件数量超过配置的最大值,删除最旧的日志文件

这个轮转过程对用户是透明的,docker logs命令会自动读取当前活跃文件和历史文件。

三、Docker Compose 日志配置实战

3.1 基础配置模板

以下是一个完整的docker-compose.yml配置示例,展示了如何为不同服务设置合理的日志轮转策略:

# 技术栈:Docker Compose v3
version: '3.8'

services:
  # Web应用服务 - 日志量中等
  web:
    image: myapp:latest
    restart: always
    ports:
      - "8080:8080"
    environment:
      - NODE_ENV=production
    # 日志轮转配置:单文件最大50MB,最多保留3个文件
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "3"

  # 反向代理服务 - 日志量大,需要更大的轮转空间
  nginx:
    image: nginx:latest
    restart: always
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "5"

  # 数据库服务 - 日志量小,可以设置保守的限制
  database:
    image: postgres:15
    restart: always
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    logging:
      driver: "json-file"
      options:
        max-size: "20m"
        max-file: "2"

  # 后台任务服务 - 日志量小但需要保留历史用于排查问题
  worker:
    image: myworker:latest
    restart: always
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "10"

volumes:
  pgdata:

3.2 配置参数详解

上面的配置中涉及了几个关键参数,下面逐一解释:

driver: 指定日志驱动类型,这里统一使用json-file。

max-size: 单个日志文件的最大大小。支持的单位有b(字节)、k(KB)、m(MB)、g(GB)。当日志文件达到这个大小时触发轮转。

max-file: 保留的日志文件最大数量。包括当前活跃文件和历史文件。比如设置为3,意味着最多保留3个文件,当创建第4个文件时会删除最旧的那个。

磁盘占用计算公式:单服务最大日志占用 = max-size × max-file

以上面的配置为例:

  • web服务:50MB × 3 = 150MB
  • nginx服务:100MB × 5 = 500MB
  • database服务:20MB × 2 = 40MB
  • worker服务:50MB × 10 = 500MB
  • 总计:约1.19GB

3.3 配置生效验证

配置好之后,验证配置是否真的生效很重要。很多人配置了轮转参数,但实际上因为容器没有重建而配置根本没有加载。

# 步骤1:强制重建所有容器以应用新配置
docker-compose down
docker-compose up -d

# 步骤2:给web服务发送一些请求以产生日志
curl http://localhost:8080/
curl http://localhost:8080/api/test

# 步骤3:检查容器实际使用的日志配置
docker inspect web --format '{{json .HostConfig.LogConfig}}' | jq .

预期的输出应该类似:

{
  "Type": "json-file",
  "Config": {
    "max-size": "50m",
    "max-file": "3"
  }
}

如果输出中Config字段是空的或者没有max-size和max-file,那说明配置没有生效。

3.4 测试轮转效果

为了验证轮转确实在工作,我们可以做一个简单的压力测试:

# 创建一个测试容器,以json-file驱动启动,并设置较小的轮转参数
docker run --name log-test \
  --log-driver json-file \
  --log-opt max-size=1m \
  --log-opt max-file=2 \
  -d alpine sh -c "
    # 持续输出日志,每100毫秒一条
    while true; do
      echo 'This is a test log line to fill up the file quickly with sufficient text content'
      sleep 0.1
    done
  "

# 等待30秒让日志文件增长
sleep 30

# 查看该容器的日志文件大小和数量
CONTAINER_ID=$(docker inspect -f '{{.Id}}' log-test)
ls -lh /var/lib/docker/containers/$CONTAINER_ID/*-json.log*

# 清理测试容器
docker stop log-test
docker rm log-test

如果一切正常,你会看到日志文件不会超过1MB,并且最多有2个日志文件(当前+1个历史)。

四、Docker Daemon 全局配置方案

4.1 全局配置的优势

除了在每个服务级别配置日志策略,还可以在所有容器的父级——Docker Daemon——做全局配置。这样所有新建的容器都会自动遵循这个配置,不需要每个服务都重复写一遍。

编辑Docker Daemon的配置文件:

# 编辑或创建daemon.json配置文件
sudo vim /etc/docker/daemon.json

写入如下内容:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  }
}

应用配置:

# 验证配置文件JSON格式是否正确
sudo python3 -c "import json; json.load(open('/etc/docker/daemon.json'))" && echo "JSON格式正确"

# 重启Docker服务使配置生效
sudo systemctl restart docker

4.2 全局配置与Compose配置的优先级

当daemon.json和docker-compose.yml中同时配置了日志策略时,docker-compose.yml中的服务级配置会覆盖daemon.json的全局配置。这个优先级关系很重要:

# 查看某个容器实际的日志配置来源
docker inspect my-container --format '日志驱动: {{.HostConfig.LogConfig.Type}} 配置: {{json .HostConfig.LogConfig.Config}}'

最佳实践是:在daemon.json中设置一个合理的全局默认值作为安全网,然后在docker-compose.yml中针对特殊需求的服务做单独覆盖。

4.3 重要注意事项:已有容器不受影响

这里有一个非常关键的坑:修改daemon.json后重启Docker,只会影响之后新创建的容器。已经存在的容器即使重启了Docker守护进程,日志配置也不会改变。

# 确认哪些容器需要重建
# 查看容器创建时间
docker ps -a --format "table {{.Names}}\t{{.CreatedSince}}\t{{.Image}}"

# 如果需要让已有容器应用新配置,必须删除并重建
docker-compose down
docker-compose up -d

五、不同场景的配置建议

5.1 开发环境配置

开发环境的特点是:磁盘空间通常充足,服务频繁重启和重建,日志主要用于调试。

# 开发环境docker-compose.yml
version: '3.8'

services:
  app:
    image: myapp:dev
    restart: on-failure
    logging:
      driver: "json-file"
      options:
        # 开发环境可以设置较小的限制,因为频繁重建容器
        max-size: "10m"
        max-file: "1"

开发环境不需要保留太多历史日志,因为调试问题时通常直接看实时输出就够了。

5.2 测试环境配置

测试环境介于开发和生产之间,日志需要保留足够的历史用于问题复现,但也不需要太激进地保留。

# 测试环境docker-compose.yml
version: '3.8'

services:
  app:
    image: myapp:staging
    restart: always
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "5"

5.3 生产环境配置

生产环境对可靠性要求最高,日志策略需要仔细考量。建议结合多种手段:

# 生产环境docker-compose.yml - 基础服务配置
version: '3.8'

services:
  api:
    image: myapp:prod
    restart: always
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "5"
        # labels 参数可以添加自定义标签,某些日志收集工具可以利用
        labels: "app=myapp,env=production"

  gateway:
    image: nginx:1.25-alpine
    restart: always
    logging:
      driver: "json-file"
      options:
        max-size: "200m"
        max-file: "5"

# 生产环境建议配合日志收集管线使用

5.4 配合日志清理脚本

即使在docker-compose.yml中配置了轮转,也建议配合一个定时清理脚本来处理可能遗漏的边界情况:

#!/bin/bash
# /opt/scripts/clean-docker-logs.sh
# Docker日志清理脚本 - 每天执行一次

# 定义日志存储目录
DOCKER_LOG_DIR="/var/lib/docker/containers"

# 定义保留天数(超过这个天数的历史日志会被删除)
RETENTION_DAYS=7

# 输出清理开始时间
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始清理Docker日志..."

# 清理超过保留天数的历史日志文件
# 只清理带时间戳后缀的已轮转文件,不影响当前活跃的日志文件
COUNT_BEFORE=$(find "$DOCKER_LOG_DIR" -name "*-json.log.*" -type f | wc -l)
COUNT_DELETED=$(find "$DOCKER_LOG_DIR" -name "*-json.log.*" -type f -mtime +"$RETENTION_DAYS" -delete 2>/dev/null | wc -l)

# 输出清理结果
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 清理完成,共删除 $COUNT_DELETED 个过期日志文件"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 当前剩余日志文件数: $((COUNT_BEFORE - COUNT_DELETED))"
# 设置脚本执行权限
chmod +x /opt/scripts/clean-docker-logs.sh

# 添加到crontab,每天凌晨3点执行
crontab -e
# 添加以下行:
# 0 3 * * * /opt/scripts/clean-docker-logs.sh >> /var/log/docker-log-cleanup.log 2>&1

六、关联技术:Fluentd 日志驱动方案

6.1 为什么要考虑 Fluentd

当你的服务数量增多,单机日志轮转已经无法满足需求时,就需要引入集中式日志管理。Fluentd是一个开源的日志收集器,可以对接Docker的原生日志驱动,将容器日志转发到远程的日志平台。

6.2 Fluentd 驱动配置示例

# 技术栈:Docker Compose + Fluentd 日志驱动
version: '3.8'

services:
  # Fluentd日志收集服务
  fluentd:
    image: fluent/fluentd:v1.16-debian
    restart: always
    ports:
      - "24224:24224"       # 接收日志的端口
      - "24224:24224/udp"
    volumes:
      - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf
      - fluentd_data:/fluentd/data
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "3"

  # Web应用 - 使用Fluentd驱动
  web:
    image: myapp:latest
    restart: always
    depends_on:
      - fluentd
    logging:
      driver: "fluentd"
      options:
        # Fluentd服务地址
        fluentd-address: "tcp://127.0.0.1:24224"
        # 日志标签,可用于在接收端区分来源
        tag: "docker.{{.Name}}"
        # 异步发送,避免日志写入阻塞应用
        fluentd-async: "true"
        # 异步发送缓冲区大小
        fluentd-async-buffer-limit: "8MB"
        # 发送失败重试次数
        fluentd-retries: "5"
        # 工作线程数
        fluentd-worker: "2"

  # 数据库服务 - 同样使用Fluentd驱动
  database:
    image: postgres:15
    restart: always
    depends_on:
      - fluentd
    logging:
      driver: "fluentd"
      options:
        fluentd-address: "tcp://127.0.0.1:24224"
        tag: "docker.{{.Name}}"
        fluentd-async: "true"

volumes:
  fluentd_data:

6.3 Fluentd 配置文件示例

# fluentd/fluent.conf - Fluentd主配置文件
# 技术栈:Fluentd

# 源:接收Docker容器日志
<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

# 输出:写入本地文件(用于演示,生产环境建议输出到远程存储)
<match docker.**>
  @type file
  path /fluentd/data/docker_logs
  # 按天切割文件
  buffer_chunk_keys time
  <buffer tag>
    @type memory
    chunk_keys time
    flush_interval 10s
    flush_thread_count 2
  </buffer>
  # 文件名格式
  <format>
    @type json_lines
  </format>
</match>

七、技术优缺点对比分析

7.1 json-file 驱动(带轮转)

优点:

第一,简单可靠。json-file是Docker的原生驱动,不需要安装任何额外组件,兼容性最好。配置就两行参数,几乎不存在配错的可能。

第二,零依赖。不需要运行额外的日志收集服务,不会因为日志收集器挂了而导致应用受影响。

第三,性能影响最小。日志直接写入本地磁盘,不涉及网络传输,延迟极低。

第四,方便本地调试。docker logs命令直接读取这些文件,排查问题时非常直观。

缺点:

第一,没有跨节点的日志聚合能力。每个容器只能看到自己的日志,无法在一个地方看到所有服务的日志。

第二,轮转是纯文件切割,没有压缩。轮转后的历史文件仍然占用完整的磁盘空间,如果日志量很大,轮转并不能从根本上解决空间问题。

第三,没有内置的日志级别过滤。所有级别的日志都会被记录,包括DEBUG和INFO这类在生产环境中价值较低但占用空间很大的日志。

第四,没有内置的日志归档和清理机制。轮转只是切割文件,不会自动压缩、传输或删除旧文件。

7.2 journald 驱动

优点:

第一,与系统日志统一管理。使用journalctl命令可以查看Docker容器日志和系统日志,不需要切换工具。

# 使用journald驱动后,查看某个容器的日志
sudo journalctl -u docker -g '<container-id>' --since '2024-01-15 08:00:00'

第二,自带压缩能力。systemd-journald支持使用zstd、lz4等压缩算法存储历史日志,能显著节省磁盘空间。

第三,支持丰富的查询参数。可以按时间范围、日志级别、关键字等维度精确查询。

缺点:

第一,依赖systemd。如果运行环境不是基于systemd的(比如某些精简版的Docker镜像内部),这个驱动就无法使用。

第二,跨主机查询不方便。journald是单机工具,无法在多个节点之间统一查询。

第三,配置灵活性较低。journald的保留策略由systemd-stdio.conf控制,不像docker-compose.yml那样可以按服务精细控制。

7.3 fluentd / fluent-bit 驱动

优点:

第一,支持集中式日志管理。所有服务的日志可以转发到同一个日志平台,便于统一分析和排查问题。

第二,支持日志处理管线。可以在收集过程中做过滤、转换、富化,比如给日志添加额外的元数据,或者过滤掉无用的DEBUG日志。

第三,支持多种输出目标。可以转发到Elasticsearch、S3、Kafka、HTTP端点等多种目的地。

第四,异步发送机制。fluentd驱动默认使用异步发送,不会阻塞应用的日志写入操作。

缺点:

第一,增加了系统复杂度。需要额外部署和维护Fluentd/Fluent Bit服务,如果这个服务挂了,日志就会丢失。

第二,配置相对复杂。需要理解Fluentd的配置文件语法,不同版本之间配置格式也有差异。

第三,网络传输增加延迟。虽然支持异步发送,但在网络状况不佳时,日志从产生到最终落盘之间的延迟可能达到秒级。

第四,资源消耗。Fluentd本身需要占用内存和CPU资源来处理日志数据,高吞吐量场景下这可能成为一个瓶颈。

八、注意事项与最佳实践

8.1 磁盘空间预算规划

在设置日志轮转参数之前,先做一个粗略的磁盘空间预算:

# 查看系统整体磁盘使用情况
df -h

# 查看Docker数据目录的详细占用
sudo du -sh /var/lib/docker/*

# 查看Docker系统总览
docker system df

假设你的服务器有100GB的可用磁盘空间,建议的分配方式是:

  • 系统保留:10GB
  • Docker镜像和层:20GB
  • 容器数据卷:20GB
  • 日志预留:5GB(所有服务加起来)
  • 构建缓存和临时文件:5GB
  • 其他:40GB

如果日志预留是5GB,假设你有20个服务,那么每个服务平均可以分配250MB的日志空间。对应到max-size和max-file参数,比如可以设置为max-size=50m,max-file=5,即每个服务250MB。

8.2 区分日志级别:在应用层面控制输出量

日志轮转只能控制文件大小,不能控制日志内容的质量。一个更根本的优化方式是在应用代码中控制日志级别:

# Python应用日志级别配置示例
import os
import logging
import logging.config

# 根据环境变量动态设置日志级别
LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO').upper()
LOG_FORMAT = '%(asctime)s [%(levelname)s] %(name)s - %(message)s'

# 配置根日志器
logging.basicConfig(
    level=getattr(logging, LOG_LEVEL),
    format=LOG_FORMAT,
    datefmt='%Y-%m-%d %H:%M:%S'
)

# 生产环境:只记录WARNING和ERROR
# 开发环境:可以设置为DEBUG
if LOG_LEVEL == 'PRODUCTION':
    # 降低第三方库的日志级别,减少噪音
    logging.getLogger('urllib3').setLevel(logging.WARNING)
    logging.getLogger('requests').setLevel(logging.WARNING)
    logging.getLogger('botocore').setLevel(logging.WARNING)
# docker-compose.yml 中通过环境变量控制日志级别
version: '3.8'

services:
  app:
    image: myapp:latest
    environment:
      LOG_LEVEL: "INFO"       # 生产环境使用INFO
      # LOG_LEVEL: "DEBUG"    # 开发环境使用DEBUG

8.3 日志中不要包含敏感信息

这是一个安全相关的注意事项,经常被开发者忽视。docker logs输出的内容对任何有Docker访问权限的人都是可见的,所以在日志中写入敏感信息是一个安全隐患。

# 反面示例:在日志中打印敏感信息
import logging
logger = logging.getLogger(__name__)

def login(password, api_key):
    # 错误做法:打印密码和API密钥
    logger.info(f"用户登录,密码: {password}, API密钥: {api_key}")
    # 这样做会导致敏感信息被写入日志文件
# 正面示例:不在日志中打印敏感信息
def login(password, api_key):
    # 正确做法:只记录必要信息,敏感数据用占位符替代
    logger.info("用户登录成功,密码: ****, API密钥: ****")
    # 或者使用debug级别记录详细信息,生产环境关闭debug
    logger.debug(f"用户登录,密码: {password}, API密钥: {api_key}")

8.4 监控日志磁盘使用情况

设置好日志轮转策略只是第一步,还需要持续监控磁盘使用情况,防止策略失效或被遗忘。

#!/bin/bash
# /opt/scripts/monitor-docker-log-space.sh
# Docker日志磁盘空间监控脚本

# 定义监控阈值
THRESHOLD_PERCENT=80  # 当磁盘使用率达到80%时告警

# 获取Docker数据目录的磁盘使用率
USAGE_PERCENT=$(df /var/lib/docker 2>/dev/null | tail -1 | awk '{print $5}' | sed 's/%//')

if [ -n "$USAGE_PERCENT" ] && [ "$USAGE_PERCENT" -ge "$THRESHOLD_PERCENT" ]; then
    # 收集详细信息
    DOCKER_TOTAL=$(du -sh /var/lib/docker 2>/dev/null | cut -f1)
    LOG_TOTAL=$(du -sh /var/lib/docker/containers 2>/dev/null | cut -f1)
    
    # 发送告警(这里可以用邮件、Webhook等方式)
    ALERT_MSG="警告: Docker磁盘使用率达到 ${USAGE_PERCENT}% (阈值: ${THRESHOLD_PERCENT}%)
Docker总占用: ${DOCKER_TOTAL}
日志目录占用: ${LOG_TOTAL}
时间: $(date '+%Y-%m-%d %H:%M:%S')"
    
    echo "$ALERT_MSG" | mail -s "Docker磁盘空间告警" admin@example.com
    # 也可以使用企业微信/钉钉WebHook发送通知
fi
# 添加到crontab,每小时检查一次
crontab -e
# 添加以下行:
# 0 * * * * /opt/scripts/monitor-docker-log-space.sh

8.5 配置文件版本管理

docker-compose.yml中的日志配置是重要的运维配置,应该纳入版本管理:

# 创建.gitignore排除敏感信息但保留compose配置结构
cat > .gitignore << 'EOF'
.env
docker-compose.override.yml
# 不要忽略这些文件:
# docker-compose.yml
# docker-compose.prod.yml
# daemon.json
EOF
# 使用不同的compose文件管理不同环境的日志配置
# 开发环境
docker-compose -f docker-compose.yml up -d

# 生产环境(使用override文件)
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# docker-compose.prod.yml - 生产环境覆盖配置
version: '3.8'

services:
  web:
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "5"

  database:
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "3"

8.6 容器重建时注意日志配置更新

当你修改了logging配置后,必须重建容器才能应用新配置。仅仅执行docker-compose restart不会生效,因为restart只是重启容器进程,不会重新创建容器。

# 查看容器当前使用的日志配置
docker inspect myapp --format '日志驱动: {{.HostConfig.LogConfig.Type}}'
docker inspect myapp --format '日志配置: {{json .HostConfig.LogConfig.Config}}'

# 正确的做法:down + up 重新创建容器
docker-compose down
docker-compose up -d

# 验证新配置是否生效
docker inspect myapp --format '{{json .HostConfig.LogConfig}}' | jq .

九、文章总结

容器日志膨胀是一个容易被忽视但后果严重的问题。一个没有配置轮转策略的Docker容器,可能在几天内产生数百GB的日志文件,最终导致磁盘空间耗尽,应用崩溃,甚至影响宿主机上其他服务的正常运行。

回顾本文的核心要点:

第一,永远不要依赖Docker的默认日志配置。默认的json-file驱动没有任何大小限制,日志文件会无限增长。

第二,在daemon.json或docker-compose.yml中配置日志轮转策略。daemon.json提供全局安全网,docker-compose.yml提供精细的服务级控制。

第三,根据服务特点设置差异化的轮转参数。反向代理和网关日志量大,需要更大的max-size和max-file;数据库和定时任务日志量小,可以设置保守的限制。

第四,配合日志清理脚本和磁盘监控,形成完整的日志管理闭环。轮转只是第一道防线,需要定期清理过期日志,并持续监控磁盘使用情况。

第五,在应用层面控制日志输出量和日志级别。从源头减少无用的日志输出,比事后清理更有效。

第六,根据部署规模和运维能力选择合适的日志驱动。单机部署用json-file加轮转就够了,多节点集群需要引入Fluentd等集中式日志方案。

日志管理不是小事。一个花10分钟配置好的轮转策略,可以帮你避免数小时的故障排查和系统恢复工作。就像那句话说的:预防胜于治疗。与其等服务挂了再手忙脚乱,不如在第一天就把日志管理做好。