如何使用 Docker 搭建日志归档服务?

来源:PHP编程网作者:长沙GEO公司头衔:草根站长
导读:本期聚焦于长沙GEO公司创作的《如何使用 Docker 搭建日志归档服务?》,敬请观看详情。生产环境中的应用容器每天产生大量日志,如果不及时处理,很容易把磁盘写满。日志归档不是简单地把文件拷贝到另一个目录,它需要解决收集、压缩、定时执行、过期清理这几个环节。本文给出一个基于 Docker Compose 的轻量级方案:应用容器和归档容器共享同一个日志卷,归档容器内置 cron 定时任务,每天凌晨对前一天日志执行打包压缩,并删除超过指定天数的归档文件。相比在宿主机上配置 logrotate,这种做法的好处是归档逻辑随容器一起交付,不依赖宿主机环境,迁移和扩缩容更方便。文中会逐步展示目录结构、Dockerfile、Compose 配置和归档脚本,并说明如何验证归档是否成功。阅读完可以快速落地一套可复用的容器化日志归档机制。

日志文件如果只进不出,再大的磁盘也会被慢慢耗尽。容器化部署让应用日志的落盘位置变得分散,传统在宿主机上配置 logrotate 的方式很难跟随服务一起迁移。我们可以借助 Docker 的卷共享能力,把日志归档做成一个独立的容器:应用容器只负责把日志写入指定目录,归档容器则定时扫描该目录,按天压缩打包,并清理过期文件。这样归档策略和业务容器解耦,也更容易在不同环境中复现。

如何使用 Docker 搭建日志归档服务?

一、容器化日志归档的整体设计

这套方案的核心是让多个容器共享同一个日志卷。假设我们有一个 Nginx 服务,它的访问日志和错误日志统一写到 /var/log/app 目录。我们在宿主机上创建一个命名卷,或者直接绑定挂载一个宿主目录,例如 ./logs:/var/log/app,然后将同一个目录再挂载到归档容器的 /logs 路径。这样归档容器就能看到应用容器刚写出的日志文件,而不需要通过网络传输或额外配置。

归档容器内部运行一个轻量级 Linux 发行版,比如 Alpine,并安装 cron 和 tar。cron 定时触发归档脚本,脚本会遍历日志目录,找到前一天产生的日志文件,将其打包成带日期的 tar.gz 文件,移动到归档目录。随后脚本会删除超过保留期限的归档包,避免归档目录无限增长。整个过程都在容器内完成,宿主机只需要保留一个数据目录。

这种设计有两个明显优点。第一,归档逻辑和业务镜像完全分离,更新归档策略时不需要重新构建业务镜像。第二,容器化后的归档服务可以随 Docker Compose 一起启动,新环境只需要一份 Compose 文件就能恢复完整的日志归档能力。它比在宿主机上写 crontab 更容易做版本管理和团队协作。

二、编写归档脚本与 Dockerfile

归档脚本是整套服务的执行核心。我们使用 Shell 编写一个简单脚本,逻辑分为三步:定位日志目录、按日期打包、清理过期归档。为了确保脚本在容器中稳定运行,需要显式指定路径和 shell。下面是一个可直接使用的示例,脚本中避免了复杂的条件判断,重点展示归档动作。

#!/bin/sh
set -e

LOG_DIR="/logs"
ARCHIVE_DIR="/archive"
DATE_STR=$(date -d "yesterday" +%Y%m%d)
KEEP_DAYS=30

mkdir -p "$ARCHIVE_DIR"

