Skip to content

容器运行与监控

容器监控要同时看宿主机、Docker daemon、容器资源和应用自身。只确认容器是 running 远远不够——CPU 打满、内存接近上限、磁盘涨满、容器频繁重启、OOM 和健康检查失败,都要能被发现。

监控的四个层次

层次关注点
宿主机CPU、内存、磁盘、inode、网络、内核日志
Docker daemon服务状态、事件、镜像和容器数量
容器CPU、内存、网络、块 IO、重启次数、健康状态
应用QPS、错误率、延迟、业务日志

容器监控是宿主机监控的补充,不是替代。容器跑在宿主机上,磁盘满、conntrack 满、Docker daemon 异常——根因最终仍然在宿主机层面。

docker stats——临时查看

bash
docker stats                  # 实时看所有运行容器的资源
docker stats --no-stream      # 只看一次,不持续刷新
字段说明
CPU %容器 CPU 使用率
MEM USAGE / LIMIT已用内存和限制值
MEM %内存使用比例
NET I/O网络收发字节
BLOCK I/O磁盘读写字节
PIDS进程数

docker stats 适合现场排查,不适合长期留存和趋势分析。长期趋势要接 Prometheus、Zabbix 或其他监控系统。

cAdvisor——容器资源指标采集

cAdvisor 采集容器 CPU、内存、网络、文件系统等指标,暴露 Prometheus 格式的 /metrics 接口:

bash
docker run -d \
  --name cadvisor \
  --restart unless-stopped \
  -p 127.0.0.1:8088:8080 \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:ro \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  gcr.io/cadvisor/cadvisor:v0.49.1

挂载说明:

挂载用途
/:/rootfs:ro读取宿主机文件系统信息
/var/run:/var/run:ro读取运行时 socket 和进程信息
/sys:/sys:ro读取 cgroups、设备、内核信息
/var/lib/docker:/var/lib/docker:ro读取 Docker 容器文件系统信息

cAdvisor 只绑定 127.0.0.1:8088。指标接口包含了宿主机和容器的详细信息,不适合直接暴露给公网或业务网络。如果 Prometheus 在另一台机器上,需要把 cAdvisor 暴露在监控网段,或通过反向代理限制访问来源。

Prometheus 抓取和常用指标

yaml
scrape_configs:
  - job_name: "cadvisor"
    static_configs:
      - targets:
          - "192.168.10.11:8088"

cAdvisor 指标很多,日常先关注这些:

指标含义
container_cpu_usage_seconds_total容器 CPU 累计使用时间
container_memory_working_set_bytes容器工作集内存(最接近 OOM 判断依据)
container_network_receive_bytes_total容器网络接收字节
container_network_transmit_bytes_total容器网络发送字节
container_fs_usage_bytes容器文件系统使用量
container_fs_reads_bytes_total容器读 IO
container_fs_writes_bytes_total容器写 IO

PromQL 示例:

promql
# 按容器看最近 5 分钟 CPU 使用速率
rate(container_cpu_usage_seconds_total{name!=""}[5m])

# 按容器看当前内存使用
container_memory_working_set_bytes{name!=""}

容器指标的标签在不同环境(Docker、K8s、containerd)里不完全一样——容器名、镜像名、实例、namespace 的标签名可能有差异。写告警规则前要先看实际标签,不要直接照搬别的环境的 PromQL。

Docker daemon 指标

Docker daemon 自身也可以暴露 Prometheus metrics。/etc/docker/daemon.json

json
{
  "metrics-addr": "127.0.0.1:9323",
  "experimental": true
}

experimental 在不同 Docker 版本里的要求不同,以当前版本官方文档和 dockerd --help 为准。

bash
sudo systemctl restart docker
curl http://127.0.0.1:9323/metrics | head

daemon metrics 偏向 Docker 自身状态(守护进程的 goroutine、API 请求延迟、镜像操作计数等),不替代 cAdvisor 的容器资源指标。这个端口也通常只绑定本机或监控网段。

日志和事件

监控不只是指标,还包括日志和事件:

