Skip to content

RadiumGu/aws-devops-agent-slack-bridge

AWS DevOps Agent ↔ Slack Bridge

🌐 Languages: 中文(当前)· English

Related: aws-devops-agent-cn-bridge — 让 Global 分区的 DevOps Agent 能访问 aws-cn 资源的跨分区桥接(CFN + IAM Roles Anywhere)。

它是什么

一个轻量级 bridge 层,把 AWS DevOps Agent(预览期)与 Slack 双向打通:

  • 告警 → 调查 → 推 Slack 的全自动 SRE 主线(CloudWatch Alarm → Lambda → DevOps Agent → Slack Block Kit 摘要)
  • Slack 内多轮对话@devops_agent <问题> 调起调查,同 thread 内复用同一 chat session,后续追问免 @

原生集成只能「完了推一下」是单向的,本仓补齐其余纬度(详见 §0.0 为什么要做这个 bridge)。

主要特性

  • 🔌 告警入口可控 — Lambda-A 把任意 namespace 的 CloudWatch alarm(EKS / RDS / Lambda / 自定义 metric / ContainerInsights…)结构化拼进 investigation description,不假设只是 EC2
  • 🔄 EventBridge 事件幂等 — 同一 alarm 不会被重复立案调查(DDB 原子 claim by alarmName + state.timestamp
  • 💬 Slack 主动调起 · thread 多轮 — Lambda-C 接 Slack Events API,fast-path 3s ack + Lambda 自异步调 worker;DDB 记录 thread_ts → chat_id 映射,同 thread 内免 @续问
  • 🛡️ Slack 签名验证 + 5min replay 防御 + event_id 幂等 — 双订阅(app_mention + message.channels)不会双发 prompt
  • 🌍 跨分区可扩展 — 事件管道全走 EventBridge + Lambda,可以叠加 cn-bridge 让 Global 区 Agent 调查 aws-cn 资源
  • 📦 一键脚本部署 — IAM / Lambda / EventBridge / API Gateway / DDB / DLQ / CloudWatch alarm 全脚本化,幂等可重复执行;Slack App 创建这一步手动一次在 docs/slack-setup.md
  • 🔁 可快速适配飞书 — chat 层抽象都在 Lambda-C 里(签名验证、Block Kit 渲染、@mention 剖析、chat.update 占位子),换成飞书只需重写 slack_verify.py、Block Kit → 飞书 card / interactive message、webhook URL 格式。Lambda-A/B/EventBridge 主线零修改。

Quick Start

git clone <repo-url> && cd aws-devops-agent-slack-bridge
cp .env.example .env
# edit .env with your account/region/Slack/Agent Space values
bash scripts/deploy.sh           # main alarm → investigation → Slack pipeline
bash scripts/deploy-chatbot.sh   # optional: Slack chatbot for interactive chat

最低需要填的 ·env·:AWS_ACCOUNT_ID / AWS_REGION / DEVOPS_AGENT_SPACE_ID / SLACK_WEBHOOK_URL / SLACK_TEST_CHANNEL。详见 §2.5 Configuration

状态: ✅ 已端到端验证通过(FIS 删 2 个 EKS node → DevOps Agent 自动调查 → Slack 推摘要 + thread 多轮对话)。

本仓里所有 <UPPERCASE_PLACEHOLDER> 都靠 .env 注入,文件不入库。


0.0 为什么要做这个 bridge

AWS DevOps Agent 自带原生 Slack 集成(官方文档),但只覆盖最基本的「调查完成 → 把结论推到一个 Slack 频道」这一种场景。落到生产 SRE 工作流里,原生集成有几个绕不过去的限制:

1. 只是单向通知,不支持 Slack 内对话 AWS 官方原文:「configure AWS DevOps Agent to update a Slack channel you select with incident response investigation key findings, root cause analyses, and generated mitigation plans」。换句话说,原生集成是 agent → Slack 的单向通道,没有 Slack 内 @mention 追问、同 thread 多轮上下文、按需发起调查这些能力。值班人员在 Slack 里看到摘要后想追问「为什么不是 X 原因」「再查一下 Y 资源」,必须切到 AWS Console 的 chat 界面,节奏被打断。

→ 本仓 Lambda-C + DynamoDB thread 表 解决:@devops_agent <问题> 在 Slack 直接调 send_message API,同 thread 内复用同一 chat_id,把 DevOps Agent 的对话能力暴露到 Slack 里。

2. 触发逻辑是黑盒,无法塞业务上下文 原生集成只能把 CloudWatch alarm(或 webhook)作为触发源,Agent Space 自己决定如何把 alarm 翻译成 investigation backlog task。当 alarm 来自非 EC2 namespace(EKS、自定义 metric、ContainerInsights),原生流程拿到的 description 经常缺关键 dimensions,导致 Agent 调查方向偏。

→ 本仓 Lambda-A 解决:在我们自己的 Lambda 里把 namespace + dimensions + alarm reason 结构化拼进 create_backlog_task 的 description(顺手修了一个 EventBridge event 里 accountId / region 在 top-level 而不是 detail 里的取值 bug),保证调查从一开始就拿到完整上下文。

3. 输出格式不可控 原生 Slack 通知是固定模板,没有 Block Kit 自定义、没有不同事件类型分别走不同 channel 的能力、不能把 executionId / journal 链接 / 关键 metric 抽成可点击元素。

→ 本仓 Lambda-B 解决:监听 aws.aidevopsInvestigation Completed 事件,自己拉 list_journal_records → investigation_summary_md,用 Slack Block Kit 自定义渲染(标题、严重度色块、journal 链接、相关资源 dimensions),可以按 alarm 类型路由到不同频道。

4. 区域 / 跨分区限制 DevOps Agent 服务本身只在少数 region 可用,且 AWS 中国区不支持。如果应用部署在 aws-cn 或者 Agent Space 所在 region 与告警源 region 不同,原生集成无能为力。

→ 本仓事件管道全部走 EventBridge + Lambda,可以无侵入地接入 aws-devops-agent-cn-bridge(IAM Roles Anywhere 跨分区 assume),让 Global 分区的 Agent Space 调查 aws-cn 资源。

5. 部署不可代码化 原生 Slack 集成必须 手动 走「Console → Register → Slack OAuth → 选 workspace → Allow → 回 Console 关联 Agent Space」流程,每个频道都要手动加 bot 用户。无法纯 IaC 管理,多账号 / 多环境复制成本高。

→ 本仓 scripts/deploy.sh + scripts/deploy-chatbot.sh 把除「创建 Slack App」之外的所有部署步骤脚本化(IAM、Lambda、EventBridge rule、API Gateway、DDB 表),.env 注入参数;Slack App 那一次性手动配置在 docs/slack-setup.md 里有详细 checklist。

一句话:原生集成是 demo 级 的「调查完了通知一下」,本仓是 生产级 的「告警入口可控、调查上下文完整、Slack 内可对话、跨区可扩展」的 bridge 层。


0. 架构总览

CloudWatch Alarm (任意 namespace)
        │  state = ALARM
        ▼
EventBridge Rule-1 ── aws.cloudwatch / CloudWatch Alarm State Change
        │
        ▼
Lambda-A (devops-agent-trigger-investigation)
        │  create_backlog_task(taskType=INVESTIGATION)
        │  把 namespace + dimensions + alarm reason 结构化进 description
        ▼
DevOps Agent  ── 自主调查 5–15 min
        │     - 调 use_aws describe_xxx 收集资源数据
        │     - 拉 CloudWatch metrics / CloudTrail events
        │  发布 aws.aidevops / Investigation Completed
        ▼
EventBridge Rule-2 ── aws.aidevops / Investigation Completed
        │
        ▼
Lambda-B (devops-agent-notify-slack)
        │  list_journal_records → investigation_summary_md
        │  Slack Incoming Webhook → Block Kit
        ▼
Slack #<SLACK_CHANNEL_ID>


2. 前置条件

2.1 账号侧

  • AWS CLI v2 已配置 <ACCOUNT_ID> 凭证
  • AWS DevOps Agent 在 ap-northeast-1 已可用(preview 阶段)
  • 已确认:你已经在 console 创建好 Agent Space(如果没有,aidevops console → Create Agent Space),把 ID 填进 .envDEVOPS_AGENT_SPACE_ID

控制台拿 ID:aidevopsAgent Spaces → 点详情 → 右上角 Copy ARN → 取 agentspace/ 后的 UUID。

2.2 boto3 版本(重要)

DevOps Agent 客户端在 boto3 1.43.0 才发布到公开 PyPI。Lambda Python 3.12 内置的 boto3 是更老的版本,不带 devops-agent 客户端,所以必须打 layer。部署脚本已自动处理(pip install boto3>=1.43.0 -t layer/python)。

服务名映射(要全部记住):

  • boto3 client 名:devops-agent
  • IAM action 前缀:aidevops:
  • EventBridge source:aws.aidevops
  • 服务 endpoint:aidevops.<region>.amazonaws.com

2.3 Slack 集成(已就绪)

频道 <SLACK_CHANNEL_ID> 已有 Incoming Webhook(被 petsite-ops-slack-notifier 用着,本方案直接复用——不用新建 Slack App,不用 Bot Token)。

Webhook URL 已挪到 Secrets Manager(2026-05-20,P0-6):

arn:aws:secretsmanager:<region>:<ACCOUNT_ID>:secret:devops-agent/slack-webhook-url-<RANDOM_SUFFIX>

Lambda-B 通过 SLACK_WEBHOOK_SECRET_ARN env var 拿到 ARN,cold-start 时 GetSecretValue 一次后缓存到 module global。

Webhook 轮换流程aws secretsmanager put-secret-value --secret-id devops-agent/slack-webhook-url --secret-string <new-url> → 等下一次 cold start(≤15 分钟空闲后)生效。

2.4 本机工具

  • aws v2.x、python3.12pipzipunzipjqenvsubstgettext 包带)
  • kubectl(验证 EKS node 时用)

