Docker 容器监控与日志实践:cgroups 资源限制、Prometheus 与日志驱动

Docker 容器监控与日志完整实践:cgroups 资源限制(CPU/内存/IO)与 docker stats、Prometheus + cAdvisor 指标采集、日志驱动(json-file/loki/fluentd)、logrotate 与日志轮转、健康检查与重启策略、告警与容量规划。

容器"跑起来了"不代表"跑得好"。Docker 自带的 docker stats 只能看实时状态,生产环境需要完整监控:用 cgroups 给容器设资源上限、用 cAdvisor + Prometheus 采集指标、用日志驱动统一收集日志并轮转。本指南把 Docker 的"监控 + 日志"从命令级提升到可告警、可排障的生产体系。

关键概念:容器资源限制靠 Linux cgroups(CPU/内存/IO 限额),采集靠 cAdvisor(容器指标 exporter),日志靠 logging driver(从 docker logs 到统一后端)。三者组合起来,容器才有"可观测性"。


1. cgroups:给容器设资源上限

1.1 为什么必须设限制

不设限制的后果:
  - 一个容器吃光所有 CPU → 影响其他容器与宿主机
  - 内存泄漏 → 触发 OOM,可能拖垮节点
  - 磁盘 IO 打满 → 整机卡顿

cgroups 让 Docker 能按容器隔离并限制资源:
  - CPU:--cpus(核数)、--cpu-shares(权重)
  - 内存:--memory、--memory-swap、--memory-reservation
  - IO:--device-read-bps、--device-write-bps

1.2 常用限制示例

# 限制为 2 核、内存 1G、交换 512M
docker run \
  --cpus=2 \
  --memory=1g \
  --memory-swap=1.5g \
  --name api \
  myapp:1.0

# compose 中同样配置
# deploy.resources.limits.cpus / limits.memory
为什么合理设置很重要:
  - 给足资源但留上限 → 防"单容器拖垮全机"
  - 设置内存上限 → 内存泄漏有边界(重启优于蔓延)
  - 关键服务预留 → 用 cpu-shares 给重要容器更高权重

2. 实时监控:docker stats 与自建采集

2.1 docker stats:秒级实时

docker stats              # 所有运行容器
docker stats api db       # 指定容器
# 显示:CPU%、内存用量/上限、网络 IO、磁盘 IO、PID

# 带格式化输出方便脚本
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

2.2 采集到 Prometheus:cAdvisor

cAdvisor(Google 开源,现已并入 cadvisor):
  作为容器运行,暴露 /metrics(Prometheus 格式)
  采集每个容器的 CPU/内存/网络/磁盘指标

部署(compose):
  cAdvisor 容器挂载 /var/lib/docker 与 cgroups,暴露 8080
  → Prometheus 用 kubernetes_sd/file_sd/static_config 抓取
  → Grafana 用官方 cadvisor 仪表盘展示
# 运行 cAdvisor(简化版)
docker run -d \
  --name cadvisor \
  --privileged \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -v /:/rootfs:ro \
  -v /var/lib/docker/:/var/lib/docker:ro \
  -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
  -p 8080:8080 \
  gcr.io/cadvisor/cadvisor:latest

ℹ️ 核心:docker stats 适合当场排障;cAdvisor → Prometheus → Grafana + 告警 才是长期监控。容器级指标、节点级指标一起采,才能定位"是容器还是宿主"。


3. 日志驱动:把 docker logs 送到统一后端

3.1 logging driver 是什么

Docker 的容器日志默认 json-file(存在节点磁盘)
  → docker logs 能看到,但:
    - 文件无限增长会撑爆磁盘
    - 多节点不便集中查看/检索

logging driver 把容器 stdout/stderr 转送到统一后端:
  - json-file(默认,本地)
  - syslog / journald(系统日志)
  - fluentd / fluent-bit(Fluent 生态)
  - gelf(Graylog)
  - loki(Grafana Loki)
  - awslogs / gcp / splunk 等云服务

3.2 配置与日志轮转

# 全局配置(daemon.json)
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",      # 单文件上限
    "max-file": "5"          # 保留轮转文件数
  }
}

# 或单容器指定
docker run --log-driver=json-file \
  --log-opt max-size=10m --log-opt max-file=3 myapp
日志轮转是必做项:
  不轮转 → 日志文件无上限增长 → 磁盘被日志写满
  设置 max-size + max-file 是防"日志撑爆磁盘"的第一道闸

