AWS Fargateで、タスク定義にAWS FireLensを含めると思わぬ差分が出るという話

# What's？

AWS FireLens＋Fluent Bitを組み込んだAWS FargateクラスターをTerraformで構成した時に、タスク定義で`terraform plan`時に妙に差分が出てきて困ったという話。

なお、原因は不明です。


# お題

Terraformで、AWS Fargateクラスターを構築します。

タスク定義に含めるコンテナは、nginxとしましょう。

最初はnginxのみのタスク定義とし、あとでFluent Bit（AWS for Fluent Bit）も追加します。

この時の`terraform plan`の挙動を見てみます。


# 環境

今回の環境は、こちら。

```shell
$ terraform version
Terraform v0.13.5
+ provider registry.terraform.io/hashicorp/aws v3.15.0


$ aws --version
aws-cli/2.1.1 Python/3.7.3 Linux/5.4.0-53-generic exe/x86_64.ubuntu.20
```

AWSのクレデンシャルは、環境変数で指定しています。

```shell
$ export AWS_ACCESS_KEY_ID=.....
$ export AWS_SECRET_ACCESS_KEY=.....
$ export AWS_DEFAULT_REGION=.....
```


# AWS Fargateのタスク定義を行う（nginxのみ）

ここからは、AWS Fargateクラスターを構築していきますが、タスク定義と補足的なリソースのみを最初に記載します。

リソース定義全体は、最後に載せます。

最初に、nginxのみを含めたタスクを定義します。

```terraform
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 = <<JSON
  [
    {
      "name": "nginx",
      "image": "nginx:1.19.4",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/nginx",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "nginx"
        }
      }
    }
  ]
  JSON
}
```

とってもシンプル。

ログは、Amazon CloudWatch Logsに出力するようにしています。あとでAWS FireLensも使うので、ここまでをミニマムとします。

```terraform
resource "aws_cloudwatch_log_group" "nginx" {
  name = "/fargate/containers/nginx"
}
```

`apply`。

```shell
$ terraform apply
```

動作確認。

```shell
$ curl -i [ALBのDNS名]
HTTP/1.1 200 OK
Date: Sun, 15 Nov 2020 03:32:23 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Server: nginx/1.19.4
Last-Modified: Tue, 27 Oct 2020 15:09:20 GMT
ETag: "5f983820-264"
Accept-Ranges: bytes

<!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>
```

ここで、`terraform plan`を実行してみます。

```shell
$ terraform plan
```

リソースを構築したばかりですし、定義の変更も行っていないので特に差分はありません。

```shell
No changes. Infrastructure is up-to-date.
```

`terraform show`を実行して

```shell
$ terraform show
```

タスク定義の部分を見てみます。

```shell
# aws_ecs_task_definition.nginx:
resource "aws_ecs_task_definition" "nginx" {
    arn                      = "arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task-definition/nginx-task-definition:37"
    container_definitions    = jsonencode(
        [
            {
                cpu              = 0
                environment      = []
                essential        = true
                image            = "nginx:1.19.4"
                logConfiguration = {
                    logDriver = "awslogs"
                    options   = {
                        awslogs-group         = "/fargate/containers/nginx"
                        awslogs-region        = "ap-northeast-1"
                        awslogs-stream-prefix = "nginx"
                    }
                }
                mountPoints      = []
                name             = "nginx"
                portMappings     = [
                    {
                        containerPort = 80
                        hostPort      = 80
                        protocol      = "tcp"
                    },
                ]
                volumesFrom      = []
            },
        ]
    )
    cpu                      = "512"
    execution_role_arn       = "arn:aws:iam::[AWSアカウントID]:role/MyEcsTaskExecutionRole"
    family                   = "nginx-task-definition"
    id                       = "nginx-task-definition"
    memory                   = "1024"
    network_mode             = "awsvpc"
    requires_compatibilities = [
        "FARGATE",
    ]
    revision                 = 37
    task_role_arn            = "arn:aws:iam::[AWSアカウントID]:role/MyEcsTaskRole"
}
```

JSONに書いていなかった部分も、デフォルト値が入っています。

ここまで確認したら、いったん`terraform destroy`。