2.5 Configuration (.env)

仓库里没有任何账号 / 资源 ID 真值;全部走 .env

cp .env.example .env
$EDITOR .env       # 填进真值

.env 已在 .gitignore真值永远不进 git.env.example 全是占位符 + 注释说明,可以放心 push。

变量 怎么拿
AWS_ACCOUNT_ID aws sts get-caller-identity --query Account --output text
AWS_REGION 你计划部署的 region(本项目所有资源同区)
DEVOPS_AGENT_SPACE_ID Console → aidevops → Agent Spaces → 详情 → Copy ARN → 取 agentspace/ 后的 UUID
DEVOPS_AGENT_SPACE_ARN 同上,整个 ARN
SLACK_CHANNEL / SLACK_TEST_CHANNEL Slack 客户端:右键频道 → View channel details → 底部 Channel ID (Cxxxxxx)
SLACK_WEBHOOK_URL Slack App → Incoming Webhooks → Add New Webhook(deploy.sh 写进 Secrets Manager 后 Lambda 从那读)
SLACK_BOT_TOKEN_SECRET_ID / SLACK_SIGNING_SECRET_ID chatbot 才用,建 Slack App 流程见 docs/slack-setup.md
API_GATEWAY_INVOKE_URL 第一次跑 deploy-chatbot.sh 后自动打印,复制回 .env

