Shell脚本如何配置容器监控告警

wen 实用脚本 1

Shell脚本如何配置容器监控告警:从零搭建自动化运维体系

目录导读

  1. 为什么需要Shell脚本实现容器监控告警?
  2. 监控告警的核心组件与工作原理
  3. 准备工作:环境依赖与工具选型
  4. 实战:编写监控CPU、内存、磁盘的Shell脚本
  5. 告警触发:集成邮件、钉钉与Slack通知
  6. 自动化部署:将脚本融入Crontab与Docker
  7. 常见问题FAQ
  8. 总结与最佳实践

为什么需要Shell脚本实现容器监控告警?

在微服务与容器化部署盛行的今天,Docker容器如同“轻量级虚拟机”般快速启动与销毁,当容器数量激增(例如Kubernetes集群中上百个Pod),手动检查每个容器的资源使用率变得不切实际。Shell脚本以其轻量、无依赖、跨平台的优势,成为快速搭建监控告警的首选工具,相比Prometheus+Grafana等重型监控方案,Shell脚本仅需几行代码即可实现核心告警逻辑,尤其适合中小规模团队或边缘计算场景。

Shell脚本如何配置容器监控告警

问:为什么不直接用现成的监控工具?
答:现有工具(如Prometheus)学习曲线陡峭,且需额外部署存储与告警组件,Shell脚本可零成本植入现有运维脚本,对现有架构侵入性最小。


监控告警的核心组件与工作原理

一个完整的容器监控告警系统需包含以下要素:

  • 数据采集:通过docker statsdocker inspect或读取/sys/fs/cgroup获取容器CPU、内存、网络I/O等指标。
  • 阈值判断:将采集数据与预设阈值(如CPU>80%、内存>90%)进行比较。
  • 告警分发:触发告警时,通过邮件、HTTP请求(钉钉机器人)、Slack Webhook等渠道通知运维人员。
  • 日志记录:将历史监控数据保存至文件或数据库,便于事后分析。

核心原理:利用docker stats --no-stream命令获取容器实时快照,通过awksed等文本处理工具提取关键数值,再结合简单的条件判断实现告警。


准备工作:环境依赖与工具选型

环境要求

  • 宿主机已安装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通知

邮件告警配置(需宿主机安装mailssmtp):

# 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

钉钉群机器人(推荐):

  1. 在钉钉群中添加“自定义机器人”
  2. 获取Webhook URL(格式:https://oapi.dingtalk.com/robot/send?access_token=XXX
  3. 脚本中使用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

  1. 在Slack App中创建Incoming Webhook
  2. 使用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容器化定时执行

进阶建议

  1. 增加指标维度:结合/sys/fs/cgroup获取更精确的CPU配额(如cpu.cfs_period_us
  2. 可视化:将日志输出到/var/log/配合ELK或Loki进行可视化分析
  3. 多机器扩展:通过SSH远程执行脚本,或结合Ansible批量部署
  4. 故障自愈:在告警后触发docker restart nginx_container等自动恢复命令

警告:生产环境建议将阈值参数、告警渠道通过环境变量注入,避免硬编码,同时需监控脚本自身运行状态,防止脚本挂掉导致告警失灵。

请记得定期审查日志,优化阈值,Shell脚本虽小,却能在容器化运维中发挥“螺丝刀”般的精准效用。

抱歉,评论功能暂时关闭!