容器化部署让应用的交付效率大幅提升,但也带来了新的可观测性挑战:日志分散在无数个短生命周期的容器中,资源指标转瞬即逝,传统基于主机的监控手段在动态调度面前几乎失效。要真正掌控 Docker 环境,必须从日志采集和指标监控两条线同时入手,构建一套完整的可观测性体系。
一、Docker 日志驱动:从 json-file 到集中式采集
Docker 默认使用 json-file 日志驱动,将容器的标准输出和标准错误以 JSON 格式写入宿主机文件。这种方式在单机调试时足够方便,但在多容器、多主机的生产环境中,日志文件会迅速膨胀,且难以跨节点检索。
Docker 提供了多种日志驱动,常见的有:
- json-file:默认驱动,支持
docker logs命令,但需要配合日志轮转防止磁盘写满。 - local:Docker 18.09 引入,采用更高效的二进制格式,同样支持
docker logs,推荐替代 json-file。 - syslog / journald:将日志转发到系统日志服务,适合已有集中式日志基础设施的团队。
- fluentd / gelf / awslogs:直接将日志推送到外部聚合系统,适合云原生环境。
- none:禁用日志,仅在对日志毫无需求的场景使用。
选择日志驱动时,核心考量是:日志是否需要长期保留、是否需要跨主机检索、是否已有日志聚合平台。对于大多数生产环境,推荐将日志驱动设置为 fluentd 或 local,再由 Fluent Bit / Fluentd 统一转发到 Elasticsearch 或 Loki。
配置方式有两种。全局配置修改 /etc/docker/daemon.json:
{
"log-driver": "local",
"log-opts": {
"max-size": "50m",
"max-file": "5"
}
}
单容器配置则在 docker run 或 Compose 文件中指定:
services:
app:
image: myapp:latest
logging:
driver: fluentd
options:
fluentd-address: "localhost:24224"
tag: "docker.{{.Name}}"
需要特别注意:日志驱动一旦在容器创建时确定,就无法通过重启容器更改,必须重新创建容器。因此建议在项目初期就规划好日志策略。
二、Prometheus 指标采集:cAdvisor 与应用埋点
日志解决的是“发生了什么”,指标解决的是“系统状态如何”。Prometheus 已成为容器监控的事实标准,其拉取模型和强大的查询语言非常适合动态环境。
2.1 容器资源指标:cAdvisor
cAdvisor 是 Google 开源的容器资源采集器,能够自动发现宿主机上的所有容器,并暴露 CPU、内存、网络、文件系统等指标。部署方式非常简单:
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
privileged: true
devices:
- /dev/kmsg
启动后访问 http://localhost:8080/metrics 即可看到 Prometheus 格式的指标。在 Prometheus 配置中加入抓取任务:
scrape_configs:
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
2.2 应用层指标:Client Library 埋点
cAdvisor 只能提供容器级别的资源指标,业务层面的 QPS、延迟、错误率等需要应用自身暴露。Prometheus 提供了多语言客户端库,以 Go 为例:
httpRequestsTotal := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path", "status"},
)
prometheus.MustRegister(httpRequestsTotal)
http.Handle("/metrics", promhttp.Handler())
Python、Java、Node.js 等语言也有对应的客户端库。关键原则是:指标命名遵循 <namespace>_<subsystem>_<name> 规范,标签基数不宜过高,避免使用用户 ID 等高基数字段作为标签。
2.3 可视化:Grafana
Prometheus 自带的表达式浏览器适合调试,但日常监控需要 Grafana。导入社区维护的 Dashboard(如 cAdvisor 的 Dashboard ID 14282),几分钟内就能获得完整的容器监控视图。建议至少配置以下面板:
- 容器 CPU 使用率与 throttling 次数
- 容器内存使用量与 OOM 事件
- 网络收发速率与丢包
- 应用请求速率、P95/P99 延迟、错误率
三、告警规则:从指标到行动
监控的价值最终体现在告警上。Prometheus 的告警由 Alertmanager 负责路由和去重,规则则在 Prometheus 中定义。
3.1 编写告警规则
以下是一组实用的容器告警规则示例:
groups:
- name: container_alerts
rules:
- alert: ContainerHighCpuUsage
expr: sum(rate(container_cpu_usage_seconds_total{name!=""}[5m])) by (name) > 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "容器 {{ $labels.name }} CPU 使用率过高"
description: "CPU 使用率已持续 10 分钟超过 80%"
- alert: ContainerMemoryNearLimit
expr: container_memory_usage_bytes / container_spec_memory_limit_bytes > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "容器 {{ $labels.name }} 内存接近上限"
- alert: ContainerRestarting
expr: rate(container_last_seen{name!=""}[5m]) < 0.5
for: 2m
labels:
severity: warning
annotations:
summary: "容器 {{ $labels.name }} 可能频繁重启"
3.2 告警分级与路由
告警不是越多越好。建议按严重程度分级:
- critical:需要立即人工介入,如服务不可用、内存 OOM、磁盘写满。通过电话或即时通讯工具直接通知值班人员。
- warning:需要关注但不必立即处理,如 CPU 持续偏高、延迟上升。通过邮件或低优先级频道通知。
- info:仅记录,用于趋势分析,不主动推送。
Alertmanager 的 route 配置支持按标签匹配路由到不同接收器,inhibit_rules 可以在严重告警触发时抑制相关次要告警,避免告警风暴。
3.3 避免常见陷阱
- 阈值不宜过紧:CPU 短时冲高是正常现象,
for子句能有效过滤抖动。 - 标签基数控制:告警规则中避免使用容器 ID 等易变标签,否则告警分组会爆炸。
- 定期回顾:每月审查一次告警历史,删除从未触发或频繁误报的规则。
四、体系整合与最佳实践
将日志和监控整合为统一的可观测性平台,建议遵循以下实践:
- 统一采集层:用 Fluent Bit 采集日志,用 Prometheus 采集指标,两者独立运行但共享标签体系(如
service、env、version),便于关联分析。 - 日志与指标联动:在 Grafana 中配置数据源关联,从指标面板一键跳转到对应时间段的日志查询。
- 资源限制与监控配合:为容器设置合理的
memory和cpu限制,监控告警阈值应略低于限制值,留出缓冲。 - 基础设施即代码:将 Prometheus 配置、告警规则、Grafana Dashboard 全部纳入 Git 管理,通过 CI/CD 自动部署。
- 容量规划:Prometheus 本地存储默认保留 15 天,生产环境建议配置远程存储(如 Thanos、VictoriaMetrics)以支持长期查询。
Docker 的可观测性建设不是一次性任务,而是伴随业务演进的持续过程。从日志驱动选型到指标采集,再到告警规则调优,每一步都需要结合自身业务特点做取舍。起步阶段不必追求大而全,先把核心指标和关键告警跑通,再逐步扩展覆盖范围,才能让监控体系真正服务于稳定性目标。
未经允许不得转载:任鹏个人博客 » Docker 容器日志与监控体系搭建:日志驱动、Prometheus 指标采集与告警


朋友圈点赞图在线生成源码