安全提示:千万不要 git add .env。脚本和 docs 都从 .env 读,<...> 占位符只用于文档展示,不会走进 AWS API。


3. 部署

3.1 准备 .env

cd /home/ubuntu/tech/devops-agent
cp .env.example .env
# 编辑 .env 填真值后再继续。详见 §2.5 Configuration。

3.2 一键部署核心组件

./scripts/deploy.sh

脚本步骤:

  1. 校验当前 caller 是 <ACCOUNT_ID>
  2. 创建 IAM Role DevOpsAgentDemoLambdaRole(含 aidevops:* 投放任务 / 读 chat / 拉 journal 权限)
  3. 构建并发布 boto3-latest layer(boto3 ≥ 1.43.0,含 devops-agent 客户端)
  4. 部署 Lambda-A devops-agent-trigger-investigation
  5. 部署 Lambda-B devops-agent-notify-slack
  6. 创建 EventBridge Rule-1(任意 CloudWatch Alarm → Lambda-A)
  7. 创建 EventBridge Rule-2(Investigation Completed → Lambda-B)
  8. 打印资源 ARN

幂等:可重复执行,已存在资源走 update 路径。

3.3 加靠谱的告警(针对 EKS node 故障)

PetSite 账号默认的 ContainerInsights node 告警已经全废(NodeName 写死了旧节点 IP)。要让 删 node 类故障真的能触发告警,跑:

./scripts/add-node-loss-alarms.sh

会创建 4 个告警(period 60s, eval 1):

告警 触发条件 真实命中率(FIS 实测)
petsite-asg-instances-below-desired-workers1a60 GroupInServiceInstances / GroupDesiredCapacity < 1.0(metric math) ❌ 故障窗口 < 60s 时不触发
petsite-asg-instances-below-desired-workers1cFE 同上 同上
petsite-eks-pods-unschedulable AWS/EKS scheduler_pending_pods_UNSCHEDULABLE > 0 ✅ 命中(实测 60s 故障窗口能捕到)
petsite-eks-apiserver-5xx AWS/EKS apiserver_request_total_5XX > 5/min ⚠️ 删 node 通常不影响 control plane

关键经验:本账号 ContainerInsights namespace 完全没 metric(CW agent / fluent-bit 没安装或停了),所以最初尝试用 cluster_node_count / cluster_failed_node_count 都失败。最后落到 AWS/EKS scheduler_pending_pods_UNSCHEDULABLE,这是 EKS 内置的 control-plane metric,不依赖任何 add-on,并且能真实反映"node 不够导致 pod 调度失败"。


4. 文件结构

