实时 ALB 日志分析用于通过 Datadog 监控、工作流和 AWS Lambda 实现主动集成恢复

发布: (2025年12月8日 GMT+8 11:22)
5 min read
原文: Dev.to

Source: Dev.to

问题

  • 剧情: Google Calendar 事件让我们抓狂,而且我们根本不知道是哪位用户受到了影响。
  • 原因: 错误大多与“消失”的渠道或无法到达 API 的事件有关。
  • 最糟糕的部分: 我们的 ELB/ALB 没有访问日志,导致我们对情况一无所知。

合理的思路

为什么不打开访问日志呢?既然已经在使用 Datadog,我决定把 ALB/ELB 的访问日志也导入 Datadog。

本项目使用 Pulumi 构建,但别担心——我们可以把它加进去。如果你还没接触过 Pulumi,可以先阅读它的文档。Pulumi 让你使用同一套库/工具管理多个提供商的基础设施即代码(IaC),类似 Terraform,但使用 TypeScript。

添加 ALB/ELB 访问日志

什么是访问日志?

访问日志 是负载均衡器上所有操作的纸质记录。每条日志包含:

  • 请求到达的时间(时间戳)
  • 客户端 IP 地址
  • 请求的 URL
  • 响应状态码(例如 200404
  • 请求延迟
  • 处理该请求的目标实例 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 中创建监控、仪表盘以及自动化恢复工作流。

Back to Blog

相关文章

阅读更多 »