```shell
$ terraform destroy
```


# AWS Fargateのタスク定義を行う（nginx＋AWS for Fluent Bit）

続いて、今度はAWS FireLensを使ったログ出力を行います。

AWSのドキュメントを見ながら、

[カスタムログルーティング](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/using_firelens.html)

先ほどのタスク定義にAWS FireLensおよびAWS for Fluent Bitの設定を追加します。

```terraform
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 = <<JSON
  [
    {
      "name": "log_router",
      "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
      "essential": true,
      "firelensConfiguration": {
        "type": "fluentbit"
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/fluentbit",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "fluentbit"
        }
      }
    },
    {
      "name": "nginx",
      "image": "nginx:1.19.4",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "logConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
          "Name": "cloudwatch",
          "region": "ap-northeast-1",
          "log_group_name": "/fargate/containers/nginx",
          "log_stream_prefix": "nginx",
          "auto_create_group": "false"
        }
      }
    }
  ]
  JSON
}
```

nginxのログは、AWS FireLensを介してAmazon CloudWatch Logsに出力するようにします。

Fluent Bit用のロググループも作成。

```terraform
resource "aws_cloudwatch_log_group" "fluentbit" {
  name = "/fargate/containers/fluentbit"
}
```

タスクロールには、Fluent BitがAmazon CloudWatch Logsにログを出力できるように権限を追加しておきます。

```terraform
data "aws_iam_policy_document" "ecs_task_role_policy_document" {
  statement {
    effect = "Allow"

    actions = [
      "logs:DescribeLogStreams",
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:PutLogEvents"
    ]

    resources = ["*"]
  }
}
```

リソース構築。

```shell
$ terraform apply
```

動作確認。

```shell
$ curl -i [ALBのDNS名]
HTTP/1.1 200 OK
Date: Sun, 15 Nov 2020 03:41:51 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Server: nginx/1.19.4
Last-Modified: Tue, 27 Oct 2020 15:09:20 GMT
ETag: "5f983820-264"
Accept-Ranges: bytes

<!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>
```

ここまではOKです。

で、この状態で`terraform plan`を実行すると

```shell
$ terraform plan
```

なにも変更していませんが、差分が検出されます。

