使用 `journald` 驱动时如何查询指定容器的日志

解读

在国内生产环境中,systemdjournald 是 CentOS 7/8、Ubuntu 20.04 等主流镜像的默认初始化系统。面试官问此题,核心想验证两点:

  1. 你是否真的把 Docker 日志驱动从默认 json-file 切到 journald 并落地过;
  2. 面对大规模集群时,你能否快速、精准、低侵入地捞日志,而不是粗暴地 docker logs
    答不出 journalctl 关键字段或不会过滤,会被直接判定为“只背过书,没上过线”。

知识点

  1. 日志驱动配置/etc/docker/daemon.json"log-driver": "journald",重启 Docker 生效。
  2. journald 索引字段
    • CONTAINER_TAG 镜像名:tag
    • CONTAINER_ID_FULL 64 位完整容器 ID
    • CONTAINER_NAME 启动时带 k8s_ 前缀的 Pod 容器名
  3. journalctl 过滤语法-u 匹配 systemd unit、-o 控制输出格式、-b 限制本次启动、_SYSTEMD_UNIT=docker.service 限定日志源。
  4. 时间与分页--since--until 支持 2024-07-01 08:00:00 格式,配合 --no-pager 可在脚本里直接 grep。
  5. 性能与权限journald 日志存 /run/log/journal/var/log/journal磁盘打爆是常见故障;普通用户需加入 systemd-journal 组才能读取。
  6. 与 JSON-File 差异docker logs 仅适用于本地驱动,journald 场景下 docker logs 会直接报错,必须转用 journalctl

答案

  1. 确认本机日志驱动
    docker info | grep 'Logging Driver'
    输出应为 journald

  2. 查询指定容器最近一次启动的日志
    已知容器短 ID 为 3b8f2e1b5e31,先拿完整 ID:
    CID=$(docker inspect -f '{{.Id}}' 3b8f2e1b5e31)

    CONTAINER_ID_FULL 字段精准过滤:
    journalctl -o short-iso _SYSTEMD_UNIT=docker.service CONTAINER_ID_FULL=$CID --since '1 hour ago'

    若只记得容器名 my-nginx,可用:
    journalctl -o cat CONTAINER_NAME=my-nginx --since '30 minutes ago' | grep ERROR

  3. 持续 tail 最新日志(等价于 docker logs -f
    journalctl -f -o short-iso CONTAINER_ID_FULL=$CID

  4. 时间范围导出给研发排障
    journalctl -o json --since '2024-07-02 14:00:00' --until '2024-07-02 14:30:00' CONTAINER_ID_FULL=$CID > container.json

  5. 权限不足时
    sudo usermod -aG systemd-journal ${USER} 重新登录即可。

拓展思考

  1. 多节点场景:journald 日志仅存本机,大规模集群需结合 rsyslog→Kafkafluent-bit+Elasticsearch 做集中化,避免 SSH 逐台 journalctl
  2. 字段裁剪:生产镜像建议写 JSON 结构化日志到 stdout,再通过 journalctl -o json 直接落盘 ES,减少二次解析 CPU 开销
  3. 存储策略:默认 SystemMaxUse=1G 在容器密集节点 3 天就满,需调大 /etc/systemd/journald.conf 并配合 logrotate 做压缩。
  4. 安全加固:敏感业务需开启 Seal=yes 防止日志被篡改,同时把 CONTAINER_ID_FULLKubernetes Pod UID 做映射,满足等保审计要求。