Docker 监控与调试
有效的监控和调试是保障容器化应用稳定运行的关键。本章将介绍 Docker 的监控工具、日志管理和故障排除技术。
监控概述
为什么需要监控?
容器化环境的监控与传统应用有所不同:
| 监控维度 | 传统应用 | 容器化应用 |
|---|---|---|
| 资源粒度 | 虚拟机/物理机 | 容器级别 |
| 生命周期 | 长期运行 | 动态创建销毁 |
| 网络模型 | 固定 IP | 动态网络 |
| 日志收集 | 文件系统 | 标准输出 |
监控指标层次
监控可以分为三个层次:
- 应用指标:请求量、响应时间、错误率、业务指标
- 容器指标:CPU、内存、网络、磁盘 IO
- 主机指标:节点资源、内核状态、存储容量
容器监控的核心是了解每个容器的资源使用情况,以便及时发现性能瓶颈和异常行为。
内置监控命令
docker stats - 容器资源统计
docker stats 是最常用的资源监控命令,可以实时查看容器的资源使用情况:
# 实时查看所有容器资源使用
docker stats
# 查看特定容器
docker stats nginx redis
# 不实时刷新(只显示一次)
docker stats --no-stream
# 自定义输出格式
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# JSON 格式输出(便于程序处理)
docker stats --format json --no-stream
输出示例:
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
b2c3d4e5f6g7 redis 0.25% 5MiB / 1GiB 0.50% 500B / 0B 0B / 0B 4
指标说明:
| 指标 | 说明 |
|---|---|
| CPU % | CPU 使用百分比 |
| MEM USAGE / LIMIT | 内存使用量 / 限制 |
| MEM % | 内存使用百分比 |
| NET I/O | 网络接收/发送字节 |
| BLOCK I/O | 磁盘读写字节 |
| PIDS | 进程数 |
docker top - 查看容器进程
# 查看容器内进程
docker top nginx
# 显示完整命令
docker top nginx aux
# 显示特定信息
docker top nginx -o pid,comm
输出示例:
UID PID PPID C STIME TTY TIME CMD
root 1234 567 0 10:00 ? 00:00:01 nginx: master process
101 1235 1234 0 10:00 ? 00:00:00 nginx: worker process
docker events - 监听 Docker 事件
# 实时监听 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 - 查看容器详情
# 查看完整配置
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)
控制组 (cgroups) 指标
Docker 使用 Linux 控制组 (cgroups) 来跟踪和限制容器的资源使用。你可以直接从 cgroups 文件系统获取详细的指标。
查找容器的 cgroup 路径
根据 cgroup 版本和驱动,路径有所不同:
cgroup v1:
- cgroupfs 驱动:
/sys/fs/cgroup/memory/docker/<container_id>/ - systemd 驱动:
/sys/fs/cgroup/memory/system.slice/docker-<container_id>.scope/
cgroup v2:
- cgroupfs 驱动:
/sys/fs/cgroup/docker/<container_id>/ - systemd 驱动:
/sys/fs/cgroup/system.slice/docker-<container_id>.scope/
内存指标
内存指标位于 memory.stat 文件中:
# 查看内存统计
cat /sys/fs/cgroup/memory/docker/<container_id>/memory.stat
关键指标说明:
| 指标 | 说明 |
|---|---|
cache | 页缓存大小 |
rss | 驻留内存集(不含缓存) |
mapped_file | 映射文件大小 |
swap | 交换空间使用量 |
pgfault | 页错误次数 |
pgmajfault | 主要页错误次数 |
active_anon | 活跃匿名内存 |
inactive_anon | 非活跃匿名内存 |
CPU 指标
CPU 指标位于 cpuacct.stat 文件中:
# 查看 CPU 统计
cat /sys/fs/cgroup/cpuacct/docker/<container_id>/cpuacct.stat
输出示例:
user 1234
system 567
- user:用户态 CPU 时间(1/100 秒为单位)
- system:内核态 CPU 时间
网络指标
网络指标需要从网络命名空间获取:
# 获取容器 PID
PID=$(docker inspect --format '{{.State.Pid}}' nginx)
# 查看网络接口统计
cat /proc/$PID/net/dev
日志管理
查看容器日志
# 查看日志
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 journal | systemd 系统 |
syslog | 发送到 syslog 守护进程 | 集中式日志 |
fluentd | 发送到 Fluentd | 日志聚合 |
awslogs | 发送到 AWS CloudWatch | AWS 环境 |
none | 禁用日志 | 安全敏感场景 |
配置日志驱动
运行时指定日志驱动:
# 使用 local 驱动(推荐)
docker run -d --log-driver=local 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": "local",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
重启 Docker 使配置生效:
sudo systemctl restart docker
Docker Compose 配置:
services:
app:
image: myapp
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
日志传递模式
Docker 提供两种日志传递模式:
- blocking(默认):直接阻塞式传递,可能影响应用性能
- non-blocking:使用中间缓冲区,避免阻塞
# 使用非阻塞模式
docker run -d \
--log-opt mode=non-blocking \
--log-opt max-buffer-size=4m \
nginx
日志聚合方案
使用 ELK Stack:
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 监控栈
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 主要指标
cAdvisor 提供的容器监控指标:
| 指标 | 说明 |
|---|---|
container_cpu_usage_seconds_total | CPU 使用时间 |
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)
# 内存使用率最高的 5 个容器
topk(5, container_memory_usage_bytes{name!=""})
# 容器数量
count(container_last_seen)
故障排除
容器启动失败
检查容器状态:
# 查看所有容器(包括已停止的)
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
# 使用专用网络调试容器
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
实用调试工具
网络调试容器
nicolaka/netshoot 是一个包含丰富网络工具的调试镜像:
# 创建包含各种网络工具的容器
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 ID | 说明 |
|---|---|
| 179 | Docker Host and Container Monitoring |
| 11600 | Docker Container |
| 893 | Docker and system monitoring |
| 11467 | Docker Swarm monitoring |
自定义面板示例
容器 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>
Docker Scout 镜像扫描
Docker Scout 是 Docker 官方提供的镜像安全分析工具,可以检测镜像中的漏洞并提供修复建议。它集成在 Docker CLI 中,使用方便。
快速扫描
快速扫描提供镜像安全状态的概览:
# 扫描本地镜像
docker scout quickview myapp:latest
# 扫描远程镜像
docker scout quickview nginx:latest
# 输出示例
# Target: nginx:latest
# Base image: nginx:1.25.3
# Updated base image: nginx:1.27.0
# Vulnerabilities: 12 critical, 45 high, 100 medium
CVE 详细报告
查看镜像中的具体漏洞详情:
# 查看所有 CVE
docker scout cves nginx:latest
# 只显示严重和高危漏洞
docker scout cves --only-severe nginx:latest
# 输出为 SARIF 格式(用于 CI/CD 集成)
docker scout cves --format sarif --output results.sarif nginx:latest
修复建议
获取更新镜像的建议:
# 查看修复建议
docker scout recommendations myapp:latest
# 查看基础镜像更新
docker scout recommendations --output-format markdown myapp:latest
输出内容包括更新的基础镜像版本、修复漏洞需要的版本、依赖包更新建议。
镜像比较
比较两个镜像的安全状态:
# 比较两个版本
docker scout compare myapp:v1 myapp:v2
# 比较不同基础镜像
docker scout compare --to nginx:alpine nginx:debian
持续监控
监控镜像更新和漏洞变化:
# 实时监控模式
docker scout watch myapp:latest
Docker Debug 调试工具
Docker Debug 是一个强大的调试工具,可以在不修改镜像的情况下进入任何容器或镜像进行调试。它特别适合调试精简镜像(如 distroless 或 scratch 基础镜像),这些镜像通常没有 shell 或调试工具。
基本用法
# 调试运行中的容器
docker debug my-container
# 调试镜像(即使没有 shell)
docker debug nginx:alpine
# 调试已停止的容器
docker debug stopped-container
安装额外工具
Docker Debug 自带常用工具(vim、curl、htop 等),也可以安装额外工具:
# 进入调试模式
docker debug my-container
# 安装 nmap 工具
install nmap
# 工具会保留在工具箱中,下次调试其他容器也可用
查看 Entrypoint
使用内置的 entrypoint 命令查看容器的入口点配置:
docker debug nginx:latest
entrypoint --print
# 输出:/docker-entrypoint.sh nginx -g "daemon off;"
# 测试运行入口点
entrypoint --run
非交互模式
直接执行命令而不进入交互模式:
# 执行单条命令
docker debug -c "cat /etc/nginx/nginx.conf" nginx:latest
# 指定 shell
docker debug --shell zsh my-container
CI/CD 集成示例
GitHub Actions 安全扫描:
name: Security Scan
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Docker Scout
run: |
docker scout quickview myapp:${{ github.sha }}
docker scout cves --only-severe --format sarif --output results.sarif myapp:${{ github.sha }}
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: results.sarif
小结
Docker 监控与调试的核心内容:
- 内置监控命令:
docker stats实时资源统计、docker top进程查看、docker events事件监听 - cgroups 指标:从
/sys/fs/cgroup文件系统获取详细的资源使用数据 - 日志管理:多种日志驱动配置、日志聚合方案(ELK、Loki)
- Prometheus 监控:cAdvisor 收集指标、Prometheus 存储、Grafana 可视化
- 镜像扫描:Docker Scout 检测漏洞、查看 CVE、获取修复建议
- 故障排除:容器启动失败、网络问题、存储问题、性能瓶颈排查
- 调试工具:Docker Debug 进入容器调试、
nicolaka/netshoot网络调试 - 告警配置:Prometheus 告警规则、Alertmanager 通知
练习
- 使用 docker stats 监控容器资源使用
- 配置日志驱动限制日志大小
- 部署 Prometheus + Grafana 监控栈
- 创建 Grafana 面板展示容器 CPU 和内存使用率
- 配置 Prometheus 告警规则,当容器内存使用超过 90% 时告警