```shell
------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # aws_ecs_service.nginx will be updated in-place
  ~ resource "aws_ecs_service" "nginx" {
        cluster                            = "arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:cluster/nginx-cluster"
        deployment_maximum_percent         = 200
        deployment_minimum_healthy_percent = 50
        desired_count                      = 3
        enable_ecs_managed_tags            = false
        health_check_grace_period_seconds  = 0
        iam_role                           = "aws-service-role"
        id                                 = "arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:service/nginx-cluster/nginx-service"
        launch_type                        = "FARGATE"
        name                               = "nginx-service"
        platform_version                   = "1.4.0"
        propagate_tags                     = "NONE"
        scheduling_strategy                = "REPLICA"
        tags                               = {}
      ~ task_definition                    = "arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task-definition/nginx-task-definition:38" -> (known after apply)
        wait_for_steady_state              = false

        deployment_controller {
            type = "ECS"
        }

        load_balancer {
            container_name   = "nginx"
            container_port   = 80
            target_group_arn = "arn:aws:elasticloadbalancing:ap-northeast-1:[AWSアカウントID]:targetgroup/tf-20201115034033903500000005/31aa063424fafa30"
        }

        network_configuration {
            assign_public_ip = false
            security_groups  = [
                "sg-0bdd096a03b3467ab",
            ]
            subnets          = [
                "subnet-07ca48860443af5f7",
                "subnet-0aa3ac7b0fcf82b5e",
            ]
        }
    }

  # aws_ecs_task_definition.nginx must be replaced
-/+ resource "aws_ecs_task_definition" "nginx" {
      ~ arn                      = "arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task-definition/nginx-task-definition:38" -> (known after apply)
      ~ container_definitions    = jsonencode(
          ~ [ # forces replacement
              ~ {
                  - cpu                   = 0 -> null
                  - environment           = [] -> null
                    essential             = true
                    firelensConfiguration = {
                        type = "fluentbit"
                    }
                    image                 = "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest"
                    logConfiguration      = {
                        logDriver = "awslogs"
                        options   = {
                            awslogs-group         = "/fargate/containers/fluentbit"
                            awslogs-region        = "ap-northeast-1"
                            awslogs-stream-prefix = "fluentbit"
                        }
                    }
                  - mountPoints           = [] -> null
                    name                  = "log_router"
                  - portMappings          = [] -> null
                  - user                  = "0" -> null
                  - volumesFrom           = [] -> null
                } # forces replacement,
              ~ {
                  - cpu              = 0 -> null
                  - environment      = [] -> null
                    essential        = true
                    image            = "nginx:1.19.4"
                    logConfiguration = {
                        logDriver = "awsfirelens"
                        options   = {
                            Name              = "cloudwatch"
                            auto_create_group = "false"
                            log_group_name    = "/fargate/containers/nginx"
                            log_stream_prefix = "nginx"
                            region            = "ap-northeast-1"
                        }
                    }
                  - mountPoints      = [] -> null
                    name             = "nginx"
                  ~ portMappings     = [
                      ~ {
                            containerPort = 80
                          - hostPort      = 80 -> null
                            protocol      = "tcp"
                        },
                    ]
                  - volumesFrom      = [] -> null
                } # forces replacement,
            ]
        )
        cpu                      = "512"
        execution_role_arn       = "arn:aws:iam::[AWSアカウントID]:role/MyEcsTaskExecutionRole"
        family                   = "nginx-task-definition"
      ~ id                       = "nginx-task-definition" -> (known after apply)
        memory                   = "1024"
        network_mode             = "awsvpc"
        requires_compatibilities = [
            "FARGATE",
        ]
      ~ revision                 = 38 -> (known after apply)
      - tags                     = {} -> null
        task_role_arn            = "arn:aws:iam::[AWSアカウントID]:role/MyEcsTaskRole"
    }

Plan: 1 to add, 1 to change, 1 to destroy.

------------------------------------------------------------------------
```

コンテナ定義の、デフォルト値まわりが軒並み指摘されているように見えます。

```shell
      ~ container_definitions    = jsonencode(
          ~ [ # forces replacement
              ~ {
                  - cpu                   = 0 -> null
                  - environment           = [] -> null
                    essential             = true
                    firelensConfiguration = {
                        type = "fluentbit"
                    }
                    image                 = "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest"
                    logConfiguration      = {
                        logDriver = "awslogs"
                        options   = {
                            awslogs-group         = "/fargate/containers/fluentbit"
                            awslogs-region        = "ap-northeast-1"
                            awslogs-stream-prefix = "fluentbit"
                        }
                    }
                  - mountPoints           = [] -> null
                    name                  = "log_router"
                  - portMappings          = [] -> null
                  - user                  = "0" -> null
                  - volumesFrom           = [] -> null
                } # forces replacement,
              ~ {
                  - cpu              = 0 -> null
                  - environment      = [] -> null
                    essential        = true
                    image            = "nginx:1.19.4"
                    logConfiguration = {
                        logDriver = "awsfirelens"
                        options   = {
                            Name              = "cloudwatch"
                            auto_create_group = "false"
                            log_group_name    = "/fargate/containers/nginx"
                            log_stream_prefix = "nginx"
                            region            = "ap-northeast-1"
                        }
                    }
                  - mountPoints      = [] -> null
                    name             = "nginx"
                  ~ portMappings     = [
                      ~ {
                            containerPort = 80
                          - hostPort      = 80 -> null
                            protocol      = "tcp"
                        },
                    ]
                  - volumesFrom      = [] -> null
                } # forces replacement,
            ]
        )
```

`terraform show`で見てみても

```shell
$ terraform show
```

nginx単体の時とそんなに変わった気はしないんですけどねぇ…。

