摘要:容器是黑盒进程,观测靠两条通道——指标回答"哪里不对劲",日志回答"为什么不对劲"。本节从 docker stats 的手边观测起步,搭起 cAdvisor 加 Prometheus 加 Grafana 的指标流水线,再治理日志驱动、轮转与聚合,并给出两通道协作的排障流程。
一句老话在容器世界格外成立:没有度量就没有优化。容器把进程藏进隔离的视野里,出了问题时你在宿主机上既看不到它的文件(在 merged 视图里),也未必理解它的行为(依赖镜像里的实现)。观测体系就是给这个黑盒装仪表盘:指标告诉你系统哪个部位在发烫,日志告诉你它为什么发烫,两者配合才能完成从症状到根因的完整推理。这套体系应该随第一个生产容器一起建立,而不是出事之后再补——事后补的观测,恰好错过你最需要它记录的那一刻。先从最简单的三板斧开始。
最快的观测不需要任何组件:
docker stats # 全部容器实时资源 docker stats web # 单容器持续观察 docker events --since 10m # 守护进程事件流
stats 的输出就是第 3 章 cgroup 账本的可视化:CPU 百分比来自配额换算、MEM LIMIT 那一列就是 --memory 写进去的墙。docker events 则是守护进程的审计流——谁启动了容器、哪个容器 OOM 死了、健康检查何时翻转,运维排障时把它挂在旁边一个终端里,很多问题在事件流里直接现形。
三板斧够手边用,但生产需要历史数据与告警,那就要一条指标流水线。
标准三件套各司其职:cAdvisor(谷歌开源)从 cgroup 与内核读取每个容器的 CPU、内存、网络、磁盘指标并以 Prometheus 格式暴露;Prometheus 定时抓取并存储时序数据;Grafana 查询绘图做面板。用 Compose 一把拉起(第 6 章知识的直接复用):
services: cadvisor: image: gcr.io/cadvisor/cadvisor:v0.49.1 volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro ports: - "8080:8080" prometheus: image: prom/prometheus:v2.54.1 volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro ports: - "9090:9090" grafana: image: grafana/grafana:11.2.0 ports: - "3000:3000"
注意 cAdvisor 的挂载:它以只读方式挂入宿主机的 /sys 与 docker 数据目录,正是在读第 3 章讲过的 cgroup 文件系统——指标不是魔法,是账本的另一种呈现。Grafana 里导入现成的容器监控面板模板,几分钟就能看到每个容器的历史曲线。
容器视角最有告警价值的四个指标:内存接近 limit(OOM 前兆,第 3 章 137 的预警)、CPU throttled 时间增长(配额不足)、容器重启次数(自愈掩盖的崩溃循环)、健康检查翻转(僵死的前兆)。告警规则就围绕它们写。
容器日志的正确入口是 docker logs,它读的是日志驱动落盘的文件。驱动有多种可选:
| 驱动 | 去向 | 适用 |
|---|---|---|
| json-file | 本地 JSON 文件 | 默认,单机够用 |
| local | 本地二进制格式 | 更省空间,推荐单机替代 |
| syslog | 系统日志服务 | 接入已有日志设施 |
| fluentd / gelf | 日志聚合器 | 多机集中式 |
单机最要紧的是轮转配置,1.2 节配过的参数再确认一遍:
{ "log-driver": "local", "log-opts": { "max-size": "10m", "max-file": "3" } }
多机环境上聚合:每台机器的容器日志统一送往集中平台(ELK 或 Loki 一类),按容器名、镜像、标签检索。应用侧配套两条纪律:日志打到标准输出与标准错误(docker logs 才收得到,写文件到可写层是反模式——第 2 章讲过写时复制的代价);格式用结构化 JSON,字段稳定,聚合平台的检索才有价值。
⚠️ 一个容易踩的坑:json-file 驱动下 docker logs 显示的是文件累积内容,容器运行数月后 logs 命令会巨慢,且磁盘早已被吃掉大半。没有轮转配置的 json-file 是生产隐患,装机时就该配好。
指标与日志的分工,用一个流程固化下来:
三个真实判读例子:内存曲线锯齿状周期逼近 limit 后归零,伴随 OOMKilled 事件——不是泄漏,是 limit 设小了反复被杀重启;CPU 长期满载但 throttled 为零——不是配额问题,是应用真忙,去扩容;容器每五分钟重启一次、日志每次都在同一行栈回溯——崩溃循环,日志里的异常栈就是答案。
观测就绪,最后一节把全书串成一场生产实战。