for file in "$LOG_DIR"/*.log; do
    if [ -f "$file" ]; then
        base=$(basename "$file")
        tar -czf "$ARCHIVE_DIR/${base%.log}-${DATE_STR}.tar.gz" -C "$LOG_DIR" "$base"
    fi
done

find "$ARCHIVE_DIR" -type f -mtime +${KEEP_DAYS} -delete

脚本中 date -d "yesterday" 是为了按自然日归档前一天的日志,避免在日志文件正在写入时直接打包导致截断。打包完成后,find 命令会删除修改时间超过 30 天的归档文件。这里使用 mtime 判断文件年龄,如果归档目录中还有其他类型文件,可以再用 -name "*.tar.gz" 进一步限定。需要注意的是,Alpine 镜像内置的 date 命令来自 BusyBox,它支持 -d 参数,但部分精简系统可能不支持,因此选择镜像时要确认。

接下来编写 Dockerfile。基础镜像使用 Alpine 是为了体积小,同时通过 apk 安装 bash 和 dcron。Alpine 默认没有 cron 服务,dcron 是一个轻量级替代方案。我们把归档脚本复制到镜像中,并配置 crontab 文件。

FROM alpine:3.20

RUN apk add --no-cache bash dcron

COPY archive.sh /usr/local/bin/archive.sh
RUN chmod +x /usr/local/bin/archive.sh

COPY crontab.txt /etc/crontabs/root

CMD ["crond", "-f", "-l", "2"]

crond 是 dcron 提供的守护进程,-f 表示前台运行,这样容器启动后不会立即退出。归档脚本被放在 /usr/local/bin 目录下,并赋予可执行权限。crontab 文件内容极简单,只需要一行:

0 2 * * * /usr/local/bin/archive.sh

这行配置表示每天凌晨 2 点执行归档脚本。容器内默认使用 UTC 时间,如果业务需要按本地时区归档,可以在 Dockerfile 中安装 tzdata 并设置 TZ 环境变量,或者接受 UTC 时间并在脚本中调整日期计算方式。

三、用 Docker Compose 编排日志归档服务

有了归档镜像后,下一步就是通过 Docker Compose 把应用容器和归档容器组合起来。Compose 文件需要定义两个服务:一个是模拟业务服务的 Nginx,另一个是归档服务。关键点在于两个服务挂载同一个卷,且归档容器需要挂载归档输出目录,以便在宿主机上查看归档结果。

version: "3.8"

services:
  web:
    image: nginx:1.27
    volumes:
      - ./logs:/var/log/app
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "8080:80"

  archiver:
    build: ./archiver
    volumes:
      - ./logs:/logs
      - ./archive:/archive
    restart: unless-stopped

在这个配置中,宿主机目录 ./logs 同时挂载到 Nginx 容器的 /var/log/app 和归档容器的 /logs。Nginx 需要调整配置,让 access_log 和 error_log 写到该目录。归档容器额外挂载 ./archive/archive,用于保存压缩后的归档文件。这样做的好处是宿主机上可以直接查看 ./archive 目录内容,不需要进入容器。

需要说明的是,如果使用 Docker 命名卷而不是绑定挂载,共享方式类似,但宿主机路径由 Docker 管理。对于生产环境,建议使用绑定挂载并纳入备份策略,因为归档文件本身就是需要长期保存的数据。另外,如果多个应用容器都写日志到同一个目录,归档脚本需要根据文件名区分来源,本文示例只处理 *.log 文件,如果有子目录结构,可以进一步扩展。

归档服务的构建上下文是 ./archiver,需要在该目录下放置 Dockerfile、archive.sh 和 crontab.txt。启动时直接执行 docker compose up -d --build,归档容器会以守护进程方式运行。若想验证 cron 是否生效,可以查看容器日志。

四、验证归档效果与常见问题

服务启动后,可以先手动向 Nginx 发送几个请求,确保日志文件产生。然后进入归档容器,手动执行一次归档脚本,检查 /archive 目录中是否出现了当天或前一天的 tar.gz 文件。例如使用 docker compose exec archiver sh -c 'ls -lh /archive' 查看文件列表。如果脚本没有执行成功,优先检查挂载目录权限以及脚本中的换行符是否为 LF 格式。

docker compose exec web sh -c 'echo "test log line" >> /var/log/app/access.log'
docker compose exec archiver sh -c '/usr/local/bin/archive.sh'
docker compose exec archiver sh -c 'ls -lh /archive'

常见的坑包括:归档容器内 cron 没有启动,通常是因为基础镜像缺少 cron 或启动命令写错;脚本没有可执行权限,导致 cron 无法调用;挂载目录在 Windows 或 macOS 上存在性能差异,大量小文件时归档速度会下降。对于 Linux 服务器,这些问题较少出现,但仍建议在 CI 中增加一次手动触发归档的测试。

另一个需要关注的是归档文件的保留策略。本方案使用 find -mtime +30 清理文件,但归档文件的修改时间在创建后几乎不会再变化,因此用修改时间判断是可靠的。如果归档目录中还有其他用途的文件,建议加上 -name "*.tar.gz" 参数。若日志量很大,也可以把 tar -czf 改为 tar -cf 配合外部压缩工具,但 gzip 对文本日志的压缩率已经很高,大多数场景下足够使用。

最后,这套方案虽然轻量,但它的定位是中小规模的日志归档。对于分布式系统或日志量达到每天数百 GB 的场景,更适合引入 Loki、Elasticsearch 等集中式日志平台,配合对象存储做冷数据归档。不过对于单体应用、内部系统或边缘节点,本文的 Docker 归档方案已经可以稳定运行,并且维护成本非常低。

Docker日志归档容器化修改时间:2026-08-24 21:10:06

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。