```shell
# aws_ecs_task_definition.nginx:
resource "aws_ecs_task_definition" "nginx" {
    arn                      = "arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task-definition/nginx-task-definition:38"
    container_definitions    = jsonencode(
        [
            {
                cpu                   = 0
                environment           = []
                essential             = true
                firelensConfiguration = {
                    type = "fluentbit"
                }
                image                 = "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest"
                logConfiguration      = {
                    logDriver = "awslogs"
                    options   = {
                        awslogs-group         = "/fargate/containers/fluentbit"
                        awslogs-region        = "ap-northeast-1"
                        awslogs-stream-prefix = "fluentbit"
                    }
                }
                mountPoints           = []
                name                  = "log_router"
                portMappings          = []
                user                  = "0"
                volumesFrom           = []
            },
            {
                cpu              = 0
                environment      = []
                essential        = true
                image            = "nginx:1.19.4"
                logConfiguration = {
                    logDriver = "awsfirelens"
                    options   = {
                        Name              = "cloudwatch"
                        auto_create_group = "false"
                        log_group_name    = "/fargate/containers/nginx"
                        log_stream_prefix = "nginx"
                        region            = "ap-northeast-1"
                    }
                }
                mountPoints      = []
                name             = "nginx"
                portMappings     = [
                    {
                        containerPort = 80
                        hostPort      = 80
                        protocol      = "tcp"
                    },
                ]
                volumesFrom      = []
            },
        ]
    )
    cpu                      = "512"
    execution_role_arn       = "arn:aws:iam::[AWSアカウントID]:role/MyEcsTaskExecutionRole"
    family                   = "nginx-task-definition"
    id                       = "nginx-task-definition"
    memory                   = "1024"
    network_mode             = "awsvpc"
    requires_compatibilities = [
        "FARGATE",
    ]
    revision                 = 38
    task_role_arn            = "arn:aws:iam::[AWSアカウントID]:role/MyEcsTaskRole"
}
```

仕方がないので、指摘されていたデフォルト値を全部埋めてあげると

```terraform
  container_definitions = <<JSON
  [
    {
      "name": "log_router",
      "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
      "essential": true,
      "firelensConfiguration": {
        "type": "fluentbit"
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/fluentbit",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "fluentbit"
        }
      },
      "cpu": 0,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": [],
      "portMappings": [],
      "user": "0"
    },
    {
      "name": "nginx",
      "image": "nginx:1.19.4",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 80,
          "hostPort": 80
        }
      ],
      "logConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
          "Name": "cloudwatch",
          "region": "ap-northeast-1",
          "log_group_name": "/fargate/containers/nginx",
          "log_stream_prefix": "nginx",
          "auto_create_group": "false"
        }
      },
      "cpu": 0,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": []
    }
  ]
  JSON
```

`plan`で差分が出なくなります。

```shell
$ terraform plan
```

どうなってるんでしょうね？

```shell
No changes. Infrastructure is up-to-date.
```

ちなみに、（まったく意味がないですが）Fluent Bitをタスク定義に入れてもAWS FireLensとして構成していない場合は差分が検出されません。

```terraform
  container_definitions = <<JSON
  [
    {
      "name": "log_router",
      "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
      "essential": true,
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/fluentbit",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "fluentbit"
        }
      }
    },
    {
      "name": "nginx",
      "image": "nginx:1.19.4",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/nginx",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "nginx"
        }
      }
    }
  ]
  JSON
```

`terraform show`で、タスク定義の状態を見てみます。

```shell
# aws_ecs_task_definition.nginx:
resource "aws_ecs_task_definition" "nginx" {
    arn                      = "arn:aws:ecs:ap-northeast-1:[AWSアカウントID]:task-definition/nginx-task-definition:39"
    container_definitions    = jsonencode(
        [
            {
                cpu              = 0
                environment      = []
                essential        = true
                image            = "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest"
                logConfiguration = {
                    logDriver = "awslogs"
                    options   = {
                        awslogs-group         = "/fargate/containers/fluentbit"
                        awslogs-region        = "ap-northeast-1"
                        awslogs-stream-prefix = "fluentbit"
                    }
                }
                mountPoints      = []
                name             = "log_router"
                portMappings     = []
                volumesFrom      = []
            },
            {
                cpu              = 0
                environment      = []
                essential        = true
                image            = "nginx:1.19.4"
                logConfiguration = {
                    logDriver = "awslogs"
                    options   = {
                        awslogs-group         = "/fargate/containers/nginx"
                        awslogs-region        = "ap-northeast-1"
                        awslogs-stream-prefix = "nginx"
                    }
                }
                mountPoints      = []
                name             = "nginx"
                portMappings     = [
                    {
                        containerPort = 80
                        hostPort      = 80
                        protocol      = "tcp"
                    },
                ]
                volumesFrom      = []
            },
        ]
    )
    cpu                      = "512"
    execution_role_arn       = "arn:aws:iam::[AWSアカウントID]:role/MyEcsTaskExecutionRole"
    family                   = "nginx-task-definition"
    id                       = "nginx-task-definition"
    memory                   = "1024"
    network_mode             = "awsvpc"
    requires_compatibilities = [
        "FARGATE",
    ]
    revision                 = 39
    task_role_arn            = "arn:aws:iam::[AWSアカウントID]:role/MyEcsTaskRole"
}
```

