使用 `docker events` 过滤出 `oom` 事件并报警

解读

在国内生产环境中,容器因内存超限被 OOM Kill 是高频故障源,轻则服务瞬断,重则触发级联重启。面试官问“用 docker events 过滤 oom 并报警”,表面考一条命令,实则验证候选人是否具备实时告警闭环思维:

  1. 能否精准过滤 Docker 原生事件流;
  2. 能否低延迟将事件推送到企业微信/钉钉/飞书;
  3. 能否去重分级,避免告警风暴;
  4. 能否联动自动扩容或触发预案。
    答出“一条 grep”只能拿 30 分,给出“事件驱动+去重+分级+回调”的完整脚本才能拿到 90+。

知识点

  1. docker events 子命令

    • 默认输出 JSON,字段:Type、Action、Actor.ID、Actor.Attributes。
    • 时间范围:--since--until 支持 RFC3339 或相对时间如 10m
    • 过滤器:-f type=container -f event=oomDocker 20.10+ 才原生支持 oom 事件,老版本需回退到 die 事件并解析 exitCode=137。
  2. OOM 事件特征

    • Action=oom,Type=container,Actor.Attributes 含 nameimageoomKilled=true
    • die 事件成对出现,需按 container ID 去重,否则双告警。
  3. 告警通道

    • 内网:飞书群机器人、钉钉自定义机器人(加签/关键字)。
    • 外网:阿里云事件总线+函数计算、腾讯云 CLS+SCF。
    • 统一要求:3 秒内到达,支持 Markdown 富文本,可 @责任人。
  4. 去重与分级

    • 内存阀值 30s 内同一容器重复 OOM 只报一次。
    • 按服务等级分级:核心服务 P1 电话,非核心 P3 群内通知。
  5. 脚本健壮性

    • 使用 jq 解析 JSON,避免 grep 误匹配。
    • 采用 systemd 守护,崩溃自动拉起;日志走 journald,方便审计。

答案

给出一条可直接落地的 Bash 方案,满足CentOS 7/8、Ubuntu 20.04+、统信 UOS等国内主流镜像源,无需 root,普通 docker 用户即可运行。

#!/bin/bash
# file: /usr/local/bin/docker-oom-watchdog.sh
set -euo pipefail

WEBHOOK="https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx"
GRACE=30     # 去重窗口秒
CACHE="/tmp/docker-oom.cache"
touch "$CACHE"

docker events \
  --filter 'type=container' \
  --filter 'event=oom' \
  --format '{{json .}}' | \
while IFS= read -r line; do
  id=$(echo "$line" | jq -r .Actor.ID)
  name=$(echo "$line" | jq -r .Actor.Attributes.name)
  image=$(echo "$line" | jq -r .Actor.Attributes.image)
  now=$(date +%s)

  # 去重:同一容器 GRACE 秒内只报一次
  last=$(grep "^${id}:" "$CACHE" | cut -d: -f2 || echo 0)
  if (( now - last < GRACE )); then
    continue
  fi

  # 更新缓存
  echo "${id}:${now}" >> "$CACHE"
  # 只保留最近 1000 条,防止膨胀
  tail -n 1000 "$CACHE" > "${CACHE}.tmp" && mv "${CACHE}.tmp" "$CACHE"

  # 组装飞书 Markdown
  msg=$(cat <<EOF
**容器 OOM 告警**
- 容器:**${name}**
- 镜像:**${image}**
- ID:\`${id:0:12}\`
- 时间:$(date '+%F %T')
- 主机:$(hostname -f)
EOF
)

  curl -sX POST "$WEBHOOK" \
       -H 'Content-Type: application/json' \
       -d "$(jq -n --arg txt "$msg" '{msg_type:"post",content:{post:{zh_cn:{title:"容器OOM",content:[[{tag:"text",text:$txt}]]}}}}')" \
       > /dev/null
done

启动与守护

sudo tee /etc/systemd/system/docker-oom-watchdog.service > /dev/null <<'EOF'
[Unit]
Description=Docker OOM Watchdog
After=docker.service
Requires=docker.service

[Service]
Type=simple
ExecStart=/usr/local/bin/docker-oom-watchdog.sh
Restart=always
RestartSec=5s
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now docker-oom-watchdog

验证

# 制造 OOM
docker run --rm -m 50m alpine sh -c 'dd if=/dev/zero of=/dev/null bs=100M'
# 3 秒内飞书群收到 Markdown 卡片,@全体

拓展思考

  1. 集群级聚合
    在 Swarm 或 K8s 场景,单节点脚本不够,需把事件打到 Kafka,用 Flink 做 1 分钟窗口聚合,输出“服务维度 OOM 率”,再触发 HPA 扩容。

  2. 根因自动采集
    OOM 瞬间自动 docker exec 抓取 /proc/meminfotopjmap,压缩后上传到 MinIO,供研发事后复盘,减少 50% 排障时间

  3. 与 Prometheus 联动
    利用 docker_exporter 把 OOM 总数转成指标 docker_container_oom_total,在 Grafana 配置告警规则,实现图形化趋势+多维度切片(镜像版本、集群、业务线)。

  4. 安全加固
    若容器以 non-root 运行,需确保 docker events 对普通用户可见:

    sudo usermod -aG docker watchdog
    

    避免脚本因权限失败而静默丢告警

  5. 合规审计
    国内金融、政务云要求告警留痕 6 个月,可把事件同时写进 Elasticsearch,索引模板开启 ILM,冷热分层节省 70% 存储。