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

wen 实用脚本 1

本文目录导读:

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

  1. 基础监控脚本框架
  2. 高级功能脚本扩展
  3. 部署与使用
  4. 告警优化配置
  5. 完整示例(生产级)
  6. 运维建议

配置容器监控告警的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告警
生产环境 每分钟检查,多渠道告警+自动恢复

最佳实践:

  1. 使用set -euo pipefail增强脚本健壮性
  2. 实现告警抑制避免风暴
  3. 集成健康检查前置验证
  4. 配置日志轮转防止日志爆炸
  5. 生产环境建议配合Prometheus+Grafana使用

这个方案涵盖了从基础监控到生产级告警的完整流程,可根据实际需求灵活调整阈值和通知方式。

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