news 2026/7/2 6:11:25

从阿里云 SLS 到 AWS CloudWatch:K8s 日志采集 + 钉钉告警完整迁移实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从阿里云 SLS 到 AWS CloudWatch:K8s 日志采集 + 钉钉告警完整迁移实战
  • 背景:有 3 台自建的 K8s 服务器,跑着核心业务。之前一直用阿里云 SLS 采集日志,但最近业务调整,希望使用AWS。
  • 日志采集看起来是件小事,但真做起来才发现:采集器用什么?日志怎么传?告警怎么配?钉钉怎么通知?
  • 经过一系列的踩坑、试错、解决各种报错,最终跑通了一条完整的链路:K8s → Fluent Bit → CloudWatch → SNS→ Lambda →钉钉告警。

AWS CloudWatch 日志接入

K8s 集群日志采集 + 钉钉告警 完整部署指南

1. 文档概述

1.1 目的

将自建 K8s 集群(3台服务器,containerd 运行时,rocky linux 9.7)的容器日志接入 AWS CloudWatch,并配置钉钉告警通知。

1.2 架构图

┌─────────────────────────────────────────────────────────────────────────────┐ │ K8s 集群 (3台服务器) │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Fluent Bit (DaemonSet) │ │ │ │ - 采集 /var/log/containers/*.log │ │ │ │ - 解析 Kubernetes 元数据 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ Amazon CloudWatch │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 日志组: /aws/containerinsights/{cluster-name}/application │ │ │ │ - 日志流按 Pod 自动命名 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 指标筛选器: ErrorCount │ │ │ │ - 筛选条件: ERROR │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 告警规则: K8s-Error-DingTalk │ │ │ │ - 条件: 5分钟内 ERROR > 5次 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ SNS 主题: K8s-DingTalk-Alarm │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ Lambda: DingTalkNotifier │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 钉钉群机器人 │ └─────────────────────────────────────────────────────────────────────────────┘

2. 前置条件

2.1 环境信息

项目
AWS 账号 ID登录AWS获取
AWS 区域按需选择
K8s 版本v1.34.6
节点数量3(1 control-plane + 2 worker)
操作系统Rocky Linux 9.7
容器运行时containerd 2.2.3
日志路径/var/log/pods///*.log
采集器Fluent Bit (aws-for-fluent-bit)

2.2 所需权限

  • AWS IAM 用户需具备以下权限:
    • CloudWatchAgentServerPolicy
    • AmazonSNSFullAccess
    • CloudWatchLogsFullAccess
    • CloudWatchFullAccess
    • AWSLambda_FullAccess
    • IAMFullAccess(创建角色和策略)

2.3 前置准备

  • AWS CLI 已安装并配置
  • kubectl 已安装并可连接集群
  • Helm 已安装(可选)
  • 钉钉群机器人 Webhook 地址已准备

3. 第一步:AWS IAM 角色配置

3.1 创建 IAM 角色(在 AWS 控制台操作)

  1. 进入 IAM → 角色 → 创建角色
  2. 选择"AWS服务" → “EC2
  3. 附加策略:CloudWatchAgentServerPolicy
  4. 角色名称:CloudWatchAgent-Role
  5. 点击"创建角色"

3.2 绑定 IAM 角色到 EC2 实例

  1. 进入 EC2 控制台 → 实例
  2. 选中需要绑定的实例(你的 3 台 K8s 节点)
  3. 操作 → 安全 → 修改 IAM 角色
  4. 选择CloudWatchAgent-Role
  5. 点击"更新 IAM 角色"

3.3 验证 IAM 角色绑定成功

curl-shttp://169.254.169.254/latest/meta-data/iam/security-credentials/CloudWatchAgent-Role|head-20

期望输出:返回包含AccessKeyIdSecretAccessKey的 JSON

3.4 为 sms-sender 用户添加权限

# 附加 SNS 权限aws iam attach-user-policy\--user-name sms-sender\--policy-arn arn:aws:iam::aws:policy/AmazonSNSFullAccess# 附加 CloudWatch 日志权限aws iam attach-user-policy\--user-name sms-sender\--policy-arn arn:aws:iam::aws:policy/CloudWatchLogsFullAccess# 附加 CloudWatch 告警权限aws iam attach-user-policy\--user-name sms-sender\--policy-arn arn:aws:iam::aws:policy/CloudWatchFullAccess# 附加 Lambda 权限aws iam attach-user-policy\--user-name sms-sender\--policy-arn arn:aws:iam::aws:policy/AWSLambda_FullAccess

4. 第二步:部署 Fluent Bit 采集器

4.1 创建部署脚本

创建deploy-fluentbit.sh

#!/bin/bash# deploy-fluentbit.sh - 部署 Fluent Bit 日志采集器# 在 K8s Master 节点执行set-eecho"=========================================="echo"部署 Fluent Bit 日志采集器"echo"=========================================="# 设置变量AWS_ACCOUNT_ID="997836553899"REGION="ap-east-1"ROLE_NAME="CloudWatchAgent-Role"CLUSTER_NAME="k8s"# 1. 创建命名空间echo">>> 创建命名空间 amazon-cloudwatch"kubectl create namespace amazon-cloudwatch --dry-run=client-oyaml|kubectl apply-f-# 2. 创建 ServiceAccountecho">>> 创建 ServiceAccount"cat<<EOF|kubectl apply-f-apiVersion: v1 kind: ServiceAccount metadata: name: fluent-bit-sa namespace: amazon-cloudwatch annotations: eks.amazonaws.com/role-arn: arn:aws:iam::$AWS_ACCOUNT_ID:role/$ROLE_NAMEEOF# 3. 创建 ConfigMapecho">>> 创建 Fluent Bit 配置"cat<<EOF|kubectl apply-f-apiVersion: v1 kind: ConfigMap metadata: name: fluent-bit-config namespace: amazon-cloudwatch labels: k8s-app: fluent-bit data: fluent-bit.conf: | [SERVICE] Flush 5 Log_Level info Daemon off Parsers_File parsers.conf HTTP_Server On HTTP_Listen 0.0.0.0 HTTP_Port 2020 [INPUT] Name tail Path /var/log/containers/*.log Parser cri Tag kube.* Refresh_Interval 10 Mem_Buf_Limit 50MB Skip_Long_Lines On [FILTER] Name kubernetes Match kube.* Kube_URL https://kubernetes.default.svc:443 Kube_Tag_Prefix kube.var.log.containers. Merge_Log On Merge_Log_Key log_processed Keep_Log On K8S-Logging.Parser On K8S-Logging.Exclude Off Annotations Off Labels Off [OUTPUT] Name cloudwatch_logs Match kube.* region ap-east-1 log_group_name /aws/containerinsights/${CLUSTER_NAME}/application log_stream_prefix${CLUSTER_NAME}- auto_create_group true log_retention_days 30 parsers.conf: | [PARSER] Name cri Format regex Regex ^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<message>.*)$ Time_Key time Time_Format %Y-%m-%dT%H:%M:%S.%L%z EOF# 4. 部署 DaemonSetecho">>> 部署 Fluent Bit DaemonSet"cat<<EOF|kubectl apply-f-apiVersion: apps/v1 kind: DaemonSet metadata: name: fluent-bit namespace: amazon-cloudwatch labels: k8s-app: fluent-bit spec: selector: matchLabels: k8s-app: fluent-bit template: metadata: labels: k8s-app: fluent-bit spec: serviceAccountName: fluent-bit-sa hostNetwork: true dnsPolicy: ClusterFirstWithHostNet containers: - name: fluent-bit image: public.ecr.aws/aws-observability/aws-for-fluent-bit:3 imagePullPolicy: Always env: - name: REGION value: "${REGION}" - name: CLUSTER_NAME value: "${CLUSTER_NAME}" resources: requests: memory: "128Mi" cpu: "50m" limits: memory: "256Mi" cpu: "100m" volumeMounts: - name: varlog mountPath: /var/log - name: dockercontainers mountPath: /var/lib/docker/containers readOnly: true - name: fluent-bit-config mountPath: /fluent-bit/etc/ - name: runlog mountPath: /var/run volumes: - name: varlog hostPath: path: /var/log - name: dockercontainers hostPath: path: /var/lib/docker/containers - name: fluent-bit-config configMap: name: fluent-bit-config - name: runlog hostPath: path: /var/run tolerations: - operator: Exists EOFecho"=========================================="echo"部署完成!"echo"=========================================="echo""echo"查看状态:"echo"kubectl get pods -n amazon-cloudwatch"echo""echo"查看日志:"echo"kubectl logs -n amazon-cloudwatch -l k8s-app=fluent-bit --tail=30"

4.2 执行部署

chmod+x deploy-fluentbit.sh ./deploy-fluentbit.sh

4.3 验证部署

# 查看 Pod 状态(3 个节点都应该 Running)kubectl get pods-namazon-cloudwatch# 查看 Fluent Bit 日志kubectl logs-namazon-cloudwatch-lk8s-app=fluent-bit--tail=30

期望输出

  • 3 个 Pod 状态为Running
  • 日志显示[ info] [output:cloudwatch_logs][ info] [input:tail]

5. 第三步:创建 SNS 主题

5.1 创建 SNS 主题

aws sns create-topic\--name"K8s-DingTalk-Alarm"\--regionap-east-1

输出示例

{"TopicArn":"arn:aws:sns:ap-east-1:997836553899:K8s-DingTalk-Alarm"}

5.2 记录 Topic ARN

保存输出中的TopicArn,后续步骤需要用到。

6. 第四步:创建 Lambda 函数(钉钉通知)

6.1 在 AWS 控制台创建 Lambda

  1. 进入 Lambda → 创建函数
  2. 选择"从头开始创作"
  3. 函数名称:DingTalkNotifier
  4. 运行时:Python 3.9
  5. 点击"创建函数"

6.2 粘贴 Lambda 代码

importjsonimporturllib3importos http=urllib3.PoolManager()# 从环境变量读取 Webhook 地址WEBHOOK_URL=os.environ.get('WEBHOOK_URL')deflambda_handler(event,context):# 解析 SNS 消息try:sns_message=event['Records'][0]['Sns']['Message']alarm_data=json.loads(sns_message)exceptExceptionase:print(f"解析消息失败:{e}")return{"statusCode":400,"body":"Invalid message"}# 提取告警信息alarm_name=alarm_data.get('AlarmName','未知告警')alarm_state=alarm_data.get('NewStateValue','未知')alarm_reason=alarm_data.get('NewStateReason','无详细信息')timestamp=alarm_data.get('StateChangeTime','未知时间')# 构建钉钉消息(包含 ERROR 关键字,满足关键词安全策略)dingtalk_msg={"msgtype":"markdown","markdown":{"title":"🚨 K8s 日志告警","text":f""" ### 🚨 K8s 日志告警 - **告警名称**:{alarm_name}- **状态**: **{alarm_state}** - **时间**:{timestamp}- **详情**:{alarm_reason}> 关键字: ERROR """},"at":{"isAtAll":False}}try:response=http.request('POST',WEBHOOK_URL,body=json.dumps(dingtalk_msg).encode('utf-8'),headers={'Content-Type':'application/json'})print(f"钉钉响应状态:{response.status}")print(f"钉钉响应内容:{response.data}")return{"statusCode":response.status,"body":json.dumps({"message":"Message sent to DingTalk"})}exceptExceptionase:print(f"发送失败:{e}")return{"statusCode":500,"body":str(e)}

重要:粘贴后必须点击“Deploy”按钮保存。

6.3 配置环境变量

  1. Lambda → 配置 → 环境变量
  2. 添加环境变量:
    • WEBHOOK_URL
    • :你的钉钉机器人 Webhook 地址

6.4 添加 SNS 触发器

  1. 点击"添加触发器"
  2. 选择 “SNS”
  3. 选择现有主题K8s-DingTalk-Alarm
  4. 点击"添加"

7. 第五步:创建告警规则

7.1 创建告警脚本

创建create-alarm.sh

#!/bin/bash# create-alarm.sh - 创建 ERROR 日志告警LOG_GROUP="/aws/containerinsights/k8s/application"REGION="ap-east-1"SNS_TOPIC_ARN="arn:aws:sns:ap-east-1:997836553899:K8s-DingTalk-Alarm"echo"=========================================="echo"创建 CloudWatch 日志告警"echo"=========================================="# 1. 创建指标筛选器echo">>> 创建 ERROR 指标筛选器..."aws logs put-metric-filter\--log-group-name"$LOG_GROUP"\--filter-name"ErrorCount"\--filter-pattern"ERROR"\--metric-transformationsmetricName=ErrorCount,metricNamespace=K8sLogs,metricValue=1\--region$REGIONif[$?-eq0];thenecho"✅ 指标筛选器创建成功"elseecho"❌ 指标筛选器创建失败"fi# 2. 创建告警echo">>> 创建告警规则..."aws cloudwatch put-metric-alarm\--alarm-name"K8s-Error-DingTalk"\--alarm-description"当 5 分钟内 ERROR 日志超过 5 条时触发钉钉告警"\--metric-name"ErrorCount"\--namespace"K8sLogs"\--statistic"Sum"\--period300\--evaluation-periods1\--threshold5\--comparison-operator"GreaterThanThreshold"\--alarm-actions"$SNS_TOPIC_ARN"\--region$REGIONif[$?-eq0];thenecho"✅ 告警规则创建成功"elseecho"❌ 告警规则创建失败"fiecho"=========================================="echo"告警配置完成!"echo"=========================================="

7.2 执行告警创建

chmod+x create-alarm.sh ./create-alarm.sh

7.3 验证告警创建

# 验证指标筛选器aws logs describe-metric-filters\--log-group-name"/aws/containerinsights/k8s/application"\--filter-name-prefix"ErrorCount"\--regionap-east-1# 验证告警aws cloudwatch describe-alarms\--alarm-names"K8s-Error-DingTalk"\--regionap-east-1

8. 第六步:测试告警

8.1 生成 ERROR 日志

# 生成 6 条 ERROR 日志(超过阈值 5)foriin{1..6};dokubectl run test-error-$i--image=busybox--restart=Never--rm-it--sh-c"echo 'ERROR: test alarm message #$i'"2>/dev/null||truesleep2done

8.2 验证指标数据

aws cloudwatch get-metric-statistics\--namespaceK8sLogs\--metric-name ErrorCount\--start-time"$(date-u-d'10 minutes ago'+%Y-%m-%dT%H:%M:%SZ)"\--end-time"$(date-u+%Y-%m-%dT%H:%M:%SZ)"\--period300\--statisticsSum\--regionap-east-1

期望输出:返回Sum值大于 0

8.3 验证钉钉收到告警

等待 3-5 分钟,钉钉群应收到告警消息:

🚨 K8s 日志告警 - 告警名称: K8s-Error-DingTalk - 状态: ALARM - 时间: 2026-07-01T03:12:10.404+0000 - 详情: Threshold Crossed: 1 datapoint [26.0 ...] was greater than the threshold (5.0). 关键字: ERROR

9. Logs Insights 查询指南

9.1 查看所有日志流(了解有哪些服务)

SOURCE"/aws/containerinsights/k8s/application"|statscount()by@logStream|sort countdesc|limit50

9.2 查看特定服务日志

SOURCE"/aws/containerinsights/k8s/application"|filter@logStreamlike/gateway/|fields@timestamp,@message|sort@timestampdesc|limit100

9.3 查看 ERROR 日志

SOURCE"/aws/containerinsights/k8s/application"|filter@messagelike/ERROR/|fields@timestamp,@message,@logStream|sort@timestampdesc|limit100

9.4 查看特定命名空间日志

SOURCE"/aws/containerinsights/k8s/application"|filter@logStreamlike/k8s/|fields@timestamp,@message,@logStream|sort@timestampdesc|limit100

10. 常见问题与解决方案

10.1 IAM 权限问题

错误信息解决方案
User is not authorized to perform: SNS:CreateTopic添加AmazonSNSFullAccess策略到用户
User is not authorized to perform: logs:PutMetricFilter添加CloudWatchLogsFullAccess策略
User is not authorized to perform: cloudwatch:PutMetricAlarm添加CloudWatchFullAccess策略
User is not authorized to perform: cloudwatch:DescribeAlarms添加CloudWatchFullAccesscloudwatch:DescribeAlarms权限

10.2 Fluent Bit 部署问题

问题解决方案
ErrImagePull/ImagePullBackOff使用public.ecr.aws/aws-observability/aws-for-fluent-bit:3替代amazon/cloudwatch-agent:1.300042.0
could not allocate key value pairFluent Bit 5.x 配置语法更严格,使用简化配置(不带@INCLUDE的子配置文件)
could not get meta for POD这是控制平面节点的警告,不影响业务 Pod,可以忽略

10.3 CloudWatch 查询问题

错误信息解决方案
MalformedQueryException检查 Logs Insights 语法,使用filter @logStream like /xxx/而非filter @logStream = "xxx"
A log group must be selected在 Logs Insights 中选择正确的日志组
kubernetes.container_name字段为空使用@logStream替代,日志流名称已包含 Pod 和容器信息

10.4 钉钉告警问题

问题解决方案
钉钉收不到消息1. 检查 Lambda 是否被触发(查看调用次数)
2. 检查 Lambda 环境变量WEBHOOK_URL是否正确
3. 检查钉钉机器人关键词是否包含ERROR
Lambda 触发但钉钉无响应查看 Lambda CloudWatch 日志,检查urllib3错误
告警不触发1. 检查指标筛选器是否创建成功
2. 等待 3-5 分钟让数据聚合
3. 查看指标数据get-metric-statistics

11. 附录

11.1 环境变量汇总

变量
AWS_ACCOUNT_ID997836553899
AWS_REGIONap-east-1
CLUSTER_NAMEk8s
LOG_GROUP/aws/containerinsights/k8s/application
SNS_TOPIC_ARNarn:aws:sns:ap-east-1:997836553899:K8s-DingTalk-Alarm
IAM_ROLECloudWatchAgent-Role

11.2 关键命令速查

# 查看 Fluent Bit Podkubectl get pods-namazon-cloudwatch# 查看 Fluent Bit 日志kubectl logs-namazon-cloudwatch-lk8s-app=fluent-bit--tail=30# 重启 Fluent Bitkubectl rollout restart daemonset fluent-bit-namazon-cloudwatch# 查看告警状态aws cloudwatch describe-alarms --alarm-names"K8s-Error-DingTalk"--regionap-east-1# 查看指标数据aws cloudwatch get-metric-statistics--namespaceK8sLogs --metric-name ErrorCount --start-time"$(date-u-d'10 minutes ago'+%Y-%m-%dT%H:%M:%SZ)"--end-time"$(date-u+%Y-%m-%dT%H:%M:%SZ)"--period300--statisticsSum--regionap-east-1# 查看日志流aws logs describe-log-streams --log-group-name"/aws/containerinsights/k8s/application"--regionap-east-1 --max-items10

11.3 相关文档链接

  • CloudWatch Logs 文档
  • Fluent Bit Kubernetes 过滤器
  • CloudWatch Logs Insights 查询语法
  • 钉钉自定义机器人文档

12. 版本历史

版本日期作者变更说明
v1.02026-07-01-初始版本,基于实际部署经验整理

文档结束

如果有任何问题或需要补充的内容,请随时提出!📝

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 6:09:58

诊所备案哪家办理快?2026年深圳主流服务商盘点

诊所备案“快”的认知误区&#xff0c;你踩过几个&#xff1f; 在深圳开办诊所&#xff0c;“办理快”几乎是每个创业者打听的头号问题。深圳的商业租金不低&#xff0c;多等一天就是多一天成本。正因如此&#xff0c;围绕“快”这个字&#xff0c;市场上流传着不少似是而非的…

作者头像 李华
网站建设 2026/7/2 6:09:23

双非车辆工程硕士学编程日记第一篇

开这篇博客既是我的学习开篇&#xff0c;也是一份公开的成长规划。希望在这里记录从算法仿真到工程落地的完整学习路径&#xff0c;也能认识更多同方向的伙伴&#xff0c;互相交流、共同进步。一、关于我&#xff1a;车辆工程研二&#xff0c;研究人车共驾方向大家好&#xff0…

作者头像 李华
网站建设 2026/7/2 6:09:17

LangGraph与CrewAI实战:多智能体协同业务落地

一、前言&#xff1a;为什么要学习 LangGraph & CrewAI单智能体在复杂业务场景存在能力瓶颈&#xff0c;工单审批、需求拆解、调研分析等场景&#xff0c;往往需要多个智能体分工协作、自动流转完成完整业务链路&#xff0c;也就是多智能体协同架构。目前工业界最主流两套多…

作者头像 李华
网站建设 2026/7/2 6:07:43

终极ASMR下载器:从零开始构建你的专属放松音频库

终极ASMR下载器&#xff1a;从零开始构建你的专属放松音频库 【免费下载链接】asmr-downloader A tool for download asmr media from asmr.one(Thanks for the asmr.one) 项目地址: https://gitcode.com/gh_mirrors/as/asmr-downloader 你是否曾为了寻找特定的ASMR音频…

作者头像 李华
网站建设 2026/7/2 6:06:12

HarmonyOS路由跳转

一、代码展示二、代码用到的全部知识点分类1. 路由跳转核心&#xff08;页面导航&#xff09;路由模块导入 import router from ohos.router 所有页面跳转 API 都依赖这个系统模块&#xff0c;不导入无法使用pushUrl。router.pushUrl() 入栈跳转作用&#xff1a;打开新页面&…

作者头像 李华
网站建设 2026/7/2 6:05:57

《实体化的幽灵》

《实体化的幽灵》 第一章&#xff1a;校准 陆沉讨厌下雨天&#xff0c;因为潮湿会让仪器的读数产生漂移。 但在 2049 年的深秋&#xff0c;深圳湾的雨已经连续下了整整一周。空气中弥漫着臭氧和腐烂海草的混合气味。陆沉站在“灵境”实验室的中央&#xff0c;看着那个悬浮在空中…

作者头像 李华