实时 ALB 日志分析用于通过 Datadog 监控、工作流和 AWS Lambda 实现主动集成恢复
Source: Dev.to
问题
- 剧情: Google Calendar 事件让我们抓狂,而且我们根本不知道是哪位用户受到了影响。
- 原因: 错误大多与“消失”的渠道或无法到达 API 的事件有关。
- 最糟糕的部分: 我们的 ELB/ALB 没有访问日志,导致我们对情况一无所知。
合理的思路
为什么不打开访问日志呢?既然已经在使用 Datadog,我决定把 ALB/ELB 的访问日志也导入 Datadog。
本项目使用 Pulumi 构建,但别担心——我们可以把它加进去。如果你还没接触过 Pulumi,可以先阅读它的文档。Pulumi 让你使用同一套库/工具管理多个提供商的基础设施即代码(IaC),类似 Terraform,但使用 TypeScript。
添加 ALB/ELB 访问日志
什么是访问日志?
访问日志 是负载均衡器上所有操作的纸质记录。每条日志包含:
- 请求到达的时间(时间戳)
- 客户端 IP 地址
- 请求的 URL
- 响应状态码(例如
200、404) - 请求延迟
- 处理该请求的目标实例 ID
Pulumi 示例:全新创建 ALB/ELB
下面是一个最小化的 Pulumi 示例,创建 ALB、目标组、监听器以及监听器规则。(在原项目中 ALB 已经存在,这里演示如何从零开始创建。)
创建 ALB
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
const mainAlb = new awsx.lb.ApplicationLoadBalancer("main-alb", {
name: "main-alb",
subnetIds: vpc.publicSubnetIds,
securityGroups: [securityGroup.id],
internal: false,
accessLogs: {
bucket: lbLogs.id,
prefix: "access-logs-lb",
enabled: true,
},
tags: {
stage: environment,
managed: "true",
},
});
创建目标组
const webhooksTargetGroup = new aws.lb.TargetGroup("webhooks-tg", {
port: 80,
protocol: "HTTP",
targetType: "ip",
vpcId: vpc.vpcId,
healthCheck: {
enabled: true,
healthyThreshold: 2,
unhealthyThreshold: 2,
interval: 10,
path: "/api/v1/health-check",
port: "traffic-port",
},
});
HTTPS 监听器
// HTTPS listener
const httpsListener = new aws.lb.Listener("httpsListener", {
loadBalancerArn: mainAlb.loadBalancer.arn,
port: 443,
protocol: "HTTPS",
defaultActions: [{
type: "fixed-response",
fixedResponse: {
contentType: "text/plain",
statusCode: "404",
messageBody: "Not Found",
},
}],
sslPolicy: "ELBSecurityPolicy-2016-08",
certificateArn: myCertificateArn,
});
// Additional certificates
new aws.lb.ListenerCertificate("webhooks-attachment", {
listenerArn: httpsListener.arn,
certificateArn: webhooksCertificateArn,
});
监听器规则
new aws.lb.ListenerRule("rule-webhooks", {
listenerArn: httpsListener.arn,
priority: 3,
actions: [{ type: "forward", targetGroupArn: webhooksTargetGroup.arn }],
conditions: [{ hostHeader: { values: [`webhooks.${route53ZoneName}`] } }],
});
Pulumi 示例:已存在的 ALB/ELB
如果负载均衡器已经存在,只需为日志创建 S3 桶并在 ALB 上启用日志功能。
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// 1. 创建用于 ALB 访问日志的 S3 桶
const albAccessLogsBucket = new aws.s3.Bucket("alb-access-logs", {
bucket: `alb-access-logs.${environment}.us-east-1.careops`,
acl: "private",
});
// 允许 ELB 写入日志的桶策略
new aws.s3.BucketPolicy("albLogsBucketPolicy", {
bucket: albAccessLogsBucket.id,
policy: albAccessLogsBucket.arn.apply(bucketArn => JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Allow",
Principal: { AWS: "arn:aws:iam::127311923021:root" }, // us-east-1 区域的 ELB 服务账号
Action: ["s3:PutObject", "s3:GetBucketAcl"],
Resource: [bucketArn, `${bucketArn}/*`],
}],
})),
});
// 2. 在 ALB 上启用访问日志
new aws.lb.LoadBalancerAttributes("mainAlbAccessLogs", {
loadBalancerArn: mainAlb.loadBalancer.arn,
attributes: [
{ key: "access_logs.s3.enabled", value: "true" },
{ key: "access_logs.s3.bucket", value: albAccessLogsBucket.bucket },
{ key: "access_logs.s3.prefix", value: "main-alb/" },
],
});
现在你已经拥有一个用于存放 ALB/ELB 流量日志的 S3 桶。
注意: ELB 会每 5 分钟为每个负载均衡器节点生成一个日志文件。交付是最终一致的,在高流量情况下,同一时间段可能会生成多个日志文件。
日志文件的命名模式如下:
bucket[/prefix]/AWSLogs/aws-account-id/elasticloadbalancing/region/yyyy/mm/dd/
aws-account-id_elasticloadbalancing_region_app.load-balancer-id_end-time_ip-address_random-string.log.gz
示例:
s3://amzn-s3-demo-logging-bucket/logging-prefix/AWSLogs/123456789012/elasticloadbalancing/us-east-2/2022/05/01/
123456789012_elasticloadbalancing_us-east-2_app.my-loadbalancer.1234567890abcdef_20220215T2340Z_172.160.001.192_20sg8hgm.log.gz
将日志转发到 Datadog
要把日志发送到 Datadog,需要一个 Lambda 函数来处理 S3 桶中新对象的事件,并将日志转发到 Datadog API。
// 3. 部署 Datadog Forwarder Lambda(使用 AWS SAM/CloudFormation 或手动部署)
// 对于 Pulumi,你可以使用 aws.cloudformation.Stack 或直接部署 Lambda
const datadogForwarder = new aws.lambda.Function("datadogForwarder", {
runtime: aws.lambda.Runtime.Python39,
handler: "lambda_function.lambda_handler",
role: datadogForwarderRole.arn,
code: new pulumi.asset.AssetArchive({
".": new pulumi.asset.FileArchive("./datadog-forwarder"),
}),
environment: {
variables: {
DD_API_KEY_SECRET_ARN: datadogApiKeySecret.arn,
DD_SITE: "datadoghq.com",
DD_TAGS: `env:${environment}`,
},
},
});
// 4. 配置 S3 事件通知,在新日志到达时触发 Lambda
new aws.s3.BucketNotification("albLogsNotification", {
bucket: albAccessLogsBucket.id,
lambdaFunctions: [{
lambdaFunctionArn: datadogForwarder.arn,
events: ["s3:ObjectCreated:*"],
filterPrefix: "access-logs-lb/",
}],
});
有了上述配置,每当新的访问日志文件落入 S3 桶时,Lambda 就会把它转发到 Datadog,随后你可以在 Datadog 中创建监控、仪表盘以及自动化恢复工作流。