跳到主要内容

Docker 监控与调试

有效的监控和调试是保障容器化应用稳定运行的关键。本章将介绍 Docker 的监控工具、日志管理和故障排除技术。

监控概述

为什么需要监控?

容器化环境的监控与传统应用有所不同:

监控维度传统应用容器化应用
资源粒度虚拟机/物理机容器级别
生命周期长期运行动态创建销毁
网络模型固定 IP动态网络
日志收集文件系统标准输出

监控指标类型

┌─────────────────────────────────────────────────────────┐
│ 监控指标层次 │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────┐ │
│ │ 应用指标 (Application) │ │
│ │ 请求量、响应时间、错误率 │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 容器指标 (Container) │ │
│ │ CPU、内存、网络、磁盘 IO │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 主机指标 (Host) │ │
│ │ 节点资源、内核状态、存储容量 │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘

内置监控命令

容器资源统计

docker stats 是最常用的资源监控命令:

# 实时查看所有容器资源使用
docker stats

# 输出示例
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
a1b2c3d4e5f6 nginx 0.50% 10MiB / 1GiB 1.00% 1.2kB / 0B 0B / 0B 5

# 查看特定容器
docker stats nginx redis

# 不实时刷新(只显示一次)
docker stats --no-stream

# 自定义输出格式
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# JSON 格式输出
docker stats --format json

指标说明

指标说明
CPU %CPU 使用百分比
MEM USAGE / LIMIT内存使用量/限制
MEM %内存使用百分比
NET I/O网络接收/发送字节
BLOCK I/O磁盘读写字节
PIDS进程数

查看容器进程

# 查看容器内进程
docker top nginx

# 输出示例
UID PID PPID C STIME TTY TIME CMD
root 1234 567 0 10:00 ? 00:00:01 nginx: master process

# 显示完整命令
docker top nginx aux

# 查看所有容器的进程
for container in $(docker ps -q); do
echo "=== $(docker inspect --format='{{.Name}}' $container) ==="
docker top $container
done

查看容器事件

# 实时监听 Docker 事件
docker events

# 过滤特定事件类型
docker events --filter type=container

# 过滤特定容器
docker events --filter container=nginx

# 过滤事件动作
docker events --filter event=start --filter event=stop --filter event=die

# 时间范围过滤
docker events --since 1h
docker events --since "2024-01-01" --until "2024-01-02"

# 格式化输出
docker events --format '{{.Time}} {{.Type}} {{.Action}} {{.Actor.ID}}'

查看容器详情

# 查看完整配置
docker inspect nginx

# 查看特定信息
docker inspect --format='{{.State.Status}}' nginx
docker inspect --format='{{.State.Health.Status}}' nginx
docker inspect --format='{{.NetworkSettings.IPAddress}}' nginx
docker inspect --format='{{.HostConfig.Memory}}' nginx

# 查看所有容器的 IP
docker inspect --format='{{.Name}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

日志管理

查看容器日志

# 查看日志
docker logs nginx

# 实时跟踪日志
docker logs -f nginx

# 显示最后 100 行
docker logs --tail 100 nginx

# 显示时间戳
docker logs -t nginx

# 时间范围过滤
docker logs --since 2024-01-01 nginx
docker logs --since 2h nginx
docker logs --until 1h nginx

# 组合使用
docker logs -f --tail 100 --since 1h nginx

日志驱动配置

Docker 支持多种日志驱动:

驱动说明适用场景
json-file默认,JSON 格式存储单机开发
local优化的本地日志生产环境
journald发送到 systemd journalsystemd 系统
syslog发送到 syslog 守护进程集中式日志
fluentd发送到 Fluentd日志聚合
awslogs发送到 AWS CloudWatchAWS 环境
none禁用日志安全敏感场景

运行时指定日志驱动

# 使用 journald
docker run -d --log-driver=journald nginx

# 使用 syslog
docker run -d --log-driver=syslog --log-opt syslog-address=tcp://192.168.1.1:514 nginx

# 禁用日志
docker run -d --log-driver=none nginx

# json-file 带限制
docker run -d \
--log-driver=json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx

Docker Daemon 配置

// /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3",
"labels": "production"
}
}

Docker Compose 配置

services:
app:
image: myapp
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

日志聚合方案

使用 ELK Stack

# docker-compose.yml
services:
elasticsearch:
image: elasticsearch:8.11.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- "9200:9200"
volumes:
- es-data:/usr/share/elasticsearch/data

logstash:
image: logstash:8.11.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
ports:
- "5000:5000"
depends_on:
- elasticsearch

kibana:
image: kibana:8.11.0
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
depends_on:
- elasticsearch

