Skip to content

Commit 549594b

Browse files
jakeskyawsjaksky
andauthored
feat: Add EventBridge lifecycle events for ECS Container Insights and update ADOT to CloudWatch Agent (#913)
Co-authored-by: jaksky <[email protected]>
1 parent 0a80256 commit 549594b

File tree

7 files changed

+101
-29
lines changed

7 files changed

+101
-29
lines changed

terraform/ecs/default/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ This section documents the variables and outputs of the Terraform configuration.
5050
| `environment_name` | Name of the environment which will be used for all resources created | `string` | `retail-store-ecs` | yes |
5151
| `opentelemetry_enabled` | Flag to enable OpenTelemetry, which will install the AWS Distro for OpenTelemetry and configure trace collection | `bool` | `false` | no |
5252
| `container_insights_setting` | Container Insights setting for ECS cluster. Must be either 'enhanced' or 'disabled'. When OpenTelemetry is enabled, defaults to 'enhanced' | `string` | `disabled` | no |
53+
| `lifecycle_events_enabled` | Enable ECS lifecycle events to CloudWatch Logs for Container Insights performance dashboard. Only available when container_insights_setting is 'enhanced' | `bool` | `false` | no |
5354
| `log_group_retention_days` | Number of days to retain logs in CloudWatch Log Groups | `number` | `30` | no |
5455

5556
### Outputs

terraform/ecs/default/main.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ module "retail_app_ecs" {
3737
container_image_overrides = var.container_image_overrides
3838
opentelemetry_enabled = var.opentelemetry_enabled
3939
container_insights_setting = var.container_insights_setting
40+
lifecycle_events_enabled = var.lifecycle_events_enabled
41+
4042

4143
catalog_db_endpoint = module.dependencies.catalog_db_endpoint
4244
catalog_db_port = module.dependencies.catalog_db_port

terraform/ecs/default/variables.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,15 @@ variable "container_insights_setting" {
3434
condition = contains(["enhanced", "disabled"], var.container_insights_setting)
3535
error_message = "container_insights_setting must be either 'enhanced' or 'disabled'"
3636
}
37+
}
38+
39+
variable "lifecycle_events_enabled" {
40+
type = bool
41+
default = false
42+
description = "Enable ECS lifecycle events to CloudWatch Logs"
43+
44+
validation {
45+
condition = !var.lifecycle_events_enabled || var.container_insights_setting == "enhanced"
46+
error_message = "lifecycle_events_enabled can only be true when container_insights_setting is 'enhanced'"
47+
}
3748
}

terraform/lib/ecs/eventbridge.tf

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
data "aws_caller_identity" "current" {}
2+
data "aws_region" "current" {}
3+
4+
resource "random_id" "eventbridge_suffix" {
5+
byte_length = 8
6+
}
7+
8+
resource "aws_cloudwatch_log_group" "ecs_container_insights" {
9+
count = (var.container_insights_setting == "enhanced" && var.lifecycle_events_enabled) ? 1 : 0
10+
name = "/aws/events/ecs/containerinsights/${var.environment_name}-cluster/performance"
11+
12+
tags = {
13+
ClusterName = "${var.environment_name}-cluster"
14+
"EventBridge-AssociatedRuleName" = "EventsToLogs-retail-${random_id.eventbridge_suffix.hex}"
15+
}
16+
}
17+
18+
resource "aws_cloudwatch_event_rule" "ecs_events" {
19+
count = (var.container_insights_setting == "enhanced" && var.lifecycle_events_enabled) ? 1 : 0
20+
name = "EventsToLogs-retail-${random_id.eventbridge_suffix.hex}"
21+
description = "This rule is used to export to CloudWatch Logs the lifecycle events of the ECS Cluster ${var.environment_name}-cluster."
22+
23+
event_pattern = jsonencode({
24+
source = ["aws.ecs"]
25+
detail = {
26+
clusterArn = ["arn:aws:ecs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:cluster/${var.environment_name}-cluster"]
27+
}
28+
})
29+
}
30+
31+
resource "aws_cloudwatch_event_target" "ecs_events_target" {
32+
count = (var.container_insights_setting == "enhanced" && var.lifecycle_events_enabled) ? 1 : 0
33+
rule = aws_cloudwatch_event_rule.ecs_events[0].name
34+
target_id = random_id.eventbridge_suffix.hex
35+
arn = aws_cloudwatch_log_group.ecs_container_insights[0].arn
36+
}
37+
38+
resource "aws_cloudwatch_log_resource_policy" "eventbridge_ecs" {
39+
count = (var.container_insights_setting == "enhanced" && var.lifecycle_events_enabled) ? 1 : 0
40+
policy_name = "EventBridge-ECS-ContainerInsights"
41+
policy_document = jsonencode({
42+
Version = "2012-10-17"
43+
Statement = [
44+
{
45+
Effect = "Allow"
46+
Principal = {
47+
Service = "events.amazonaws.com"
48+
}
49+
Action = [
50+
"logs:CreateLogStream",
51+
"logs:PutLogEvents"
52+
]
53+
Resource = "${aws_cloudwatch_log_group.ecs_container_insights[0].arn}:*"
54+
}
55+
]
56+
})
57+
}

terraform/lib/ecs/service/ecs.tf

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,22 @@ locals {
8282
}
8383

8484
otel_container = {
85-
name = "aws-otel-collector"
86-
image = "public.ecr.aws/aws-observability/aws-otel-collector:latest"
85+
name = "cloudwatch-agent"
86+
image = "public.ecr.aws/cloudwatch-agent/cloudwatch-agent:latest"
8787
essential = true
88-
command = ["--config=/etc/ecs/container-insights/otel-task-metrics-config.yaml"]
88+
environment = [
89+
{
90+
name = "CW_CONFIG_CONTENT"
91+
value = jsonencode({
92+
agent = {}
93+
traces = {
94+
traces_collected = {
95+
otlp = {}
96+
}
97+
}
98+
})
99+
}
100+
]
89101
portMappings = [
90102
{
91103
containerPort = 4318
@@ -97,7 +109,7 @@ locals {
97109
options = {
98110
"awslogs-group" = var.cloudwatch_logs_group_id
99111
"awslogs-region" = data.aws_region.current.name
100-
"awslogs-stream-prefix" = "otel-collector"
112+
"awslogs-stream-prefix" = "cloudwatch-agent"
101113
}
102114
}
103115
}

terraform/lib/ecs/service/iam.tf

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ resource "aws_iam_role_policy_attachment" "cloudwatch_logs" {
6666
policy_arn = aws_iam_policy.cloudwatch_logs.arn
6767
}
6868

69-
resource "aws_iam_policy" "adot_collector" {
69+
resource "aws_iam_policy" "cloudwatch_agent" {
7070
count = var.opentelemetry_enabled ? 1 : 0
71-
name = "${var.environment_name}-${var.service_name}-adot-collector"
72-
description = "ADOT Collector policy for ${var.service_name}"
71+
name = "${var.environment_name}-${var.service_name}-cloudwatch-agent"
72+
description = "CloudWatch Agent policy for ${var.service_name}"
7373
tags = var.tags
7474

7575
policy = jsonencode({
@@ -79,10 +79,7 @@ resource "aws_iam_policy" "adot_collector" {
7979
Effect = "Allow"
8080
Action = [
8181
"xray:PutTraceSegments",
82-
"xray:PutTelemetryRecords",
83-
"xray:GetSamplingRules",
84-
"xray:GetSamplingTargets",
85-
"xray:GetSamplingStatisticSummaries"
82+
"xray:PutTelemetryRecords"
8683
]
8784
Resource = "*"
8885
},
@@ -93,35 +90,21 @@ resource "aws_iam_policy" "adot_collector" {
9390
"logs:CreateLogStream",
9491
"logs:CreateLogGroup",
9592
"logs:DescribeLogStreams",
96-
"logs:DescribeLogGroups",
97-
"logs:PutRetentionPolicy"
93+
"logs:DescribeLogGroups"
9894
]
9995
Resource = [
10096
"arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:${var.cloudwatch_logs_group_id}:*",
101-
"arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:${var.cloudwatch_logs_group_id}:log-stream:*",
102-
"arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:/aws/ecs/containerinsights/${var.environment_name}*:*"
97+
"arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:${var.cloudwatch_logs_group_id}:log-stream:*"
10398
]
104-
},
105-
{
106-
Effect = "Allow"
107-
Action = [
108-
"cloudwatch:PutMetricData",
109-
"ec2:DescribeVolumes",
110-
"ec2:DescribeTags",
111-
"ecs:ListClusters",
112-
"ecs:ListContainerInstances",
113-
"ecs:DescribeContainerInstances"
114-
]
115-
Resource = "*"
11699
}
117100
]
118101
})
119102
}
120103

121-
resource "aws_iam_role_policy_attachment" "adot_collector" {
104+
resource "aws_iam_role_policy_attachment" "cloudwatch_agent" {
122105
count = var.opentelemetry_enabled ? 1 : 0
123106
role = aws_iam_role.task_role.name
124-
policy_arn = aws_iam_policy.adot_collector[0].arn
107+
policy_arn = aws_iam_policy.cloudwatch_agent[0].arn
125108
}
126109

127110
resource "aws_iam_role_policy_attachment" "task_role_additional" {

terraform/lib/ecs/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,9 @@ variable "container_insights_setting" {
141141
error_message = "container_insights_setting must be either 'enhanced' or 'disabled'"
142142
}
143143
}
144+
145+
variable "lifecycle_events_enabled" {
146+
type = bool
147+
default = false
148+
description = "Enable ECS lifecycle events to CloudWatch Logs"
149+
}

0 commit comments

Comments
 (0)