Shell脚本如何配置容器监控告警:从零搭建自动化运维体系
目录导读
- 为什么需要Shell脚本实现容器监控告警?
- 监控告警的核心组件与工作原理
- 准备工作:环境依赖与工具选型
- 实战:编写监控CPU、内存、磁盘的Shell脚本
- 告警触发:集成邮件、钉钉与Slack通知
- 自动化部署:将脚本融入Crontab与Docker
- 常见问题FAQ
- 总结与最佳实践
为什么需要Shell脚本实现容器监控告警?
在微服务与容器化部署盛行的今天,Docker容器如同“轻量级虚拟机”般快速启动与销毁,当容器数量激增(例如Kubernetes集群中上百个Pod),手动检查每个容器的资源使用率变得不切实际。Shell脚本以其轻量、无依赖、跨平台的优势,成为快速搭建监控告警的首选工具,相比Prometheus+Grafana等重型监控方案,Shell脚本仅需几行代码即可实现核心告警逻辑,尤其适合中小规模团队或边缘计算场景。

问:为什么不直接用现成的监控工具?
答:现有工具(如Prometheus)学习曲线陡峭,且需额外部署存储与告警组件,Shell脚本可零成本植入现有运维脚本,对现有架构侵入性最小。
监控告警的核心组件与工作原理
一个完整的容器监控告警系统需包含以下要素:
- 数据采集:通过
docker stats、docker inspect或读取/sys/fs/cgroup获取容器CPU、内存、网络I/O等指标。 - 阈值判断:将采集数据与预设阈值(如CPU>80%、内存>90%)进行比较。
- 告警分发:触发告警时,通过邮件、HTTP请求(钉钉机器人)、Slack Webhook等渠道通知运维人员。
- 日志记录:将历史监控数据保存至文件或数据库,便于事后分析。
核心原理:利用docker stats --no-stream命令获取容器实时快照,通过awk、sed等文本处理工具提取关键数值,再结合简单的条件判断实现告警。
准备工作:环境依赖与工具选型
环境要求:
- 宿主机已安装Docker(版本≥19.03)
- Shell解释器:Bash(推荐4.0+)
- 可选工具:
jq(JSON解析)、curl(发送HTTP请求)、mail(邮件发送)
安装依赖(以Ubuntu/CentOS为例):
# Ubuntu apt-get update && apt-get install -y jq curl mailutils # CentOS yum install -y jq curl mailx
关键命令验证:
docker stats --no-stream --format "{{.Name}} {{.CPUPerc}} {{.MemPerc}}" | head -5
输出示例:my_container 12.45% 34.56%
实战:编写监控CPU、内存、磁盘的Shell脚本
以下是一个完整的监控脚本(container_monitor.sh),涵盖CPU、内存、磁盘及容器状态检测:
#!/bin/bash
# ========== 配置参数 ==========
THRESHOLD_CPU=80 # CPU百分比阈值
THRESHOLD_MEM=90 # 内存百分比阈值
THRESHOLD_DISK=85 # 磁盘使用率阈值
ALERT_INTERVAL=300 # 告警间隔(秒),避免重复通知
LOG_FILE="/var/log/container_monitor.log"
# ========== 告警函数 ==========
send_alert() {
local message="$1"
local subject="[ALERT] 容器监控告警"
# 示例:发送邮件(需配置mailutils)
echo "$message" | mail -s "$subject" admin@example.com
# 示例:发送钉钉机器人(替换WEBHOOK_URL)
# curl -s -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \
# -H "Content-Type: application/json" \
# -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}"
}
# ========== 采集并检查CPU/内存 ==========
check_container_resources() {
docker stats --no-stream --format "{{.Name}}|{{.CPUPerc}}|{{.MemPerc}}" | while IFS='|' read -r name cpu mem; do
# 去除百分号并转换为数值
cpu_val=${cpu%\%}
mem_val=${mem%\%}
# CPU告警
if (( $(echo "$cpu_val > $THRESHOLD_CPU" | bc -l) )); then
send_alert "容器 $name CPU使用率: $cpu%(阈值: ${THRESHOLD_CPU}%)"
echo "$(date) [WARN] $name CPU: $cpu%" >> $LOG_FILE
fi
# 内存告警
if (( $(echo "$mem_val > $THRESHOLD_MEM" | bc -l) )); then
send_alert "容器 $name 内存使用率: $mem%(阈值: ${THRESHOLD_MEM}%)"
echo "$(date) [WARN] $name MEM: $mem%" >> $LOG_FILE
fi
done
}
# ========== 检查容器磁盘(进入容器内检查) ==========
check_container_disk() {
docker ps -q | while read cid; do
# 使用docker exec执行df命令
disk_usage=$(docker exec "$cid" df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//')
if [ -n "$disk_usage" ] && [ "$disk_usage" -gt "$THRESHOLD_DISK" ]; then
container_name=$(docker inspect --format '{{.Name}}' "$cid" | cut -d'/' -f2)
send_alert "容器 $container_name 磁盘使用率: ${disk_usage}%(阈值: ${THRESHOLD_DISK}%)"
echo "$(date) [WARN] $container_name DISK: ${disk_usage}%" >> $LOG_FILE
fi
done
}
# ========== 检查容器运行状态 ==========
check_container_status() {
# 检测退出状态的容器
exited_containers=$(docker ps -a --filter "status=exited" --format "{{.Names}}")
if [ -n "$exited_containers" ]; then
send_alert "以下容器已退出: $exited_containers"
echo "$(date) [FAIL] 退出容器: $exited_containers" >> $LOG_FILE
fi
}
# ========== 主流程 ==========
main() {
echo "========== 监控开始 $(date) ==========" >> $LOG_FILE
check_container_resources
check_container_disk
check_container_status
}
main
脚本要点说明:
- 使用
docker stats --no-stream避免持续阻塞 bc -l支持浮点数比较(需安装bc工具)- 磁盘检查需容器内包含
df命令(如Alpine镜像需安装coreutils) - 告警函数仅发送一次,实际生产需加入
last_alert_time缓存避免刷屏
告警触发:集成邮件、钉钉与Slack通知
邮件告警配置(需宿主机安装mail或ssmtp):
# Ubuntu安装并配置ssmtp apt-get install ssmtp # 编辑 /etc/ssmtp/ssmtp.conf mailhub=smtp.gmail.com:587 AuthUser=your_email@gmail.com AuthPass=your_app_password UseSTARTTLS=YES
钉钉群机器人(推荐):
- 在钉钉群中添加“自定义机器人”
- 获取Webhook URL(格式:
https://oapi.dingtalk.com/robot/send?access_token=XXX) - 脚本中使用curl发送JSON:
curl -s -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}"
Slack Webhook:
- 在Slack App中创建Incoming Webhook
- 使用curl发送:
curl -s -X POST "https://hooks.slack.com/services/T000000/B000000/XXXXXXXX" \ -H "Content-Type: application/json" \ -d "{\"text\":\"$message\"}"
自动化部署:将脚本融入Crontab与Docker
添加定时任务(每5分钟执行一次):
crontab -e */5 * * * * /usr/local/bin/container_monitor.sh
将脚本封装为Docker镜像(适合容器化部署监控任务本身):
FROM alpine:latest RUN apk add --no-cache docker-cli bash bc curl COPY container_monitor.sh /monitor.sh RUN chmod +x /monitor.sh CMD ["bash", "/monitor.sh"]
注意:需挂载宿主机Docker socket:
docker run -d --name mon-agent \
-v /var/run/docker.sock:/var/run/docker.sock \
your_monitor_image
常见问题FAQ
Q1:脚本执行报错“docker: command not found”
A:确保宿主机已安装Docker,且当前用户属于docker组(或使用sudo执行)。
Q2:docker stats显示NaN表示什么?
A:通常表示容器刚启动或已停止,可加入grep -v NaN过滤,或检查容器状态。
Q3:邮件发送失败如何处理?
A:检查SMTP配置和网络连通性,使用mail -v开启调试模式,或改用钉钉/Slack替代。
Q4:如何自定义监控指标(如网络流量、进程数)?
A:使用docker inspect获取NetworkSettings字段,或进入容器执行ps aux统计进程数量。
Q5:告警太频繁如何优化?
A:实现“告警冷却期”,记录每个容器的上次告警时间,仅当超过ALERT_INTERVAL时才再次发送。
总结与最佳实践
Shell脚本配置容器监控告警的精髓在于“轻量、灵活、可定制”,通过本文的实战代码,你已能:
- 核心能力:采集CPU/内存/磁盘/容器状态
- 告警通道:邮件、钉钉、Slack三选一
- 自动化:Crontab或Docker容器化定时执行
进阶建议:
- 增加指标维度:结合
/sys/fs/cgroup获取更精确的CPU配额(如cpu.cfs_period_us) - 可视化:将日志输出到
/var/log/配合ELK或Loki进行可视化分析 - 多机器扩展:通过SSH远程执行脚本,或结合Ansible批量部署
- 故障自愈:在告警后触发
docker restart nginx_container等自动恢复命令
警告:生产环境建议将阈值参数、告警渠道通过环境变量注入,避免硬编码,同时需监控脚本自身运行状态,防止脚本挂掉导致告警失灵。
请记得定期审查日志,优化阈值,Shell脚本虽小,却能在容器化运维中发挥“螺丝刀”般的精准效用。