app:
image: myapp
logging:
driver: "syslog"
options:
syslog-address: "tcp://logstash:5000"
tag: "myapp"

volumes:
es-data:

使用 Loki + Grafana

services:
loki:
image: grafana/loki:latest
ports:
- "3100:3100"
volumes:
- ./loki-config.yml:/etc/loki/local-config.yaml

promtail:
image: grafana/promtail:latest
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml

grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_AUTH_ANONYMOUS_ENABLED=true
volumes:
- grafana-data:/var/lib/grafana

volumes:
grafana-data:

Prometheus 监控

部署 Prometheus 栈

# docker-compose.yml
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'

grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana

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

node-exporter:
image: prom/node-exporter:latest
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro

volumes:
prometheus-data:
grafana-data:

Prometheus 配置

# prometheus.yml
global:
scrape_interval: 15s

scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['prometheus:9090']

- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']

- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']

容器指标说明

cAdvisor 提供的主要指标

指标说明
container_cpu_usage_seconds_totalCPU 使用时间
container_memory_usage_bytes内存使用量
container_network_receive_bytes_total网络接收字节
container_network_transmit_bytes_total网络发送字节
container_fs_usage_bytes文件系统使用量
container_last_seen容器最后可见时间

常用 PromQL 查询

# 容器 CPU 使用率
rate(container_cpu_usage_seconds_total{name!="",image!=""}[5m]) * 100

# 容器内存使用
container_memory_usage_bytes{name!="",image!=""}

# 容器网络流量
rate(container_network_receive_bytes_total[5m])
rate(container_network_transmit_bytes_total[5m])

# 按容器名汇总 CPU
sum(rate(container_cpu_usage_seconds_total{name!="",image!=""}[5m])) by (name)

# 内存使用率最高的容器
topk(5, container_memory_usage_bytes{name!=""})

# 容器数量
count(container_last_seen)

cAdvisor 直接使用

cAdvisor(Container Advisor)可以直接查看容器资源使用:

# 运行 cAdvisor
docker run -d \
--name=cadvisor \
-p 8080:8080 \
-v /:/rootfs:ro \
-v /var/run:/var/run:ro \
-v /sys:/sys:ro \
-v /var/lib/docker/:/var/lib/docker:ro \
gcr.io/cadvisor/cadvisor:latest

# 访问 Web UI
# http://localhost:8080

故障排除

容器启动失败

检查容器状态

# 查看所有容器(包括已停止的)
docker ps -a

# 查看容器退出原因
docker inspect --format='{{.State.ExitCode}}' nginx
docker inspect --format='{{.State.Error}}' nginx
docker inspect --format='{{.State.OOMKilled}}' nginx

# 查看容器日志
docker logs nginx

常见退出码

退出码说明
0正常退出
1应用错误
137被 SIGKILL 杀死(可能是 OOM)
139段错误(Segmentation Fault)
143被 SIGTERM 终止

进入容器调试

# 执行单个命令
docker exec nginx ls /app

# 进入交互终端
docker exec -it nginx bash

# 使用 sh(如果没有 bash)
docker exec -it nginx sh

# 以 root 用户进入
docker exec -it -u root nginx bash

# 指定工作目录
docker exec -it -w /app nginx bash

# 传递环境变量
docker exec -it -e DEBUG=true nginx bash

网络调试

# 查看容器网络配置
docker network inspect bridge

# 查看容器端口映射
docker port nginx

# 进入容器测试网络
docker exec -it nginx sh
# 在容器内执行
ping db
curl http://api:3000/health
nslookup db

# 使用专用网络调试容器
docker run --rm -it --network container:nginx nicolaka/netshoot
# 在调试容器中可以使用各种网络工具
dig db
curl -v http://localhost:80
tcpdump -i eth0

存储调试

# 查看容器挂载
docker inspect --format='{{json .Mounts}}' nginx | jq

# 查看数据卷
docker volume ls
docker volume inspect my-volume

# 查看容器磁盘使用
docker system df

# 查看容器文件系统变更
docker diff nginx

# 从容器复制文件出来
docker cp nginx:/app/logs ./logs

性能调试

# 实时监控资源
docker stats nginx

# 查看容器进程
docker top nginx

# 使用 perf 分析(需要特权)
docker run --rm -it --privileged --pid=container:nginx \
-v /lib/modules:/lib/modules \
nicolaka/netshoot perf top

# 使用 strace 跟踪系统调用
docker run --rm -it --privileged --pid=container:nginx \
nicolaka/netshoot strace -p 1

健康检查调试