bash
docker events --since 1h    # 最近 1 小时内的容器创建、停止、OOM 等事件
docker logs --since 30m app # 最近 30 分钟日志

生产环境里日志通常接到 Loki、ELK、Fluent Bit、Filebeat 或云日志服务。容器标准输出天然适合采集,但应用日志格式要稳定——日志结构不统一,查询和告警规则就很难维护。

日志轮转

默认 json-file 日志驱动会把容器标准输出写到宿主机文件里。查看日志文件路径:

bash
docker inspect web --format '{{.LogPath}}'

daemon 级别轮转配置写在 /etc/docker/daemon.json

json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "5"
  }
}

重启 Docker 后,这个配置只对新建容器生效。已经存在的容器要重建才会应用新的日志选项。日志量大的服务除了本地轮转,还要接入日志平台;本地日志只作为短期排查和兜底。

OOM 和资源限制

容器被 OOM kill 时,docker ps -a 可能看到退出码 137inspect 能看到是否被 OOM:

bash
docker ps -a --filter name=app
docker inspect app --format '{{.State.OOMKilled}} {{.State.ExitCode}}'
dmesg -T | grep -i 'killed process'

常见方向:

方向说明
应用内存泄漏内存持续上涨,重启后暂时恢复
限制太小正常业务峰值也超过了 --memory
运行时参数未适配JVM heap、Node.js old space、Go GC 没按容器限制设置
宿主机整体内存不足多个容器和系统进程共同造成内存压力

内存限制是硬上限。Java 的 -Xmx、Node.js 的 --max-old-space-size、Go 的 GOMEMLIMIT 都要和容器限制对齐。

健康检查

健康检查用于判断服务是否真的可用,不只是进程是否存在:

bash
docker run -d \
  --name app \
  --health-cmd 'curl -fsS http://127.0.0.1:8080/health || exit 1' \
  --health-interval 30s \
  --health-timeout 3s \
  --health-retries 3 \
  registry.example.com/ops/app:1.0

查看状态:

bash
docker inspect app --format '{{.State.Health.Status}}'
docker inspect app --format '{{json .State.Health.Log}}'

健康检查路径要轻,只检查进程能否处理基本请求和关键依赖的最小状态。复杂 SQL、远程接口调用和慢逻辑放进健康检查,故障时会让入口层更难判断。

高权限参数和 socket 风险

参数或挂载风险
--privileged放开大量内核能力和设备访问
-v /:/host把宿主机根目录挂进容器
--network host网络隔离减弱
--pid host能看到宿主机进程命名空间
/var/run/docker.sock容器可以控制宿主机 Docker

节点监控、网络排查、CI 构建工具有时需要高权限或 Docker socket。配置时要把范围收窄到具体容器和具体环境,能给单个 capability 就不直接开 --privileged

告警方向

告警说明
宿主机磁盘使用率高/var/lib/docker、日志、volume 都会受影响
容器内存接近限制提前发现 OOM 风险,不要等 kill 了再查
容器频繁重启应用崩溃、配置错误、依赖不可用
健康检查失败服务进程还在但已不可用——比进程退出更难发现
镜像拉取失败仓库、网络、证书、权限问题
Docker daemon down单机所有容器的管理能力异常

容器频繁重启要配合应用日志一起看。只报"容器重启了 10 次"信息量不够,告警最好能同时带上退出码、OOMKilled 状态、最近日志摘要和镜像版本。

现场排查顺序

bash
# 第一步:容器层面
docker ps -a
docker inspect app --format '{{.State.Status}} {{.State.ExitCode}} {{.State.OOMKilled}}'
docker logs --tail 100 app
docker stats --no-stream app
journalctl -u docker -n 100 --no-pager

# 第二步:宿主机层面
df -h
df -ih
free -h
dmesg -T | tail -n 50
ss -lntp

容器监控的价值在于把"容器状态、资源曲线、宿主机状态、应用日志"四条线串起来。只看其中一条,Docker 问题、宿主机问题和应用问题很容易混在一起——排查效率取决于能不能快速定界到其中一层。