devops-agent/
├── README.md                                    ← 本文件
├── .env.example                                 ← 配置模板(占位符,可入库)
├── .env                                         ← 真实配置(.gitignore 排除,永远不入库)
├── .gitignore
├── iam/
│   ├── lambda-role-trust.json                   Lambda 信任策略
│   ├── devops-agent-policy.json                 aidevops:* 权限(含 chat)
│   ├── chatbot-policy.json.template             chatbot 用 IAM policy 模板(账号 ID 用 ${AWS_ACCOUNT_ID} 占位,deploy 时 envsubst 渲染到 .build/iam/)
│   └── backups/
│       └── RestrictToTokyoRegion-*.json         旧 region 限制 policy 备份(已删除)
├── lib/
│   └── agent_chat.py                            DevOps Agent EventStream 解析与多轮对话(CLI + Lambda-C 共用)
├── lambda/
│   ├── cli/chat.py                              Chat CLI 入口
│   ├── lambda_a/lambda_function.py              触发调查(通用化 description)
│   ├── lambda_b/lambda_function.py              Slack webhook 通知
│   └── lambda_c/                                Slack Chatbot(交互式多轮)
│       ├── lambda_function.py                   entry + worker dispatcher
│       └── slack_verify.py                      Slack 签名验证
├── tests/                                       71 测试覆盖 Lambda-A/B/C + 签名验证
├── eventbridge/
│   ├── rule-1-alarm-to-lambda-pattern.json
│   └── rule-2-investigation-completed-pattern.json
└── scripts/
    ├── deploy.sh                                一键部署主链路(读 .env)
    ├── deploy-chatbot.sh                        部署 Lambda-C + API GW + DLQ + alarms
    ├── setup-dashboard.sh                       provision CloudWatch Dashboard(deploy.sh 默认会调)
    ├── cleanup.sh                               一键清理主链路
    ├── cleanup-chatbot.sh                       清理 chatbot 资源
    ├── add-node-loss-alarms.sh                  PetSite 专用:加 EKS/ASG node-loss 告警
    ├── chat.sh                                  Chat CLI wrapper
    ├── run-fis-2node-termination.sh             PetSite 专用:FIS 删 2 个 node 验证脚本
    └── test-trigger.sh                          (旧)stress-ng EC2 触发测试

5. 核心代码(关键改动点)

5.0 Chat CLI(交互式实时对话)

除了异步的 Backlog Task 调查,本项目还提供一个 CLI 工具,调 create_chat + send_message 同步跟 Agent 聊天。

# 单轮问答
./scripts/chat.sh "List running EC2 instances"

# 交互式 REPL(多轮上下文)
./scripts/chat.sh -i

# 恢复之前的会话(多轮追问)
./scripts/chat.sh --resume <executionId> "follow-up question"

# 看到 executionId / token usage / tool calls / context utilization
./scripts/chat.sh --show-ids "..."

# 看到 Agent 的 thinking 过程
./scripts/chat.sh --show-thinking "..."

实现要点lambda/cli/chat.py):

  • send_message 返回一个 EventStream,需要按 内容块类型 分流:

    block type 含义 默认是否展示
    final_response 最终回答 ✅ stdout
    text Agent 思考过程 ❌(--show-thinking 才展)
    chat_title 自动生成的会话标题 ❌(--show-ids 才展)
    context_usage 上下文窗口利用率 ❌ metadata
    tool_use / tool_summary Agent 调用的 AWS API 详情 ❌(--show-ids 才展)
  • 多轮对话靠复用同一个 executionIdcreate_chat 只需一次。

  • usage.inputTokens / outputTokens 可以跟踪成本。

  • context_usage.context_window.utilization 超过 70% 考虑开新会话。

5.1 Lambda-A:通用化的 description(含 bug fix)

# 把所有 dimensions 都摊出来,不假设是 EC2
metric = metrics[0].get("metricStat", {}).get("metric", {})
namespace   = metric.get("namespace", "")
metric_name = metric.get("name", "")
dimensions  = metric.get("dimensions", {}) or {}

# ⚠️ accountId / region 在 EventBridge event 的 TOP LEVEL,不在 detail 里!
# 之前曾从 detail.get("accountId") 读,永远是空。现在从 event.get("account") 读。
account = event.get("account", "")
region  = event.get("region", REGION)