# 查看健康检查状态
docker inspect --format='{{json .State.Health}}' nginx | jq

# 查看健康检查日志
docker inspect --format='{{range .State.Health.Log}}{{.Output}}{{end}}' nginx

# 手动执行健康检查命令
docker exec nginx curl -f http://localhost/health

实用调试工具

网络调试容器

# 创建包含各种网络工具的容器
docker run --rm -it --network my-network nicolaka/netshoot

# 常用命令
dig db # DNS 查询
curl -v http://api:3000 # HTTP 请求
nc -zv db 3306 # 端口测试
tcpdump -i eth0 # 抓包
ss -tuln # 查看端口
ip addr # 网络接口

存储调试容器

# 挂载数据卷进行调试
docker run --rm -it -v my-volume:/data alpine sh
# 在容器中查看数据
ls -la /data
cat /data/config.yml

容器资源限制调试

# 检查容器资源限制
docker inspect --format='Memory: {{.HostConfig.Memory}}, CPU: {{.HostConfig.NanoCpus}}' nginx

# 测试内存限制
docker run --rm -it --memory="100m" progrium/stress --vm 1 --vm-bytes 150M

# 测试 CPU 限制
docker run --rm -it --cpus="0.5" progrium/stress --cpu 4

监控告警

Prometheus 告警规则

# alert.rules.yml
groups:
- name: docker_alerts
rules:
- alert: ContainerDown
expr: absent(container_last_seen{name=~".+"})
for: 5m
labels:
severity: critical
annotations:
summary: "Container {{ $labels.name }} is down"

- alert: HighMemoryUsage
expr: container_memory_usage_bytes{name!=""} / container_spec_memory_limit_bytes{name!=""} * 100 > 90
for: 5m
labels:
severity: warning
annotations:
summary: "Container {{ $labels.name }} memory usage > 90%"

- alert: HighCPUUsage
expr: rate(container_cpu_usage_seconds_total{name!=""}[5m]) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "Container {{ $labels.name }} CPU usage > 80%"

Alertmanager 配置

# alertmanager.yml
global:
smtp_smarthost: 'smtp.example.com:587'
smtp_from: '[email protected]'
smtp_auth_username: '[email protected]'
smtp_auth_password: 'password'

route:
receiver: 'team-email'
group_wait: 30s
group_interval: 5m
repeat_interval: 1h

receivers:
- name: 'team-email'
email_configs:
- to: '[email protected]'

可视化面板

Grafana Dashboard

推荐导入以下 Dashboard:

Dashboard ID说明
179Docker Host and Container Monitoring
11600Docker Container
893Docker and system monitoring
11467Docker Swarm monitoring

自定义 Grafana 面板

容器 CPU 使用率面板

# Query
sum(rate(container_cpu_usage_seconds_total{name=~"$container"}[5m])) by (name) * 100

# Legend
{{ name }}

容器内存使用面板

# Query
container_memory_usage_bytes{name=~"$container"}

# Legend
{{ name }}

故障排除清单

容器无法启动

# 1. 检查日志
docker logs <container>

# 2. 检查状态
docker inspect <container>

# 3. 检查镜像
docker images
docker history <image>

# 4. 尝试交互运行
docker run -it --entrypoint sh <image>

# 5. 检查资源限制
docker stats --no-stream

容器性能问题

# 1. 查看资源使用
docker stats <container>

# 2. 检查进程
docker top <container>

# 3. 检查日志
docker logs --tail 1000 <container>

# 4. 进入容器检查
docker exec -it <container> sh

# 5. 使用性能工具
docker run --rm -it --pid=container:<container> nicolaka/netshoot top

网络连接问题

# 1. 检查网络配置
docker network inspect <network>

# 2. 检查容器 IP
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container>

# 3. 测试连通性
docker exec <container> ping <target>

# 4. 检查端口
docker port <container>
docker exec <container> ss -tuln

# 5. 检查 DNS
docker exec <container> nslookup <hostname>

小结

本章我们学习了:

  1. 内置监控命令:docker stats、docker top、docker events
  2. 日志管理:日志驱动、日志聚合方案
  3. Prometheus 监控:部署、指标、告警
  4. 故障排除:启动失败、网络问题、存储问题
  5. 调试工具:网络调试、性能调试
  6. 可视化面板:Grafana Dashboard 配置

练习

  1. 使用 docker stats 监控容器资源使用
  2. 配置日志驱动限制日志大小
  3. 部署 Prometheus + Grafana 监控栈
  4. 创建 Grafana 面板展示容器 CPU 和内存使用率
  5. 配置 Prometheus 告警规则,当容器内存使用超过 90% 时告警