3.3 Loki / Fluentd 集中收集

Loki 方案(轻量,与 Grafana 一体):
  promtail 或 docker 的 loki logging driver 收集
  → Loki 存储、Grafana 查询(LogQL)

Fluentd 方案(生态广):
  docker 的 fluentd driver 把日志送到 fluentd 集群
  → 可再转 Elasticsearch/Kafka 等

生产建议:
  中小规模 → Loki(简单、便宜)
  已有 ELK/EFK → 直接接 fluentd/fluent-bit
  日志量大 → 采样 + 分级(错误全量、INFO 采样)

4. 健康检查与自动重启

4.1 HEALTHCHECK

# Dockerfile 里定义健康检查
FROM myapp
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl -fsS http://localhost:8080/health || exit 1
# 或运行时/compose 指定
docker run --health-cmd="curl -fsS http://localhost/health" \
  --health-interval=30s --health-timeout=5s \
  --health-retries=3 myapp

4.2 重启策略

# --restart 策略控制崩溃后行为
docker run --restart=unless-stopped myapp
#   no / always / on-failure[:N] / unless-stopped

# Swarm/K8s 层面:失败自动重建到期望副本数
# 本地 compose:restart: unless-stopped
健康检查 + 重启策略的组合:
  探活失败 → 标记 unhealthy → 编排/重启拉起
  单机 docker:on-failure 重启,配日志定位根因

5. 告警与容量规划

告警维度(容器级):
  - 内存使用率 > 90% 持续 5m
  - CPU 长时间打满
  - 容器频繁重启(restart 计数)
  - 日志增长异常 / 错误日志激增

容量规划:
  - 记录容器峰值资源 → 定合理 limits
  - 节点可用资源 vs 所有容器 requests 之和
  - 预留余量,避免"容器全挤一个节点"

工具:Prometheus 规则 + Alertmanager 告警到 IM/邮件
# Prometheus 告警示例:容器内存持续超限
- alert: ContainerMemoryHigh
  expr: (container_memory_usage_bytes / container_spec_memory_limit_bytes) > 0.9
  for: 5m
  annotations:
    summary: "容器内存使用率超过 90%"

6. 常见避坑

坑现象对策
不设资源限制一个容器拖垮全机设 cpus/memory limits
日志不轮转磁盘被写满max-size + max-file
只看 docker stats无历史、无法告警cAdvisor + Prometheus
日志全堆节点磁盘排障难、易丢logging driver 集中收集
无健康检查服务挂了自己不知道HEALTHCHECK + 告警
重启策略 no崩溃后不再起来restart=unless-stopped

7. 最佳实践清单

□ 所有容器设 cpus/memory limits(防单容器拖垮)
□ 关键服务用 cpu-shares 保证权重
□ docker stats 只用于当场排障,长期用 cAdvisor+Prometheus
□ Grafana 建容器看板(CPU/内存/网络/磁盘)
□ 日志驱动选 Loki 或 fluentd,接集中后端
□ 配 max-size/max-file 日志轮转
□ HEALTHCHECK + restart 策略 + 告警
□ 记录峰值,做容量规划
□ Alertmanager 告警进 IM/邮件

一句话原则

Docker 可观测性 = cgroups 设边界 + cAdvisor 采指标 + 日志驱动集中收,
三者齐了,容器才算"看得清、防得住、查得了"。

小结

Docker 监控与日志的工程化,本质是给容器"装上仪表盘和安全带":cgroups 限制 CPU/内存/IO 防止失控、cAdvisor + Prometheus + Grafana 建立长期可告警的指标体系、logging driver 把分散日志集中起来并轮转。落地记住五件事:容器必须设资源上限、docker stats 只排障用而 cAdvisor 才是长期采集、日志必配 max-size/max-file 防撑爆、HEALTHCHECK + 重启策略 + 告警闭环、记录峰值做容量规划。当每个容器的资源、状态、日志都清晰可见并自动告警,Docker 环境才从"能跑"升级为"可运营"。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「DevOps」更多文章

  1. 备份与容灾自动化:RPO/RTO、Velero、PITR 与恢复演练
  2. 配置漂移与安全基线:IaC漂移检测、CIS合规、供应链安全与密钥轮换
  3. 内部开发者平台(IDP)工程化:Backstage、Golden Path 与自服务能力