本文目录导读:

配置容器监控告警的Shell脚本通常涉及资源指标采集、阈值判断和告警通知三个核心步骤,以下是一个系统化的配置方案,包含完整脚本示例。
基础监控脚本框架
#!/bin/bash
# 容器监控告警脚本
# 适用场景:Docker容器资源监控
# ====== 配置区域 ======
CONTAINER_NAME="${1:-}" # 可指定容器名,不指定则监控所有
CPU_THRESHOLD=80 # CPU使用率阈值(%)
MEM_THRESHOLD=80 # 内存使用率阈值(%)
DISK_THRESHOLD=80 # 磁盘使用率阈值(%)
RESTART_THRESHOLD=3 # 重启次数阈值
# 告警通知配置
NOTIFY_EMAIL="admin@example.com"
NOTIFY_SLACK_WEBHOOK="https://hooks.slack.com/services/xxx"
# ====== 核心监控函数 ======
# 获取容器监控数据
get_container_stats() {
docker stats --no-stream --format \
"{{.Name}}\t{{.CPUPerc}}\t{{.MemPerc}}\t{{.PIDs}}" 2>/dev/null
}
# 检查容器运行状态
check_container_status() {
docker ps -a --filter "name=${CONTAINER_NAME}" --format "{{.Names}}\t{{.Status}}"
}
# 检查容器重启次数
check_restart_count() {
docker inspect -f '{{.RestartCount}}' "$1" 2>/dev/null
}
# 发送告警通知(支持多种通知方式)
send_alert() {
local subject="$1"
local message="$2"
# 方式1: 邮件告警
echo "$message" | mail -s "$subject" "$NOTIFY_EMAIL"
# 方式2: Slack告警
if [[ -n "$NOTIFY_SLACK_WEBHOOK" ]]; then
curl -s -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"🚨 *${subject}*\n${message}\"}" \
"$NOTIFY_SLACK_WEBHOOK" &>/dev/null
fi
# 方式3: 日志记录
logger "Container Alert: $subject - $message"
}
# 执行监控检查
perform_monitoring() {
local alert_triggered=false
# 步骤1: 检查容器运行状态
if [[ -z "$CONTAINER_NAME" ]]; then
# 监控所有容器
containers=$(docker ps -q)
else
containers=$(docker ps -q -f "name=${CONTAINER_NAME}")
fi
for container_id in $containers; do
local container_name=$(docker inspect -f '{{.Name}}' "$container_id" | sed 's/\///')
local stats_info=$(docker stats --no-stream --format \
"{{.CPUPerc}}\t{{.MemPerc}}" "$container_id" 2>/dev/null)
# 解析CPU和内存使用率
local cpu_usage=$(echo "$stats_info" | awk '{print $1}' | sed 's/%//')
local mem_usage=$(echo "$stats_info" | awk '{print $2}' | sed 's/%//')
# 检查CPU阈值
if (( $(echo "$cpu_usage > $CPU_THRESHOLD" | bc -l) )); then
send_alert "容器CPU超限" "容器: $container_name\nCPU使用率: $cpu_usage%\n阈值: $CPU_THRESHOLD%"
alert_triggered=true
fi
# 检查内存阈值
if (( $(echo "$mem_usage > $MEM_THRESHOLD" | bc -l) )); then
send_alert "容器内存超限" "容器: $container_name\n内存使用率: $mem_usage%\n阈值: $MEM_THRESHOLD%"
alert_triggered=true
fi
# 检查重启次数
local restart_count=$(check_restart_count "$container_name")
if [[ $restart_count -gt $RESTART_THRESHOLD ]]; then
send_alert "容器频繁重启" "容器: $container_name\n重启次数: $restart_count\n阈值: $RESTART_THRESHOLD"
alert_triggered=true
fi
done
# 步骤2: 记录健康状态
if [[ "$alert_triggered" = false ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 所有容器运行正常" >> /var/log/container_monitor.log
fi
}
# ====== 主执行逻辑 ======
perform_monitoring
高级功能脚本扩展
1 磁盘监控增强版
#!/bin/bash
# 容器磁盘使用监控
monitor_disk_usage() {
local alert_disk=false
docker system df --format "{{.Type}}\t{{.Size}}\t{{.Reclaimable}}" | while read line; do
type=$(echo $line | awk '{print $1}')
usage=$(echo $line | awk '{print $2}' | sed 's/[A-Za-z]//g')
# 检查磁盘使用率
if [[ "$type" == "Images" || "$type" == "Containers" ]]; then
if (( $(echo "$usage > $DISK_THRESHOLD" | bc -l) )); then
alert_disk=true
send_alert "容器磁盘空间不足" "类型: $type\n使用量: $usage\n阈值: $DISK_THRESHOLD%"
fi
fi
done
}
2 网络流量监控
# 网络IO监控
monitor_network() {
local network_threshold=1000 # MB/s
docker stats --no-stream --format \
"{{.Name}}\t{{.NetIO}}" | while read container netio; do
# 解析网络IO (格式: 1.2kB / 3.4MB)
rx_bytes=$(echo "$netio" | awk '{print $1}' | sed 's/[A-Za-z]//g')
tx_bytes=$(echo "$netio" | awk '{print $3}' | sed 's/[A-Za-z]//g')
if (( $(echo "$rx_bytes > $network_threshold" | bc -l) )); then
send_alert "容器网络异常" "容器: $container\n接收流量: $netio"
fi
done
}
部署与使用
1 安装依赖
# 确保安装bc(用于浮点数计算) apt-get install bc mailutils curl -y # Debian/Ubuntu yum install bc mailx curl -y # CentOS/RHEL
2 定时任务配置
# 添加到crontab(每分钟检查一次) * * * * * /usr/local/bin/container_monitor.sh >> /var/log/container_monitor.log 2>&1 # 复杂调度场景(工作时间内每分钟检查,其他时间每5分钟) */1 9-18 * * 1-5 /usr/local/bin/container_monitor.sh */5 * * * * /usr/local/bin/container_monitor.sh
3 Prometheus+Alertmanager集成
#!/bin/bash
# 生成Prometheus指标格式输出
prometheus_metrics() {
while true; do
docker stats --no-stream --format \
"container_cpu_usage{name=\"{{.Name}}\"} {{.CPUPerc}}\ncontainer_mem_usage{name=\"{{.Name}}\"} {{.MemPerc}}" \
| sed 's/%//g' > /tmp/container_metrics.prom
sleep 10
done
}
# Alertmanager自定义告警配置
# 安装node_exporter和textfile收集器
# 在/etc/prometheus/alert.rules.yml添加:
# groups:
# - name: container_alerts
# rules:
# - alert: ContainerHighCPU
# expr: container_cpu_usage > 80
# for: 5m
# labels:
# severity: warning
# annotations:
# summary: "Container CPU high"
告警优化配置
1 智能告警降噪
# 告警抑制:避免重复告警
declare -A alert_history
check_alert_suppression() {
local container="$1"
local alert_type="$2"
local current_time=$(date +%s)
local suppress_window=300 # 5分钟内不重复告警
if [[ -n "${alert_history[$container_$alert_type]}" ]]; then
local last_alert=${alert_history[$container_$alert_type]}
if (( current_time - last_alert < suppress_window )); then
return 1 # 抑制告警
fi
fi
alert_history["$container_$alert_type"]=$current_time
return 0 # 允许告警
}
2 健康检查前置
# 监控前先做健康检查
pre_healthcheck() {
# 检查Docker daemon状态
if ! docker info &>/dev/null; then
send_alert "Docker守护进程异常" "Docker daemon无法连接"
exit 1
fi
# 检查容器健康状态
docker ps --filter "health=unhealthy" --format "{{.Names}}" | while read container; do
send_alert "容器健康检查失败" "容器: $container"
done
}
完整示例(生产级)
#!/bin/bash
# 生产环境容器监控告警脚本
set -euo pipefail
# 配置文件
CONFIG_FILE="/etc/container_monitor.conf"
LOG_FILE="/var/log/container_monitor.log"
# 加载配置
if [[ -f "$CONFIG_FILE" ]]; then
source "$CONFIG_FILE"
else
# 默认配置
CPU_THRESHOLD=85
MEM_THRESHOLD=80
DISK_THRESHOLD=85
RESTART_THRESHOLD=3
SLACK_WEBHOOK=""
EMAIL_RECIPIENT=""
fi
# 告警通知函数
send_notification() {
local severity="${1:-WARNING}"
local subject="$2"
local message="$3"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# 日志记录
echo "[$timestamp] [$severity] $subject: $message" >> "$LOG_FILE"
# 邮件通知
if [[ -n "$EMAIL_RECIPIENT" ]]; then
echo "$message" | mail -s "[$severity] $subject" "$EMAIL_RECIPIENT"
fi
# Slack通知
if [[ -n "$SLACK_WEBHOOK" ]]; then
color="#FF0000"
[[ "$severity" == "WARNING" ]] && color="#FFA500"
curl -s -X POST -H 'Content-type: application/json' \
--data "{\"attachments\":[{\"color\":\"$color\",\"title\":\"$subject\",\"text\":\"$message\",\"footer\":\"Container Monitor\"}]}" \
"$SLACK_WEBHOOK" &>/dev/null || true
fi
}
# 主监控逻辑
monitor_containers() {
# 获取所有运行中的容器
containers=$(docker ps --format "{{.Names}}")
for container in $containers; do
# 获取容器统计信息
stats=$(docker stats --no-stream --format \
"{{.CPUPerc}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}" "$container" 2>/dev/null)
if [[ -z "$stats" ]]; then
send_notification "ERROR" "容器统计失败" "无法获取容器 $container 的统计信息"
continue
fi
# 解析指标
cpu=$(echo "$stats" | awk '{print $1}' | sed 's/%//')
mem=$(echo "$stats" | awk '{print $2}' | sed 's/%//')
# CPU告警
if (( $(echo "$cpu > $CPU_THRESHOLD" | bc -l) )); then
send_notification "CRITICAL" "容器CPU过载" \
"容器: $container\nCPU使用率: $cpu%\n阈值: $CPU_THRESHOLD%"
fi
# 内存告警
if (( $(echo "$mem > $MEM_THRESHOLD" | bc -l) )); then
send_notification "CRITICAL" "容器内存过载" \
"容器: $container\n内存使用率: $mem%\n阈值: $MEM_THRESHOLD%"
fi
# 检查重启次数
restart_count=$(docker inspect -f '{{.RestartCount}}' "$container" 2>/dev/null)
if [[ "$restart_count" -gt "$RESTART_THRESHOLD" ]]; then
send_notification "WARNING" "容器频繁重启" \
"容器: $container\n重启次数: $restart_count\n阈值: $RESTART_THRESHOLD"
fi
# 检查容器健康状态
health=$(docker inspect -f '{{.State.Health.Status}}' "$container" 2>/dev/null)
if [[ "$health" == "unhealthy" ]]; then
send_notification "CRITICAL" "容器健康检查失败" \
"容器: $container\n健康状态: $health"
fi
done
# 全局系统资源检查
check_system_resources
}
# 系统资源检查
check_system_resources() {
# Docker磁盘使用
disk_usage=$(docker system df --format "{{.Type}}\t{{.Size}}" | grep "Images" | awk '{print $2}')
# 检查磁盘使用率
if [[ -n "$disk_usage" ]]; then
usage_num=$(echo "$disk_usage" | sed 's/[A-Za-z]//g')
if (( $(echo "$usage_num > $DISK_THRESHOLD" | bc -l) )); then
send_notification "WARNING" "Docker磁盘空间不足" \
"当前使用: $disk_usage\n阈值: $DISK_THRESHOLD%"
fi
fi
}
# 主执行
main() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始容器监控..." >> "$LOG_FILE"
monitor_containers
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 监控完成" >> "$LOG_FILE"
}
main "$@"
运维建议
| 场景 | 配置建议 |
|---|---|
| 开发环境 | 每5分钟检查一次,仅发送邮件告警 |
| 测试环境 | 每2分钟检查,邮件+Slack告警 |
| 生产环境 | 每分钟检查,多渠道告警+自动恢复 |
最佳实践:
- 使用
set -euo pipefail增强脚本健壮性 - 实现告警抑制避免风暴
- 集成健康检查前置验证
- 配置日志轮转防止日志爆炸
- 生产环境建议配合Prometheus+Grafana使用
这个方案涵盖了从基础监控到生产级告警的完整流程,可根据实际需求灵活调整阈值和通知方式。