使用AWS FireLens输出日志时,可以查看附加到日志上的Amazon ECS元数据
什么?
据说,使用在Amazon ECS上可用的日志驱动程序AWS FireLens可以为Amazon ECS元数据添加标记。
我想确认一下这个内容。
使用AWS FireLens时产生的元数据
使用AWS FireLens时附加的元数据,请参考以下文档。
创建使用FireLens配置的任务定义/ 使用Amazon ECS元数据。
在任务定义中,如果将要用作AWS FireLens的容器的enable-ecs-log-metadata设置为true,则会在日志中添加以下字段。
-
- ecs_cluster – タスクが所属するクラスターの名前。
-
- ecs_task_arn – コンテナが所属するタスクの完全な ARN。
- ecs_task_definition – タスクが使用しているタスク定義名とリビジョン。
这是Amazon ECS的元数据。
我們這次想親自看看這個內容。
: “请用中文翻译以下内容,只需要一个选项:”
(Note: The provided text is not clear and does not have a specific meaning. It seems like a request for translation, but there is no content mentioned. Therefore, the Chinese paraphrase focuses on clarifying the request itself.)
无论如何,由于我们需要使用Amazon ECS,所以这次我想要构建一个使用nginx容器的AWS Fargate集群。
我打算尝试 AWS Fargate 的两种任务定义。
-
- nginxコンテナのみをタスク定義に含め、ログはawslogsログドライバーを使用してAmazon CloudWatch Logsに出力
- nginxコンテナおよびAWS for Fluent Bitコンテナを使い、nginxのログはfirelensログドライバーを使用してAmazon CloudWatch Logsに出力
在这里,我们将使用Terraform来构建整个环境。
环境
这次的环境是这个。
$ terraform version
Terraform v0.14.7
+ provider registry.terraform.io/hashicorp/aws v3.29.0
另外,假设AWS凭证已经通过环境变量进行了设置。
$ export AWS_ACCESS_KEY_ID=...
$ export AWS_SECRET_ACCESS_KEY=...
$ export AWS_DEFAULT_REGION=ap-northeast-1
进行AWS Fargate集群的资源定义。
那么,让我们开始构建AWS Fargate集群吧。
我们将使用Terraform进行部署,但这次我们将把所有内容都写在一个main.tf文件中。
首先,指定Terraform和Provider的版本。
terraform {
required_version = "0.14.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = "3.29.0"
}
}
}
provider "aws" {
}
我需要VPC和ALB等其他部分,但我打算先介绍AWS Fargate,然后在最后整理其他内容。
尽管如此,由于创建AWS Fargate还依赖于这些资源,因此我们会事先将这些部分整理到本地变量中。
locals {
vpc_id = module.vpc.vpc_id
private_subnets = module.vpc.private_subnets
nginx_service_security_groups = [module.nginx_service_sg.this_security_group_id]
load_balancer_target_group_arn = module.load_balancer.target_group_arns[0]
nginx_simple_container_definition = # nginxのみのタスク定義
nginx_with_fluentbit_container_definitions = # nginx+Fluent Bitのコンテナ定義
}
以下是被注释掉的部分,用于定义任务所使用的容器。这次,我们希望切换这两个定义并进行部署。
让我们放上到任务定义为止的部分。
任务用角色和任务执行用角色。
data "aws_iam_policy_document" "ecs_assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
data "aws_iam_policy" "ecs_task_execution_role_policy" {
arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
resource "aws_iam_role" "ecs_task_execution_role" {
name = "MyEcsTaskExecutionRole"
assume_role_policy = data.aws_iam_policy_document.ecs_assume_role.json
}
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy_attachment" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = data.aws_iam_policy.ecs_task_execution_role_policy.arn
}
data "aws_iam_policy_document" "ecs_task_role_policy_document" {
statement {
effect = "Allow"
actions = [
"logs:DescribeLogStreams",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
resources = ["*"]
}
}
resource "aws_iam_policy" "ecs_task_role_policy" {
name = "MyEcsTaskPolicy"
policy = data.aws_iam_policy_document.ecs_task_role_policy_document.json
}
resource "aws_iam_role" "ecs_task_role" {
name = "MyEcsTaskRole"
assume_role_policy = data.aws_iam_policy_document.ecs_assume_role.json
}
resource "aws_iam_role_policy_attachment" "ecs_task_role_policy_attachment" {
role = aws_iam_role.ecs_task_role.name
policy_arn = aws_iam_policy.ecs_task_role_policy.arn
}
在任务卷中,我们预先授予了与Amazon CloudWatch Logs相关的权限,以便AWS for Fluent Bit能够将日志输出到Amazon CloudWatch Logs。
Amazon CloudWatch Logs是每个容器的日志输出目标。
AWS Fargate的集群定义。
resource "aws_cloudwatch_log_group" "nginx" {
name = "/fargate/containers/nginx"
}
resource "aws_cloudwatch_log_group" "fluentbit" {
name = "/fargate/containers/fluentbit"
}
resource "aws_ecs_cluster" "nginx" {
name = "nginx-cluster"
}
resource "aws_ecs_task_definition" "nginx" {
family = "nginx-task-definition"
cpu = "512"
memory = "1024"
network_mode = "awsvpc"
requires_compatibilities = [
"FARGATE"]
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
task_role_arn = aws_iam_role.ecs_task_role.arn
container_definitions = local.nginx_simple_container_definition
# container_definitions = local.nginx_with_fluentbit_container_definitions
}
resource "aws_ecs_service" "nginx" {
name = "nginx-service"
cluster = aws_ecs_cluster.nginx.arn
task_definition = aws_ecs_task_definition.nginx.arn
desired_count = 3
launch_type = "FARGATE"
platform_version = "1.4.0"
deployment_minimum_healthy_percent = 50
network_configuration {
assign_public_ip = false
security_groups = local.nginx_service_security_groups
subnets = local.private_subnets
}
load_balancer {
target_group_arn = local.load_balancer_target_group_arn
container_name = "nginx"
container_port = 80
}
}
接下来,我们将切换到 container_definitions 的部分。
resource "aws_ecs_task_definition" "nginx" {
family = "nginx-task-definition"
cpu = "512"
memory = "1024"
network_mode = "awsvpc"
requires_compatibilities = [
"FARGATE"]
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
task_role_arn = aws_iam_role.ecs_task_role.arn
container_definitions = local.nginx_simple_container_definition
# container_definitions = local.nginx_with_fluentbit_container_definitions
}
尝试在没有AWS FireLens的情况下进行构建
首先,让我们尝试在没有AWS FireLens的情况下进行构建。
以下是用于任务定义的容器定义。
nginx_simple_container_definition = <<JSON
[
{
"name": "nginx",
"image": "nginx:1.19.7",
"essential": true,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 80
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${aws_cloudwatch_log_group.nginx.name}",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "nginx-log-stream"
}
}
}
]
JSON
非常简单。日志输出目标为Amazon CloudWatch Logs,并指定了先前定义的日志组。
那么,在任务定义中指定此容器定义
resource "aws_ecs_task_definition" "nginx" {
family = "nginx-task-definition"
cpu = "512"
memory = "1024"
network_mode = "awsvpc"
requires_compatibilities = [
"FARGATE"]
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
task_role_arn = aws_iam_role.ecs_task_role.arn
container_definitions = local.nginx_simple_container_definition
# container_definitions = local.nginx_with_fluentbit_container_definitions
}
申请。
$ terraform apply
以tail的方式监听日志组并等待
$ aws logs tail --follow /fargate/containers/nginx
当集群构建并启动容器后,尝试使用curl进行访问。
$ curl [ALBのDNS名]
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
生成的日志如下所示。
*已更改访问来源的IP地址。
2021-02-22T12:47:34.424000+00:00 nginx-log-stream/nginx/df733e0802104d3890ebaad461c8d7cf 10.0.10.209 - - [22/Feb/2021:12:47:34 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:35.754000+00:00 nginx-log-stream/nginx/df733e0802104d3890ebaad461c8d7cf 10.0.10.209 - - [22/Feb/2021:12:47:35 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:37.315000+00:00 nginx-log-stream/nginx/df733e0802104d3890ebaad461c8d7cf 10.0.10.209 - - [22/Feb/2021:12:47:37 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:41.261000+00:00 nginx-log-stream/nginx/163a9d4c115f4951b5cac39ef16fe60e 10.0.10.209 - - [22/Feb/2021:12:47:41 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:43.301000+00:00 nginx-log-stream/nginx/df733e0802104d3890ebaad461c8d7cf 10.0.10.209 - - [22/Feb/2021:12:47:43 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:45.343000+00:00 nginx-log-stream/nginx/df733e0802104d3890ebaad461c8d7cf 10.0.10.209 - - [22/Feb/2021:12:47:45 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:47.377000+00:00 nginx-log-stream/nginx/163a9d4c115f4951b5cac39ef16fe60e 10.0.10.209 - - [22/Feb/2021:12:47:47 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:49.408000+00:00 nginx-log-stream/nginx/df733e0802104d3890ebaad461c8d7cf 10.0.10.209 - - [22/Feb/2021:12:47:49 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:51.435000+00:00 nginx-log-stream/nginx/7b8175f48e1244f1a41912f4af179129 10.0.10.209 - - [22/Feb/2021:12:47:51 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:53.196000+00:00 nginx-log-stream/nginx/df733e0802104d3890ebaad461c8d7cf 10.0.10.209 - - [22/Feb/2021:12:47:53 +0000] "GET / HTTP/1.1" 200 612 "-" "ELB-HealthChecker/2.0" "-"
2021-02-22T12:47:53.196000+00:00 nginx-log-stream/nginx/7b8175f48e1244f1a41912f4af179129 10.0.10.209 - - [22/Feb/2021:12:47:53 +0000] "GET / HTTP/1.1" 200 612 "-" "ELB-HealthChecker/2.0" "-"
2021-02-22T12:47:53.468000+00:00 nginx-log-stream/nginx/163a9d4c115f4951b5cac39ef16fe60e 10.0.10.209 - - [22/Feb/2021:12:47:53 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:55.500000+00:00 nginx-log-stream/nginx/163a9d4c115f4951b5cac39ef16fe60e 10.0.10.209 - - [22/Feb/2021:12:47:55 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
2021-02-22T12:47:57.541000+00:00 nginx-log-stream/nginx/7b8175f48e1244f1a41912f4af179129 10.0.10.209 - - [22/Feb/2021:12:47:57 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
提取作为记录的值,大致如下。
10.0.10.209 - - [22/Feb/2021:12:47:34 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" "aaa.bbb.ccc.ddd"
我已经确认了日志的格式,所以我将销毁资源。
$ terraform destroy
通过AWS FireLens输出日志
接下来,让我们通过AWS FireLens来输出日志。
AWS Fargate的任务定义如下所示。
resource "aws_ecs_task_definition" "nginx" {
family = "nginx-task-definition"
cpu = "512"
memory = "1024"
network_mode = "awsvpc"
requires_compatibilities = [
"FARGATE"]
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
task_role_arn = aws_iam_role.ecs_task_role.arn
# container_definitions = local.nginx_simple_container_definition
container_definitions = local.nginx_with_fluentbit_container_definitions
}
我们可以参考实际的container_definitions定义(容器定义),因为可以设置是否附加Amazon ECS元数据,所以我们可以在两种情况下进行确认。
有Amazon ECS元数据标记。
以下是为Amazon ECS附加元数据的容器定义。这里包括了AWS for Fluent Bit和nginx的两个容器定义。
nginx_with_fluentbit_container_definitions = <<JSON
[
{
"name": "log_router",
"image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:2.10.1",
"essential": true,
"firelensConfiguration": {
"type": "fluentbit",
"options":{
"enable-ecs-log-metadata": "true"
}
},
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${aws_cloudwatch_log_group.fluentbit.name}",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "fluentbit-log-stream"
}
}
},
{
"name": "nginx",
"image": "nginx:1.19.7",
"essential": true,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 80
}
],
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Name": "cloudwatch",
"region": "ap-northeast-1",
"log_group_name": "${aws_cloudwatch_log_group.nginx.name}",
"log_stream_prefix": "nginx-log-stream-",
"auto_create_group": "false"
}
}
}
]
JSON
在firelensConfiguration的选项设置中,将enable-ecs-log-metadata设置为true。这样,通过AWS FireLens输出的日志将附带Amazon ECS的元数据。这是默认设置。
"firelensConfiguration": {
"type": "fluentbit",
"options":{
"enable-ecs-log-metadata": "true"
}
},
所以,以下的方式也是同义词对吧。
"firelensConfiguration": {
"type": "fluentbit"
},
以当前状态进行申请。
$ terraform apply
与之前相同,我们会在构建资源之后使用curl命令对日志组进行tail并进行访问尝试。
$ aws logs tail --follow /fargate/containers/nginx
以下是可获取的日志。
2021-02-22T13:01:17.712000+00:00 nginx-log-stream-nginx-firelens-d90128b0816e4a38b34888f721bf60fb {"container_id":"d90128b0816e4a38b34888f721bf60fb-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:17 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:19.759000+00:00 nginx-log-stream-nginx-firelens-d90128b0816e4a38b34888f721bf60fb {"container_id":"d90128b0816e4a38b34888f721bf60fb-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:19 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:20.292000+00:00 nginx-log-stream-nginx-firelens-d90128b0816e4a38b34888f721bf60fb {"container_id":"d90128b0816e4a38b34888f721bf60fb-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:20 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"ELB-HealthChecker/2.0\" \"-\"","source":"stdout"}
2021-02-22T13:01:21.790000+00:00 nginx-log-stream-nginx-firelens-e07924a4952c4e36844603a88819b4ce {"container_id":"e07924a4952c4e36844603a88819b4ce-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/e07924a4952c4e36844603a88819b4ce","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:21 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:23.825000+00:00 nginx-log-stream-nginx-firelens-d90128b0816e4a38b34888f721bf60fb {"container_id":"d90128b0816e4a38b34888f721bf60fb-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:23 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:25.862000+00:00 nginx-log-stream-nginx-firelens-d90128b0816e4a38b34888f721bf60fb {"container_id":"d90128b0816e4a38b34888f721bf60fb-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:25 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:27.899000+00:00 nginx-log-stream-nginx-firelens-d90128b0816e4a38b34888f721bf60fb {"container_id":"d90128b0816e4a38b34888f721bf60fb-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:27 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:29.937000+00:00 nginx-log-stream-nginx-firelens-e07924a4952c4e36844603a88819b4ce {"container_id":"e07924a4952c4e36844603a88819b4ce-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/e07924a4952c4e36844603a88819b4ce","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:29 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:31.975000+00:00 nginx-log-stream-nginx-firelens-e07924a4952c4e36844603a88819b4ce {"container_id":"e07924a4952c4e36844603a88819b4ce-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/e07924a4952c4e36844603a88819b4ce","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:31 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:34.013000+00:00 nginx-log-stream-nginx-firelens-d6bcefeb9a014f17bc444b18f2f0d487 {"container_id":"d6bcefeb9a014f17bc444b18f2f0d487-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d6bcefeb9a014f17bc444b18f2f0d487","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:34 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:36.049000+00:00 nginx-log-stream-nginx-firelens-e07924a4952c4e36844603a88819b4ce {"container_id":"e07924a4952c4e36844603a88819b4ce-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/e07924a4952c4e36844603a88819b4ce","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:36 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:38.093000+00:00 nginx-log-stream-nginx-firelens-d6bcefeb9a014f17bc444b18f2f0d487 {"container_id":"d6bcefeb9a014f17bc444b18f2f0d487-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d6bcefeb9a014f17bc444b18f2f0d487","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:38 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:01:40.308000+00:00 nginx-log-stream-nginx-firelens-d6bcefeb9a014f17bc444b18f2f0d487 {"container_id":"d6bcefeb9a014f17bc444b18f2f0d487-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d6bcefeb9a014f17bc444b18f2f0d487","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:40 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"ELB-HealthChecker/2.0\" \"-\"","source":"stdout"}
2021-02-22T13:01:40.313000+00:00 nginx-log-stream-nginx-firelens-d90128b0816e4a38b34888f721bf60fb {"container_id":"d90128b0816e4a38b34888f721bf60fb-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:40 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"ELB-HealthChecker/2.0\" \"-\"","source":"stdout"}
2021-02-22T13:01:42.168000+00:00 nginx-log-stream-nginx-firelens-d6bcefeb9a014f17bc444b18f2f0d487 {"container_id":"d6bcefeb9a014f17bc444b18f2f0d487-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d6bcefeb9a014f17bc444b18f2f0d487","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:42 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
刚才和之前相比,日志的格式发生了变化。
让我们提取并格式化一行。
$ echo '{"container_id":"d90128b0816e4a38b34888f721bf60fb-2531612879","container_name":"nginx","ecs_cluster":"nginx-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb","ecs_task_definition":"nginx-task-definition:8","log":"10.0.10.190 - - [22/Feb/2021:13:01:17 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}' | jq
{
"container_id": "d90128b0816e4a38b34888f721bf60fb-2531612879",
"container_name": "nginx",
"ecs_cluster": "nginx-cluster",
"ecs_task_arn": "arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task/nginx-cluster/d90128b0816e4a38b34888f721bf60fb",
"ecs_task_definition": "nginx-task-definition:8",
"log": "10.0.10.190 - - [22/Feb/2021:13:01:17 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"",
"source": "stdout"
}
日志已变为JSON格式,并增加了6个字段:container_id、 container_name、ecs_cluster、ecs_task_arn、ecs_task_definition、source。
原始的日志存储在日志字段中。
嗯?不管来源如何,赋予的字段应该有三个吧?试着关闭Amazon ECS元数据的赋予来确认一下。
顺便提一下,AWS for Fluent Bit自身的日志只是简单地通过awslogs输出到Amazon CloudWatch Logs,所以如果不使用AWS FireLens,就和之前一样(因此省略不赘述)。
释放资源。
$ terraform destroy
没有为Amazon ECS附加元数据
我尝试从之前的容器定义中更改,以便不将Amazon ECS元数据添加进去。
nginx_with_fluentbit_container_definitions = <<JSON
[
{
"name": "log_router",
"image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:2.10.1",
"essential": true,
"firelensConfiguration": {
"type": "fluentbit",
"options":{
"enable-ecs-log-metadata": "false"
}
},
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${aws_cloudwatch_log_group.fluentbit.name}",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "fluentbit-log-stream"
}
}
},
{
"name": "nginx",
"image": "nginx:1.19.7",
"essential": true,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 80
}
],
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Name": "cloudwatch",
"region": "ap-northeast-1",
"log_group_name": "${aws_cloudwatch_log_group.nginx.name}",
"log_stream_prefix": "nginx-log-stream-",
"auto_create_group": "false"
}
}
}
]
JSON
变更的是
"firelensConfiguration": {
"type": "fluentbit",
"options":{
"enable-ecs-log-metadata": "false"
}
},
以此状态申请
$ terraform apply
和之前一样,在构建资源之后,我们将使用curl访问并同时tail日志组。
$ aws logs tail --follow /fargate/containers/nginx
这是获得的日志。
2021-02-22T13:39:14.048000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:14 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:16.090000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:16 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:18.137000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:18 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:20.287000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:20 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:22.330000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:22 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:24.369000+00:00 nginx-log-stream-nginx-firelens-9e9a09f1b8924ce3926c7c6653bd3ec1 {"container_id":"9e9a09f1b8924ce3926c7c6653bd3ec1-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:24 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:26.408000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:26 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:28.447000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:28 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:28.483000+00:00 nginx-log-stream-nginx-firelens-9e9a09f1b8924ce3926c7c6653bd3ec1 {"container_id":"9e9a09f1b8924ce3926c7c6653bd3ec1-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:28 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"ELB-HealthChecker/2.0\" \"-\"","source":"stdout"}
2021-02-22T13:39:28.485000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:28 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"ELB-HealthChecker/2.0\" \"-\"","source":"stdout"}
2021-02-22T13:39:28.485000+00:00 nginx-log-stream-nginx-firelens-e0f54e9a04cd4d59be03b4ae47c6c690 {"container_id":"e0f54e9a04cd4d59be03b4ae47c6c690-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:28 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"ELB-HealthChecker/2.0\" \"-\"","source":"stdout"}
2021-02-22T13:39:30.488000+00:00 nginx-log-stream-nginx-firelens-9e9a09f1b8924ce3926c7c6653bd3ec1 {"container_id":"9e9a09f1b8924ce3926c7c6653bd3ec1-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:30 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:32.530000+00:00 nginx-log-stream-nginx-firelens-37d9cebd8fbb4d57bd7fa646323e501a {"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:32 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
2021-02-22T13:39:34.569000+00:00 nginx-log-stream-nginx-firelens-9e9a09f1b8924ce3926c7c6653bd3ec1 {"container_id":"9e9a09f1b8924ce3926c7c6653bd3ec1-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:34 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}
我会提取一行文本,然后按照先前的方式进行整理。
$ echo '{"container_id":"37d9cebd8fbb4d57bd7fa646323e501a-2531612879","container_name":"nginx","log":"10.0.10.227 - - [22/Feb/2021:13:39:14 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"","source":"stdout"}' | jq
{
"container_id": "37d9cebd8fbb4d57bd7fa646323e501a-2531612879",
"container_name": "nginx",
"log": "10.0.10.227 - - [22/Feb/2021:13:39:14 +0000] \"GET / HTTP/1.1\" 200 612 \"-\" \"curl/7.68.0\" \"aaa.bbb.ccc.ddd\"",
"source": "stdout"
}
即使将Amazon ECS的元数据附加关闭,通过AWS FireLens,容器ID和容器名称仍会被添加。
总结
整理以下结果
-
- AWS FireLensを通してログ出力すると、JSON形式になり、少なくともcontainer_id、container_nameおよびログの出力元(sourceが追加される)
enable-ecs-log-metadataをtrueにすると、ecs_cluster、ecs_task_arn、ecs_task_definitionの3つが追加される(これはデフォルトの動作)
那就是這樣嗎。 (Nà ma.)
如果只是将Amazon ECS的日志保存在Amazon CloudWatch Logs中,那么查看资源定义就可以知道哪个任务将日志保存在哪个日志组中,所以可能并没有太大意义。
如果要将此日志进一步汇总到其他地方,这些元数据将变得有效。
给予的额外福利
我将列出包括了之前省略的VPC、ALB等的整体资源定义。
terraform {
required_version = "0.14.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = "3.29.0"
}
}
}
provider "aws" {
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "2.71.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
azs = ["ap-northeast-1a", "ap-northeast-1c"]
public_subnets = ["10.0.10.0/24", "10.0.20.0/24"]
private_subnets = ["10.0.30.0/24", "10.0.40.0/24"]
map_public_ip_on_launch = false
enable_nat_gateway = true
single_nat_gateway = false
one_nat_gateway_per_az = false
}
module "load_balancer_sg" {
source = "terraform-aws-modules/security-group/aws//modules/http-80"
version = "3.18.0"
name = "load-balancer-sg"
vpc_id = module.vpc.vpc_id
ingress_cidr_blocks = ["0.0.0.0/0"]
}
module "nginx_service_sg" {
source = "terraform-aws-modules/security-group/aws"
version = "3.18.0"
name = "nginx-service-sg"
vpc_id = module.vpc.vpc_id
ingress_with_cidr_blocks = [
{
from_port = 80
to_port = 80
protocol = "tcp"
description = "nginx-service inbound ports"
cidr_blocks = "10.0.10.0/24"
},
{
from_port = 80
to_port = 80
protocol = "tcp"
description = "nginx-service inbound ports"
cidr_blocks = "10.0.20.0/24"
}
]
egress_with_cidr_blocks = [
{
from_port = 0
to_port = 0
protocol = "-1"
description = "nginx-service outbound ports"
cidr_blocks = "0.0.0.0/0"
}
]
}
module "load_balancer" {
source = "terraform-aws-modules/alb/aws"
version = "5.11.0"
name = "nginx-alb"
vpc_id = module.vpc.vpc_id
load_balancer_type = "application"
internal = false
subnets = module.vpc.public_subnets
security_groups = [module.load_balancer_sg.this_security_group_id]
target_groups = [
{
backend_protocol = "HTTP"
backend_port = 80
target_type = "ip"
health_check = {
interval = 20
}
}
]
http_tcp_listeners = [
{
port = 80
protocol = "HTTP"
}
]
}
locals {
vpc_id = module.vpc.vpc_id
private_subnets = module.vpc.private_subnets
nginx_service_security_groups = [module.nginx_service_sg.this_security_group_id]
load_balancer_target_group_arn = module.load_balancer.target_group_arns[0]
nginx_simple_container_definition = <<JSON
[
{
"name": "nginx",
"image": "nginx:1.19.7",
"essential": true,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 80
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${aws_cloudwatch_log_group.nginx.name}",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "nginx-log-stream"
}
}
}
]
JSON
nginx_with_fluentbit_container_definitions = <<JSON
[
{
"name": "log_router",
"image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:2.10.1",
"essential": true,
"firelensConfiguration": {
"type": "fluentbit",
"options":{
"enable-ecs-log-metadata": "true"
}
},
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${aws_cloudwatch_log_group.fluentbit.name}",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "fluentbit-log-stream"
}
}
},
{
"name": "nginx",
"image": "nginx:1.19.7",
"essential": true,
"portMappings": [
{
"protocol": "tcp",
"containerPort": 80
}
],
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Name": "cloudwatch",
"region": "ap-northeast-1",
"log_group_name": "${aws_cloudwatch_log_group.nginx.name}",
"log_stream_prefix": "nginx-log-stream-",
"auto_create_group": "false"
}
}
}
]
JSON
}
data "aws_iam_policy_document" "ecs_assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
data "aws_iam_policy" "ecs_task_execution_role_policy" {
arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
resource "aws_iam_role" "ecs_task_execution_role" {
name = "MyEcsTaskExecutionRole"
assume_role_policy = data.aws_iam_policy_document.ecs_assume_role.json
}
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy_attachment" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = data.aws_iam_policy.ecs_task_execution_role_policy.arn
}
data "aws_iam_policy_document" "ecs_task_role_policy_document" {
statement {
effect = "Allow"
actions = [
"logs:DescribeLogStreams",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
resources = ["*"]
}
}
resource "aws_iam_policy" "ecs_task_role_policy" {
name = "MyEcsTaskPolicy"
policy = data.aws_iam_policy_document.ecs_task_role_policy_document.json
}
resource "aws_iam_role" "ecs_task_role" {
name = "MyEcsTaskRole"
assume_role_policy = data.aws_iam_policy_document.ecs_assume_role.json
}
resource "aws_iam_role_policy_attachment" "ecs_task_role_policy_attachment" {
role = aws_iam_role.ecs_task_role.name
policy_arn = aws_iam_policy.ecs_task_role_policy.arn
}
resource "aws_cloudwatch_log_group" "nginx" {
name = "/fargate/containers/nginx"
}
resource "aws_cloudwatch_log_group" "fluentbit" {
name = "/fargate/containers/fluentbit"
}
resource "aws_ecs_cluster" "nginx" {
name = "nginx-cluster"
}
resource "aws_ecs_task_definition" "nginx" {
family = "nginx-task-definition"
cpu = "512"
memory = "1024"
network_mode = "awsvpc"
requires_compatibilities = [
"FARGATE"]
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
task_role_arn = aws_iam_role.ecs_task_role.arn
# container_definitions = local.nginx_simple_container_definition
container_definitions = local.nginx_with_fluentbit_container_definitions
}
resource "aws_ecs_service" "nginx" {
name = "nginx-service"
cluster = aws_ecs_cluster.nginx.arn
task_definition = aws_ecs_task_definition.nginx.arn
desired_count = 3
launch_type = "FARGATE"
platform_version = "1.4.0"
deployment_minimum_healthy_percent = 50
network_configuration {
assign_public_ip = false
security_groups = local.nginx_service_security_groups
subnets = local.private_subnets
}
load_balancer {
target_group_arn = local.load_balancer_target_group_arn
container_name = "nginx"
container_port = 80
}
}
output "alb_arn" {
value = module.load_balancer.this_lb_arn
}
output "alb_dns_name" {
value = module.load_balancer.this_lb_dns_name
}