description = (
    # ===== Investigation starting point(与控制台字段对齐)=====
    f"Investigation starting point:\n"
    f"  Source: CloudWatch Alarm '{alarm_name}'\n"
    f"  Account: {account}  Region: {region}\n"
    f"  Namespace: {namespace}\n"
    f"  Metric: {metric_name}\n"
    f"  Dimensions:\n" + "\n".join(f"  - {k}: {v}" for k, v in dimensions.items()) + "\n"
    f"  Alarm reason: {reason}\n\n"
    # ===== Investigation details =====
    f"Investigation details:\n"
    f"  Identify the root cause of this alarm. ..."
)
告警类型 Namespace 关键 dimensions 是否需改代码
EC2 CPU 飙升 AWS/EC2 InstanceId ❌ 自适配
RDS 连接耗尽 AWS/RDS DBInstanceIdentifier ❌ 自适配
EKS pods unschedulable AWS/EKS ClusterName ❌ 自适配
Lambda 错误率 AWS/Lambda FunctionName ❌ 自适配
ALB 5xx AWS/ApplicationELB LoadBalancer, TargetGroup ❌ 自适配

5.2 Lambda-B:Slack Incoming Webhook

  • 复用 petsite-ops-slack-notifier 用的 webhook
  • 标准库 urllib.request,无第三方依赖
  • Block Kit 三段式:header / metadata fields / divider / summary chunks
  • summary > 2900 字符自动按行分块(Slack mrkdwn block 单块 3000 字符上限)
  • 仅在 data.status == "COMPLETED" 才发,避免中间状态噪音

5.3 IAM 权限

iam/devops-agent-policy.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DevOpsAgentBacklog",
      "Effect": "Allow",
      "Action": [
        "aidevops:CreateBacklogTask",
        "aidevops:GetBacklogTask",
        "aidevops:ListJournalRecords",
        "aidevops:ListBacklogTasks"
      ],
      "Resource": "*"
    },
    {
      "Sid": "DevOpsAgentChat",
      "Effect": "Allow",
      "Action": [
        "aidevops:CreateChat",
        "aidevops:SendMessage",
        "aidevops:ListChats",
        "aidevops:ListPendingMessages"
      ],
      "Resource": "*"
    }
  ]
}

⚠️ IAM action 前缀是 aidevops:不是 devops-agent:)。

Agent Space 服务角色另外说一下DevOpsAgentRole-AgentSpace-<RANDOM_SUFFIX>Agent 自己用来调 AWS API(EC2/RDS/EKS Describe)的角色,不归本项目管。它原本挂了一个 RestrictToTokyoRegion inline policy 限制只能查 Tokyo,但副作用是 Agent 第一步 DescribeRegions 在 us-east-1 endpoint 就被 deny,导致整个调查链路失效。该 policy 已经在调试时删除(备份在 iam/backups/),允许 Agent 跨 region 扫描(每次问答 ~30 个 tool call 是这个原因)。如需恢复 region 限制,参考官方文档tag-based scoping 替代纯 region deny。

5.4 EventBridge

Rule-1(任意 ALARM → Lambda-A):

{
  "source": ["aws.cloudwatch"],
  "detail-type": ["CloudWatch Alarm State Change"],
  "detail": { "state": { "value": ["ALARM"] } }
}

Rule-2(Investigation Completed → Lambda-B):

{
  "source": ["aws.aidevops"],
  "detail-type": ["Investigation Completed"]
}

5.5 Slack Chatbot(交互式多轮对话)

除了 告警 → 调查 → 推送 Slack 这条异步主线,还部署了 Slack Chatbot:用户在 #<SLACK_CHANNEL_ID>@devops_agent <问题> 即可调 DevOps Agent chat,结果推回同一 thread,同 thread 内多轮追问会复用同一个 chat session

架构

Slack @mention → Slack Events API → API Gateway HTTP API → Lambda-C
                                                              │ (fast path: ack 200 in <3s)
                                                              ├→ lambda.invoke(self, _internal=chat)  异步自调用
                                                              │
                                                              └→ (worker path)
                                                                  1. DDB get_item(thread_ts) 查/建 chat
                                                                  2. devops-agent.send_message  调用
                                                                  3. Slack chat.postMessage 占位占 + chat.update 替换

环境变量(都在 .env):

SLACK_BOT_TOKEN_SECRET_ID=devops-agent/slack-chatbot-token
SLACK_SIGNING_SECRET_ID=devops-agent/slack-signing-secret
SLACK_TEST_CHANNEL=<SLACK_CHANNEL_ID>
THREAD_TABLE_NAME=devops-agent-slack-threads
LAMBDA_C_NAME=devops-agent-slack-chatbot

部署

# 1. 创建 Slack App(手动一次)、拿 Bot Token + Signing Secret、存进 Secrets Manager(详见 docs/slack-setup.md)

# 2. 部署(脚本会自动建 DDB 表 + 启用 TTL,幂等可重复执行)
export ENV_FILE=.env
./scripts/deploy-chatbot.sh
# 输出里会包含 API GW Invoke URL,用于下一步