AWS FireLensとして構成した時と比べて、`firelensConfiguration`とかログ出力定義とかに差分があるのはもちろんなのですが。

AWS FireLensとして構成した場合は、Fluent Bitコンテナに以下の値が追加されています。

```
      "user": "0"
```

なにか、差分になる理由があるんでしょうね…。

`user`を`0`に指定しているということは、UIDを指定していることになると思うのですが。

[タスク定義パラメータ](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html)

AWS FireLensが関係しそうだということはわかったのですが、今回はこれ以上追わないことにします。


# リソース定義全体

最後に、ここまでのリソース定義全体を載せておきます。

VPCからALB、AWS Fargateのクラスターやサービス定義などを含め、ここまで登場したタスク定義のJSONについてはコメントで残しています。

有効にして残しているのは、AWS FireLensを使いつつ`plan`で差分が出ないパターンですね。

`main.tf`

```terraform
terraform {
  required_version = "0.13.5"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.15.0"
    }
  }
}

provider "aws" {
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.64.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 = true

  enable_nat_gateway     = true
  single_nat_gateway     = false
  one_nat_gateway_per_az = true
}

module "load_balancer_sg" {
  source  = "terraform-aws-modules/security-group/aws//modules/http-80"
  version = "3.16.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.16.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.9.0"

  name = "nginx"

  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]
}

data "aws_iam_policy_document" "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.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.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 = <<JSON
  [
    {
      "name": "log_router",
      "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
      "essential": true,
      "firelensConfiguration": {
        "type": "fluentbit"
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/fluentbit",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "fluentbit"
        }
      },
      "cpu": 0,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": [],
      "portMappings": [],
      "user": "0"
    },
    {
      "name": "nginx",
      "image": "nginx:1.19.4",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 80,
          "hostPort": 80
        }
      ],
      "logConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
          "Name": "cloudwatch",
          "region": "ap-northeast-1",
          "log_group_name": "/fargate/containers/nginx",
          "log_stream_prefix": "nginx",
          "auto_create_group": "false"
        }
      },
      "cpu": 0,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": []
    }
  ]
  JSON

  /*
  container_definitions = <<JSON
  [
    {
      "name": "log_router",
      "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
      "essential": true,
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/fluentbit",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "fluentbit"
        }
      }
    },
    {
      "name": "nginx",
      "image": "nginx:1.19.4",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/nginx",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "nginx"
        }
      }
    }
  ]
  JSON
  */

  /*
  container_definitions = <<JSON
  [
    {
      "name": "log_router",
      "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest",
      "essential": true,
      "firelensConfiguration": {
        "type": "fluentbit"
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/fluentbit",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "fluentbit"
        }
      }
    },
    {
      "name": "nginx",
      "image": "nginx:1.19.4",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "logConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
          "Name": "cloudwatch",
          "region": "ap-northeast-1",
          "log_group_name": "/fargate/containers/nginx",
          "log_stream_prefix": "nginx",
          "auto_create_group": "false"
        }
      }
    }
  ]
  JSON
  */

  /*
  container_definitions = <<JSON
  [
    {
      "name": "nginx",
      "image": "nginx:1.19.4",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/fargate/containers/nginx",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "nginx"
        }
      }
    }
  ]
  JSON
  */
}

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
  }
}
```