背景
AWS Elastic Container Service (ECS) 提供了一种简单的方式来管理部署在容器内的微服务的日志。它与 CloudWatch 日志无缝集成,运行在 ECS Fargate 上的容器会将它们的标准输出直接导入 CloudWatch 日志。这主要得益于 awslogs 日志驱动程序的实现,并且完全由 AWS 管理。
虽然 CloudWatch 对大多数用例来说是一个合适的选择,但在某些场景下,使用第三方的日志收集工具可能更为适合,例如:
- 将日志采集至 ELK(Elasticsearch、Logstash、Kibana)以实现日志聚合和分析;
- 提供比 CloudWatch 更强大的搜索和溯源功能;
- 避免 CloudWatch 的高昂费用,尤其是在服务数量增加后,每月的成本会显著上升;
理解 ECS 使用 FireLens & Fluent Bit 的原理
在将容器内的日志采集至 ELK,我们面临的一个挑战是如何将日志流式传输到 ELK 中,一个可选的方案是使用 Fluent Bit 作为日志路由工具。
Fluent Bit 是一个轻量级的日志收集代理,其核心功能是从容器中收集日志消息并将其流式传输到指定的存储。它提供了一系列插件,几乎可以与所有主流的日志聚合器无缝集成。此外,Fluent Bit 能够从多种来源和多种格式收集日志,并可以对这些消息进行转换,实现生产者服务和消费者之间的无缝衔接。
Fluent Bit 完成支持 AWS ECS Fargate,同时,AWS 提供了 FireLens 日志驱动来简化了 ECS 与 Fluent Bit 的集成。也就是说,我们可以通过 FireLens 日志驱动来指定集成 Fluentd 还是 Fluent Bit。
AWS 提供的 Fluent Bit Docker 日志驱动程序通过 Unix 套接字或 TCP 套接字统一接收容器的标准输出日志。出于性能考虑,默认使用 Unix 套接字,因为其传输速度更快、性能更高。此外,部署在 FireLens 容器中的 Fluent Bit 还会监听 TCP 套接字(默认端口:24224,需确保在内网环境中可访问),以接收基于 Fluent Forward 协议的日志消息。这些消息可以由应用程序通过 Fluent Logger Libraries 发送到 Fluent Bit。
Fluent Bit 在接收日志后,能够根据配置对日志进行处理和路由,将其转发到指定的日志存储或分析系统,也就是上图中管到流的流程。在 Fluent Bit 中,日志处理的管理顺序是固定的,无论配置文件中各部分的排列顺序如何,这种实现更有利于我们自定义日志源、过滤器等。
在 ECS 中,Fluent Bit 默认会进行处理以下处理:
- 接收日志;
- 往日志中新增ECS 元数据;
- 执行用户自定义的配置;
- 根据任务定义里面的配置进行日志路由;
针对以上的 Fluent Bit 会执行用户自定义的配置,这个也是我们可以自定义日志解析、过滤,新增或者重命名字段等自定义处理,我们的 Java 堆栈异常解析也是基于该特点来集成的。
ECS Fargate 集成 Fluent Bit
在 ECS 上集成 Fluent Bit,我们需要通过创建或变更任务定义,任务定义包括了容器运行所需要的参数,同时,也包括了服务、Fluent Bit 镜像地址的配置。AWS 提供了 FireLens 来集成 Fluent Bit,那么,该 Fluent Bit 是作为 Sidecar containers 的存在。
Sidecar Containers 是围绕着主容器运行的第二个容器,它被用来加强或者扩展主容器的功能,比如可以提供附加的服务、日志、监控、安全等,不需要直接修改主容器的应用的代码。
日志收集配置
在任务定义中,更改日志收集配置,使用 AWS FireLens 将日志导出到 FireHose,如下:
{
"containerDefinitions": [
{
"name": "your project",
"image": "your docker image",
"essential": true,
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"delivery_stream": "test-app-logs",
"time_key_format": "%Y-%m-%dT%H:%M:%S.%3NZ",
"region": "us-east-1",
"Name": "kinesis_firehose",
"time_key": "@timestamp"
},
"secretOptions": []
}
}
...
]
}
以上的配置主要是通过 Fluent Bit 提供的 Amazon Kinesis Data Firehose 实现的,针对以上的参数主要作用如下:
| Key | Description |
|---|---|
| Name | 固定值:kinesis_firehose,插件的名称 |
| region | The AWS Region |
| delivery_stream | Firehose 的流名称 |
| time_key | 将时间戳添加到此键下的记录中。默认情况下,Fluent Bit 的时间戳不会添加到发送到 Kinesis 的记录中。 |
| time_key_format | strftime 兼容的时间戳格式字符串;例如,默认为"%Y-%m-%dT%H:%M:%S"。使用"%3N "支持毫秒精度,使用"%9N "和"%L "支持纳秒精度;例如,添加"%3N "支持毫秒"%Y-%m-%dT%H:%M:%S.%3N"。该选项与 time_key 一起使用。 |
以上配置了 time_key,也就是在 Fluent Bit 会把当前时间戳添加 Firehose 的记录中。
日志路由容器 FireLens 配置
日志路由容器配置主要配置aws-for-fluent-bit的镜像,自定义fluent bit的配置文件配置,最终的任务定义配置如下:
{
...
{
"name": "log_router",
"image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:init-2.32.5",
"cpu": 0,
"memoryReservation": 51,
"portMappings": [],
"essential": false,
"environment": [
{
"name": "aws_fluent_bit_init_s3_1",
"value": "arn:aws:s3:::yourBucket/aaaaa.conf"
},
{
"name": "aws_fluent_bit_init_s3_2",
"value": "arn:aws:s3:::yourBucket/bbbbb.conf"
}
],
"firelensConfiguration": {
"type": "fluentbit"
}
}
]
...
}
配置 FireLens 支持的日志路由类别,也就是配置使用 Fluent Bit 的容器,注意,主要容器需要选择为否,以作为 Sidecar Container 运行。接着就是设置映像 URI,我们可以先通过 aws-for-fluent-bit 了解镜像的使用注意事项。
通过以上版本信息得知,选用指定版本 tag 的 stable 版本是推荐的,适用于线上环境。但我们使用的是 init-2.32.5 版本,这是出于什么考虑呢?
主要是因为我们需要自定义 fluent-bit 配置以实现自定义日志解析,开放监控等,那么,我们可以通过将配置文件放在 S3 或者打包时复制到 Docker 容器内,同时,配置文件的管理也需要兼顾可维护性,与现有的应用容器尽量解耦,因此,我们这边优先选择把配置文件放在 S3,AWS 也提供了相关的支持。可以通过 Amazon ECS 任务定义示例:将日志路由到 FireLens 查看具体实现,如通过在任务定义中新增 config-file-type 与 config-file-value 两个配置项实现,如下:
但是,上图也标识了 AWS Fargate 上的任务仅支持
file 配置文件类型,后续,在 AWS firelens config missing options for S3 and path · Issue #946 找到了解决方案,如下:
也就是说,官方提供了 init tag 的容器来解决 AWS Fargate 无法支持配置 S3 文件类型的问题。通过 using-the-init-tag 的使用指引只需两步不就可以实现,步骤如下:
- 使用
aws-for-fluent-bit的init版本的镜像; - 在 FireLens 的环境变量中配置 S3 文件的 ARN;
- 以上配置使用了 Firehose 以及 S3,因此我们需要为 ECS Task Role 授予以下权限:
"firehose:PutRecordBatch",
"firehose:PutRecord",
"s3:GetBucketLocation",
"s3:GetObject"
Fluent Bit 内存限制配置
在日志路由模块,我们还需要配置 Fluent Bit 的 CPU 和内存的限制,主要也是避免 Fluent Bit 占用过多的 CPU 和内存资源,导致主应用容器资源不足,进而影响应用的性能和稳定性。关于 Fluent Bit 的 CPU 和内存限制,前期可以先通过官方的建议来进行估算(官方作为压测,具体可以参考:Under the hood: FireLens for Amazon ECS Tasks)。
最后
通过本文的介绍,我们探讨了如何在 AWS ECS Fargate 上使用 Fluent Bit 进行自定义日志收集和路由。Fluent Bit 不仅能够高效地将日志路由到多种存储系统(如 ELK、Kinesis Firehose 等),还支持与 Prometheus 集成,实现日志和监控数据的统一管理。此外,Fluent Bit 提供了丰富的插件和过滤器,支持日志的解析、转换和增强,能够满足复杂的日志处理需求。
Fluent Bit 的日志路由只是其强大功能的一部分,它还支持多种输入输出插件、数据缓冲、重试机制等特性,能够应对高吞吐量和复杂的日志处理场景。未来,随着微服务和云原生技术的进一步发展,Fluent Bit 将在日志管理、监控和数据分析领域发挥更大的作用。