# 3. 在 Slack App 控制台配 Event Subscriptions(手动一次):
#    Request URL = 上一步 Invoke URL
#    Subscribe to bot events: app_mention
#    Save → Reinstall App

验证

# 在 #<SLACK_CHANNEL_ID> 里:
@devops_agent ping                                  # 得到 "Hey there!" 之类
@devops_agent list EC2 instances in <region>        # 得到 EC2 列表
# 同 thread 追问(点上一条的 “Reply in thread”):
which one is biggest?                                # thread 内免 @(见§5.6 Slack 使用说明)

详细使用说明、Slack App 配置、多 topic 场景、设计要点都集中在 §5.6 Slack 使用说明 里。


5.6 Slack 使用说明 · 配置 + 交互行为

Slack App 一次性配置(详细步骤在 docs/slack-setup.md):

步骤 在哪做 做什么
1 https://api.slack.com/apps → Create 新建 App,名字随意(如 PetSite DevOps Agent
2 OAuth & Permissions → Bot Token Scopes app_mentions:readchat:writechannels:historygroups:history(私有频道时)
3 Event Subscriptions → Enable Request URL 填 deploy-chatbot.sh 输出的 API GW URL;订阅 bot events: app_mention + message.channels
4 Install to Workspace 拿到 Bot Token (xoxb-...) + Signing Secret,存进 Secrets Manager(脚本用)
5 频道里 /invite @devops_agent 把 bot 加进所有需要的频道(私有频道必须,公共频道也建议)

正常使用方式

场景 怎么发 bot 行为
新问题(顶层) @devops_agent <问题> 在频道顶层发 bot 创建新 chat session,回复以 thread 形式开启
同 thread 追问 直接在 thread 里发消息(不用 @ bot 复用这个 thread 已有的 chat session(DDB hit),保留多轮上下文
老 thread 重新激活 7 天内同 thread 继续发 bot 仍复用原 chat(DDB TTL 7 天)
老 thread > 7 天 同 thread 发消息 DDB 已过期 → 当作新问题处理(不可避免
新 topic(新 thread) 必须 @devops_agent <问题> 重新顶层发 bot 开新 chat session,与之前 thread 隔离
老 channel 内不相关闲聊 不要 @ bot bot 不响应(message.channels 命中后查 DDB,没记录就丢;EMF metric UnhandledMessageEvents 计数)

⚠️ 注意点

  • 不要在私有频道直接 mention,必须先 /invite @devops_agent 加进去
  • 不要把 bot 加进 #general 这种高噪声频道 —— 即使 message.channels 会 DDB 过滤掉 noise,也会消耗 Lambda invocation
  • thread 内多轮对话期间,每条新消息消耗 1 次 Lambda 调用(fast-path ack + worker 异步),reserved concurrency 上限 5(脚本默认)
  • bot 只看 thread_ts 不看用户身份:所以同 thread 内任何人发消息 bot 都会响应(设计上是为了协作场景;如果不想这样要在 worker 里加 user 白名单)

架构

Slack @mention → Slack Events API → API Gateway HTTP API → Lambda-C
                                                              │ (fast path: ack 200 in <3s)
                                                              ├→ event_id 幂等 check(DDB evt: 前缀)
                                                              ├→ lambda.invoke(self, _internal=chat) 异步自调用
                                                              │
                                                              └→ (worker path)
                                                                  1. DDB get_item(thread_ts) 查/建 chat
                                                                  2. devops-agent.send_message
                                                                  3. Slack chat.postMessage 占位 + chat.update 替换

关键设计点

  • Slack 3 秒响应规则 — fast path 必须在 3s 内 200 ack。同 Lambda 自异步调用(InvocationType=Event)走 worker;fast path 实测 热启动 ~258ms / 冷启动 ~1019ms
  • 多轮对话thread_ts 作为 DDB PK,同 thread 复用同一 executionId(chat session)
  • 双订阅幂等app_mention + message.channels 同一 user message 会触发两次 event,DDB evt: 前缀的 ConditionalCheck 原子去重
  • 安全 — Slack signing 验签(v0:timestamp:body HMAC-SHA256)+ 5min replay protection + hmac.compare_digest 时序安全比较
  • TTL — thread 表 7 天后自动过期;超过一周没人提的 thread 下次会重启会话

为什么没用 Incoming Webhook:webhook 只能单向发,不能接 Slack events,双向必须 Bot Token。Lambda-B(推 Slack 摘要)走 webhook 即可;Lambda-C(多轮交互)必须走 Bot Token + chat.postMessage / chat.update。

单元测试覆盖tests/test_slack_verify.py 12 个场景(正常签名 / 大写 header / 过期时间戳 / 未来时间戳 / 篡改 body / 错 secret / 缺 header / 空 secret / 非 bytes body / timing-safe 比对 等);tests/test_lambda_c.py 25 个场景(fast/worker path、event 幂等、thread reply 自动响应、race-loser LWW 等)。


6. 端到端验证(FIS 实战)

6.1 实战脚本

./scripts/run-fis-2node-termination.sh

会克隆账号里现成的 EKS node termination 模板(EXT25AmEAp21foyA),改 instanceTerminationPercentage=100,删 PetSite/workers1a60 nodegroup 的全部 2 个 node

6.2 流量来源

复用账号里现有的 openclaw-health-canary Synthetic(rate 30 min,频率较低)。如需更密集流量验证 ALB 5xx 告警:

# 临时压一会儿
hey -z 5m -c 5 http://<your-alb-dns-name>/

6.3 实测时间线(参考)

时间点 事件 备注
T+0s FIS start-experiment 状态 initiating
T+13s FIS completed 2 个 1a node 已被 terminate
T+1min ASG 补上 1 个新 node minSize=2 强制
T+2min petsite-eks-pods-unschedulable OK → ALARM(3 pods unschedulable) ✅ 告警捕到
T+2min EventBridge → Lambda-A → create_backlog_task DevOps Agent 接到
T+3min 告警 ALARM → OK(pods 已重新调度) 故障窗口约 60s
T+5–15min DevOps Agent 调查完成,发 Investigation Completed 事件
T+5–15min Lambda-B 拉 journal → Slack <SLACK_CHANNEL_ID> 收到 markdown 摘要

6.4 观察日志

source .env  # so AWS_REGION / DEVOPS_AGENT_SPACE_ID are loaded into shell

# Lambda-A 实时日志
aws logs tail /aws/lambda/devops-agent-trigger-investigation --follow --region "${AWS_REGION}"

# Lambda-B 实时日志
aws logs tail /aws/lambda/devops-agent-notify-slack --follow --region "${AWS_REGION}"

# 当前 Investigation 任务
python3 -c "
import os, boto3, json
c = boto3.client('devops-agent', region_name=os.environ['AWS_REGION'])
r = c.list_backlog_tasks(agentSpaceId=os.environ['DEVOPS_AGENT_SPACE_ID'], filter='taskType=INVESTIGATION')
print(json.dumps(r['tasks'][:5], default=str, indent=2))
"

6.5 关键发现(这次实战学到的)

  1. ASG GroupInServiceInstances < Desired 告警没触发 — 故障窗口 < 60s,1-min period 的告警没采到 < 1.0 的 datapoint。删 node 类故障 ASG 告警不可靠
  2. AWS/EKS scheduler_pending_pods_UNSCHEDULABLE 是关键检测点 — 这是 EKS 内置 metric,反映 实际症状(pod 找不到 node)。建议作为 EKS 集群的 baseline alarm
  3. ContainerInsights metric 在本账号不存在 — 任何依赖 cluster_node_count / cluster_failed_node_count 的告警都会 INSUFFICIENT_DATA
  4. Bug found & fixed:原 Lambda-A 从 event['detail'].get('accountId') 读 account ID,但 EventBridge 事件结构里 accountregiontop-level 字段。已改成 event.get('account') / event.get('region')


8. 清理

./scripts/cleanup.sh           # 主链路(IAM role / Lambda-A&B / 两个 EventBridge 规则)
./scripts/cleanup-chatbot.sh   # chatbot(Lambda-C / API Gateway / SlackChatbotAccess inline policy)

会删:IAM role、3 个 Lambda、2 个 EventBridge 规则、API Gateway HTTP API。 不会删(需手动):

  • boto3 layer 版本(layer 是按账号共享,cleanup 留下避免误删别的项目)
  • Agent Space
  • 3 个 SQS DLQ(devops-agent-trigger-dlq / devops-agent-notify-dlq / devops-agent-slack-chatbot-dlq
  • CloudWatch Alarms(devops-agent-slack-chatbot-{errors,apigw-5xx,ddb-throttle} + 4 个 node-loss 告警)
  • CloudWatch Dashboard DevOpsAgent-PetSite
  • DynamoDB devops-agent-slack-threads
  • Secrets Manager 三个 secret(webhook URL / bot token / signing secret)
  • Slack webhook + Slack App

手动清理示例:

# DLQ
for q in devops-agent-trigger-dlq devops-agent-notify-dlq devops-agent-slack-chatbot-dlq; do
  url=$(aws sqs get-queue-url --region "${AWS_REGION}" --queue-name "$q" --query QueueUrl --output text 2>/dev/null) \
    && aws sqs delete-queue --region "${AWS_REGION}" --queue-url "$url"
done

# Dashboard
aws cloudwatch delete-dashboards --region "${AWS_REGION}" --dashboard-names DevOpsAgent-PetSite

# Chatbot alarms
aws cloudwatch delete-alarms --region "${AWS_REGION}" --alarm-names \
  devops-agent-slack-chatbot-errors \
  devops-agent-slack-chatbot-apigw-5xx \
  devops-agent-slack-chatbot-ddb-throttle

# Node-loss alarms (PetSite-specific)
aws cloudwatch delete-alarms --region "${AWS_REGION}" --alarm-names \
  petsite-asg-instances-below-desired-workers1a60 \
  petsite-asg-instances-below-desired-workers1cFE \
  petsite-eks-pods-unschedulable \
  petsite-eks-apiserver-5xx

附录 A:Investigation Completed 事件示例

{
  "source": "aws.aidevops",
  "detail-type": "Investigation Completed",
  "detail": {
    "version": "1.0.0",
    "metadata": {
      "agent_space_id": "<AGENT_SPACE_UUID>",
      "task_id": "<UUID>",
      "execution_id": "exe-ops1-<UUID>"
    },
    "data": {
      "task_type": "INVESTIGATION",
      "priority": "HIGH",
      "status": "COMPLETED",
      "created_at": "...",
      "updated_at": "...",
      "summary_record_id": "<UUID>"
    }
  }
}

附录 B:Journal record 类型

recordType 说明
investigation_summary_md 完整调查摘要(Markdown)—— Lambda-B 用这个发 Slack
investigation_summary 结构化摘要(JSON)
symptom 发现的症状
finding 调查发现(含根因)
observation 观测数据
investigation_gap 调查信息缺口
message Agent 对话消息

附录 C:关键 ARN 速查(模板)

全部用占位符;运行 bash scripts/print-config.sh 或自己看 .env / aws sts get-caller-identity 拿到真值。

Account:            <ACCOUNT_ID>
Region:             <region>
Agent Space:        <agent-space-name>
Agent Space ID:     <AGENT_SPACE_UUID>
Agent Space ARN:    arn:aws:aidevops:<region>:<ACCOUNT_ID>:agentspace/<AGENT_SPACE_UUID>
Slack Channel:      <SLACK_CHANNEL_ID>
Slack Webhook:      <secret> arn:aws:secretsmanager:<region>:<ACCOUNT_ID>:secret:devops-agent/slack-webhook-url-<RANDOM_SUFFIX>
Slack App (bot):    <slack-app-id> (PetSite DevOps Agent)
Slack Bot User:     <slack-bot-user-id> (devops_agent)
Slack Bot ID:       <slack-bot-id>
Bot Token Secret:   arn:aws:secretsmanager:<region>:<ACCOUNT_ID>:secret:devops-agent/slack-chatbot-token-<RANDOM_SUFFIX>
Sign Secret:        arn:aws:secretsmanager:<region>:<ACCOUNT_ID>:secret:devops-agent/slack-signing-secret-<RANDOM_SUFFIX>
IAM Role (Lambda):  arn:aws:iam::<ACCOUNT_ID>:role/DevOpsAgentDemoLambdaRole
IAM Role (Agent):   arn:aws:iam::<ACCOUNT_ID>:role/service-role/DevOpsAgentRole-AgentSpace-<RANDOM_SUFFIX>
Lambda-A:           arn:aws:lambda:<region>:<ACCOUNT_ID>:function:devops-agent-trigger-investigation
Lambda-B:           arn:aws:lambda:<region>:<ACCOUNT_ID>:function:devops-agent-notify-slack
Lambda-C:           arn:aws:lambda:<region>:<ACCOUNT_ID>:function:devops-agent-slack-chatbot
API Gateway:        <API_ID>
API Invoke URL:     https://<API_ID>.execute-api.<region>.amazonaws.com/slack/events
DDB Thread Table:   arn:aws:dynamodb:<region>:<ACCOUNT_ID>:table/devops-agent-slack-threads
Layer (boto3):      arn:aws:lambda:<region>:<ACCOUNT_ID>:layer:boto3-latest:1
Rule-1:             DevOps-Agent-Demo-Alarm-To-Lambda
Rule-2:             DevOps-Agent-Investigation-Completed
EKS Cluster:        <eks-cluster-name>
PetSite ALB:        <alb-dns-name>

About

PetSite reference integration for AWS DevOps Agent (preview): CloudWatch Alarm → Backlog Task → Slack notification + threaded chatbot. Built on Lambda-A/B/C, EventBridge, DDB.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors