Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32106296
D15490.1765014208.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
31 KB
Referenced Files
None
Subscribers
None
D15490.1765014208.diff
View Options
diff --git a/services/terraform/remote/service_backup.tf b/services/terraform/remote/service_backup.tf
--- a/services/terraform/remote/service_backup.tf
+++ b/services/terraform/remote/service_backup.tf
@@ -12,6 +12,9 @@
# URL accessible by other services in the same Service Connect namespace
# This renders to 'http://backup-service:50052'
backup_local_url = "http://${local.backup_sc_dns_name}:${local.backup_service_container_http_port}"
+
+ # Fargate-specific URL for Fargate services to communicate with Fargate backup service
+ backup_fargate_url = "http://${local.backup_sc_dns_name}-fargate:${local.backup_service_container_http_port}"
}
resource "aws_ecs_task_definition" "backup_service" {
@@ -182,8 +185,31 @@
certificate_arn = data.aws_acm_certificate.backup_service.arn
default_action {
- type = "forward"
- target_group_arn = aws_lb_target_group.backup_service_http.arn
+ type = "forward"
+
+ # Production: Simple forwarding (unchanged)
+ target_group_arn = local.is_staging ? null : aws_lb_target_group.backup_service_http.arn
+
+ # Staging: Weighted forwarding
+ dynamic "forward" {
+ for_each = local.is_staging ? [1] : []
+ content {
+ target_group {
+ arn = aws_lb_target_group.backup_service_http.arn
+ weight = 100 # 100% EC2
+ }
+
+ target_group {
+ arn = aws_lb_target_group.backup_service_http_fargate[0].arn
+ weight = 0 # 0% Fargate
+ }
+
+ stickiness {
+ enabled = false
+ duration = 10
+ }
+ }
+ }
}
lifecycle {
diff --git a/services/terraform/remote/service_backup_fargate.tf b/services/terraform/remote/service_backup_fargate.tf
new file mode 100644
--- /dev/null
+++ b/services/terraform/remote/service_backup_fargate.tf
@@ -0,0 +1,144 @@
+# Fargate task definition (staging only)
+resource "aws_ecs_task_definition" "backup_service_fargate" {
+ count = local.is_staging ? 1 : 0
+ family = "backup-service-fargate-task-def"
+ container_definitions = jsonencode([
+ {
+ name = local.backup_service_container_name
+ image = local.backup_service_server_image
+ essential = true
+ portMappings = [
+ {
+ name = local.backup_sc_port_name
+ containerPort = local.backup_service_container_http_port
+ protocol = "tcp"
+ appProtocol = "http"
+ },
+ ]
+ environment = [
+ {
+ name = "RUST_LOG"
+ value = local.is_staging ? "info,backup=debug,comm_lib=debug" : "info"
+ },
+ {
+ name = "BLOB_SERVICE_URL",
+ value = local.blob_fargate_url
+ },
+ {
+ name = "IDENTITY_SERVICE_ENDPOINT",
+ value = local.identity_fargate_url
+ },
+ {
+ name = "COMM_SERVICES_USE_JSON_LOGS",
+ value = local.comm_services_use_json_logs
+ }
+ ]
+ logConfiguration = {
+ "logDriver" = "awslogs"
+ "options" = {
+ "awslogs-create-group" = "true"
+ "awslogs-group" = "/ecs/backup-service-fargate-task-def"
+ "awslogs-region" = "us-east-2"
+ "awslogs-stream-prefix" = "ecs"
+ }
+ }
+ }
+ ])
+ task_role_arn = aws_iam_role.backup_service.arn
+ execution_role_arn = aws_iam_role.ecs_task_execution.arn
+ network_mode = "awsvpc"
+ cpu = "256"
+ memory = "512"
+ requires_compatibilities = ["FARGATE"]
+
+ skip_destroy = true
+}
+
+# Fargate ECS Service (staging only)
+resource "aws_ecs_service" "backup_service_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "backup-service-fargate"
+ cluster = aws_ecs_cluster.comm_services.id
+ launch_type = "FARGATE"
+
+ task_definition = aws_ecs_task_definition.backup_service_fargate[0].arn
+ force_new_deployment = true
+
+ network_configuration {
+ subnets = [
+ aws_subnet.public_a.id,
+ aws_subnet.public_b.id,
+ aws_subnet.public_c.id,
+ ]
+ security_groups = [aws_security_group.backup_service.id]
+ assign_public_ip = true
+ }
+
+ service_connect_configuration {
+ enabled = true
+ service {
+ discovery_name = "${local.backup_sc_dns_name}-fargate"
+ port_name = local.backup_sc_port_name
+ client_alias {
+ port = local.backup_service_container_http_port
+ dns_name = "${local.backup_sc_dns_name}-fargate"
+ }
+ }
+ }
+
+ # HTTP
+ load_balancer {
+ target_group_arn = aws_lb_target_group.backup_service_http_fargate[0].arn
+ container_name = local.backup_service_container_name
+ container_port = local.backup_service_container_http_port
+ }
+
+ deployment_circuit_breaker {
+ enable = true
+ rollback = true
+ }
+
+ lifecycle {
+ ignore_changes = [desired_count]
+ }
+
+ enable_execute_command = true
+ enable_ecs_managed_tags = true
+}
+
+# Fargate HTTP target group (staging only)
+resource "aws_lb_target_group" "backup_service_http_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "backup-service-http-fargate-tg"
+ port = local.backup_service_container_http_port
+ protocol = "HTTP"
+ vpc_id = aws_vpc.default.id
+ target_type = "ip"
+
+ health_check {
+ enabled = true
+ healthy_threshold = 2
+ unhealthy_threshold = 3
+
+ protocol = "HTTP"
+ path = "/health"
+ matcher = "200-204"
+ }
+}
+
+# Auto-scaling for Fargate service (staging only)
+module "backup_service_fargate_autoscaling" {
+ source = "../modules/fargate-autoscaling"
+
+ create_resources = local.is_staging
+ service_name = local.is_staging ? aws_ecs_service.backup_service_fargate[0].name : ""
+ cluster_name = aws_ecs_cluster.comm_services.name
+
+ min_capacity = 1
+ max_capacity = 4
+ cpu_target = 40.0
+ memory_target = 50.0
+
+ scale_in_cooldown = 300 # 5 minutes
+ scale_out_cooldown = 60 # 1 minute
+}
\ No newline at end of file
diff --git a/services/terraform/remote/service_blob.tf b/services/terraform/remote/service_blob.tf
--- a/services/terraform/remote/service_blob.tf
+++ b/services/terraform/remote/service_blob.tf
@@ -11,6 +11,9 @@
# URL accessible by other services in the same Service Connect namespace
# This renders to 'http://blob-service:50053'
blob_local_url = "http://${local.blob_sc_dns_name}:${local.blob_service_container_http_port}"
+
+ # Fargate-specific URL for Fargate services to communicate with Fargate blob service
+ blob_fargate_url = "http://${local.blob_sc_dns_name}-fargate:${local.blob_service_container_http_port}"
blob_service_container_grpc_port = 50051
blob_service_grpc_public_port = 50053
@@ -185,8 +188,31 @@
certificate_arn = data.aws_acm_certificate.blob_service.arn
default_action {
- type = "forward"
- target_group_arn = aws_lb_target_group.blob_service_http.arn
+ type = "forward"
+
+ # Production: Simple forwarding (unchanged)
+ target_group_arn = local.is_staging ? null : aws_lb_target_group.blob_service_http.arn
+
+ # Staging: Weighted forwarding
+ dynamic "forward" {
+ for_each = local.is_staging ? [1] : []
+ content {
+ target_group {
+ arn = aws_lb_target_group.blob_service_http.arn
+ weight = 100 # 100% EC2
+ }
+
+ target_group {
+ arn = aws_lb_target_group.blob_service_http_fargate[0].arn
+ weight = 0 # 0% Fargate
+ }
+
+ stickiness {
+ enabled = false
+ duration = 10
+ }
+ }
+ }
}
lifecycle {
diff --git a/services/terraform/remote/service_blob_fargate.tf b/services/terraform/remote/service_blob_fargate.tf
new file mode 100644
--- /dev/null
+++ b/services/terraform/remote/service_blob_fargate.tf
@@ -0,0 +1,141 @@
+# Fargate task definition (staging only)
+resource "aws_ecs_task_definition" "blob_service_fargate" {
+ count = local.is_staging ? 1 : 0
+ family = "blob-service-fargate-task-def"
+ container_definitions = jsonencode([
+ {
+ name = local.blob_service_container_name
+ image = local.blob_service_server_image
+ essential = true
+ portMappings = [
+ {
+ name = local.blob_sc_port_name
+ containerPort = local.blob_service_container_http_port
+ protocol = "tcp"
+ appProtocol = "http"
+ }
+ ]
+ environment = [
+ {
+ name = "RUST_LOG"
+ value = local.is_staging ? "info,blob=debug,comm_lib=debug" : "info"
+ },
+ {
+ name = "BLOB_S3_BUCKET_NAME",
+ value = local.blob_service_s3_bucket
+ },
+ {
+ name = "IDENTITY_SERVICE_ENDPOINT",
+ value = local.identity_fargate_url
+ },
+ {
+ name = "COMM_SERVICES_USE_JSON_LOGS",
+ value = local.comm_services_use_json_logs
+ }
+ ]
+ logConfiguration = {
+ "logDriver" = "awslogs"
+ "options" = {
+ "awslogs-create-group" = "true"
+ "awslogs-group" = "/ecs/blob-service-fargate-task-def"
+ "awslogs-region" = "us-east-2"
+ "awslogs-stream-prefix" = "ecs"
+ }
+ }
+ }
+ ])
+ task_role_arn = aws_iam_role.services_ddb_full_access.arn
+ execution_role_arn = aws_iam_role.ecs_task_execution.arn
+ network_mode = "awsvpc"
+ cpu = "256"
+ memory = "512"
+ requires_compatibilities = ["FARGATE"]
+
+ skip_destroy = true
+}
+
+# Fargate ECS Service (staging only)
+resource "aws_ecs_service" "blob_service_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "blob-service-fargate"
+ cluster = aws_ecs_cluster.comm_services.id
+ launch_type = "FARGATE"
+
+ task_definition = aws_ecs_task_definition.blob_service_fargate[0].arn
+ force_new_deployment = true
+
+ network_configuration {
+ subnets = [
+ aws_subnet.public_a.id,
+ aws_subnet.public_b.id,
+ aws_subnet.public_c.id,
+ ]
+ security_groups = [aws_security_group.blob_service.id]
+ assign_public_ip = true
+ }
+
+ service_connect_configuration {
+ enabled = true
+ service {
+ discovery_name = "${local.blob_sc_dns_name}-fargate"
+ port_name = local.blob_sc_port_name
+ client_alias {
+ port = local.blob_service_container_http_port
+ dns_name = "${local.blob_sc_dns_name}-fargate"
+ }
+ }
+ }
+
+ # HTTP
+ load_balancer {
+ target_group_arn = aws_lb_target_group.blob_service_http_fargate[0].arn
+ container_name = local.blob_service_container_name
+ container_port = local.blob_service_container_http_port
+ }
+
+ deployment_circuit_breaker {
+ enable = true
+ rollback = true
+ }
+
+ lifecycle {
+ ignore_changes = [desired_count]
+ }
+}
+
+# Fargate HTTP target group (staging only)
+resource "aws_lb_target_group" "blob_service_http_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "blob-service-http-fargate-tg"
+ port = local.blob_service_container_http_port
+ protocol = "HTTP"
+ vpc_id = aws_vpc.default.id
+ target_type = "ip"
+
+ health_check {
+ enabled = true
+ healthy_threshold = 2
+ unhealthy_threshold = 3
+
+ protocol = "HTTP"
+ path = "/health"
+ matcher = "200-499"
+ }
+}
+
+# Auto-scaling for Fargate service (staging only)
+module "blob_service_fargate_autoscaling" {
+ source = "../modules/fargate-autoscaling"
+
+ create_resources = local.is_staging
+ service_name = local.is_staging ? aws_ecs_service.blob_service_fargate[0].name : ""
+ cluster_name = aws_ecs_cluster.comm_services.name
+
+ min_capacity = 1
+ max_capacity = 4
+ cpu_target = 35.0
+ memory_target = 45.0
+
+ scale_in_cooldown = 300 # 5 minutes
+ scale_out_cooldown = 60 # 1 minute
+}
\ No newline at end of file
diff --git a/services/terraform/remote/service_identity.tf b/services/terraform/remote/service_identity.tf
--- a/services/terraform/remote/service_identity.tf
+++ b/services/terraform/remote/service_identity.tf
@@ -15,6 +15,9 @@
# URL accessible by other services in the same Service Connect namespace
# This renders to e.g. 'http://identity-service:50054'
identity_local_url = "http://${local.identity_sc_dns_name}:${local.identity_service_container_grpc_port}"
+
+ # Fargate-specific URL for Fargate services to communicate with Fargate identity service
+ identity_fargate_url = "http://${local.identity_sc_dns_name}-fargate:${local.identity_service_container_grpc_port}"
# Port that is exposed to the public SSL endpoint (appended to domain name)
identity_service_grpc_public_port = 50054
@@ -277,8 +280,31 @@
certificate_arn = data.aws_acm_certificate.identity_service.arn
default_action {
- type = "forward"
- target_group_arn = aws_lb_target_group.identity_service_ws.arn
+ type = "forward"
+
+ # Production: Simple forwarding (unchanged)
+ target_group_arn = local.is_staging ? null : aws_lb_target_group.identity_service_ws.arn
+
+ # Staging: Weighted forwarding
+ dynamic "forward" {
+ for_each = local.is_staging ? [1] : []
+ content {
+ target_group {
+ arn = aws_lb_target_group.identity_service_ws.arn
+ weight = 100 # 100% EC2
+ }
+
+ target_group {
+ arn = aws_lb_target_group.identity_service_ws_fargate[0].arn
+ weight = 0 # 0% Fargate
+ }
+
+ stickiness {
+ enabled = false
+ duration = 10
+ }
+ }
+ }
}
lifecycle {
@@ -295,8 +321,31 @@
certificate_arn = data.aws_acm_certificate.identity_service.arn
default_action {
- type = "forward"
- target_group_arn = aws_lb_target_group.identity_service_grpc.arn
+ type = "forward"
+
+ # Production: Simple forwarding (unchanged)
+ target_group_arn = local.is_staging ? null : aws_lb_target_group.identity_service_grpc.arn
+
+ # Staging: Weighted forwarding
+ dynamic "forward" {
+ for_each = local.is_staging ? [1] : []
+ content {
+ target_group {
+ arn = aws_lb_target_group.identity_service_grpc.arn
+ weight = 100 # Start with 100% EC2
+ }
+
+ target_group {
+ arn = aws_lb_target_group.identity_service_grpc_fargate[0].arn
+ weight = 0 # Start with 0% Fargate
+ }
+
+ stickiness {
+ enabled = true
+ duration = 10
+ }
+ }
+ }
}
lifecycle {
diff --git a/services/terraform/remote/service_identity_fargate.tf b/services/terraform/remote/service_identity_fargate.tf
new file mode 100644
--- /dev/null
+++ b/services/terraform/remote/service_identity_fargate.tf
@@ -0,0 +1,263 @@
+# Fargate task definition (staging only)
+resource "aws_ecs_task_definition" "identity_service_fargate" {
+ count = local.is_staging ? 1 : 0
+ family = "identity-service-fargate-task-def"
+ container_definitions = jsonencode([
+ {
+ name = local.identity_service_container_name
+ image = local.identity_service_server_image
+ essential = true
+ portMappings = [
+ {
+ name = local.identity_sc_port_name
+ containerPort = local.identity_service_container_grpc_port
+ protocol = "tcp"
+ appProtocol = "grpc"
+ },
+ {
+ name = local.identity_sc_ws_port_name
+ containerPort = local.identity_service_container_ws_port
+ protocol = "tcp"
+ appProtocol = "http"
+ }
+ ]
+ environment = [
+ {
+ name = "RUST_LOG"
+ value = local.is_staging ? "info,identity=debug,comm_lib=debug" : "info"
+ },
+ {
+ name = "KEYSERVER_PUBLIC_KEY"
+ value = nonsensitive(local.secrets["keyserverPublicKey"])
+ },
+ {
+ name = "TUNNELBROKER_GRPC_ENDPOINT"
+ value = local.tunnelbroker_fargate_grpc_url
+ },
+ {
+ name = "BACKUP_SERVICE_URL",
+ value = local.backup_fargate_url
+ },
+ {
+ name = "BLOB_SERVICE_URL",
+ value = local.blob_fargate_url
+ },
+ {
+ name = "OPENSEARCH_ENDPOINT"
+ value = module.shared.opensearch_domain_identity.endpoint
+ },
+ {
+ name = "ALLOW_ORIGIN_LIST"
+ value = local.is_staging ? local.staging_allow_origin_list : local.production_allow_origin_list
+ },
+ {
+ name = "COMM_SERVICES_USE_JSON_LOGS",
+ value = local.comm_services_use_json_logs
+ },
+ {
+ name = "REDACT_SENSITIVE_DATA",
+ value = local.is_staging ? "false" : "true"
+ }
+ ]
+ secrets = [
+ {
+ name = "OPAQUE_SERVER_SETUP"
+ valueFrom = data.aws_secretsmanager_secret.identity_server_setup.arn
+ }
+ ]
+ logConfiguration = {
+ "logDriver" = "awslogs"
+ "options" = {
+ "awslogs-create-group" = "true"
+ "awslogs-group" = "/ecs/identity-service-fargate-task-def"
+ "awslogs-region" = "us-east-2"
+ "awslogs-stream-prefix" = "ecs"
+ }
+ }
+ }
+ ])
+ task_role_arn = aws_iam_role.services_ddb_full_access.arn
+ execution_role_arn = aws_iam_role.ecs_task_execution.arn
+ network_mode = "awsvpc"
+ cpu = "256"
+ memory = "512"
+ requires_compatibilities = ["FARGATE"]
+
+ skip_destroy = true
+}
+
+# Fargate ECS Service (staging only)
+resource "aws_ecs_service" "identity_service_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "identity-service-fargate"
+ cluster = aws_ecs_cluster.comm_services.id
+ launch_type = "FARGATE"
+
+ task_definition = aws_ecs_task_definition.identity_service_fargate[0].arn
+ force_new_deployment = true
+
+ network_configuration {
+ subnets = [
+ aws_subnet.public_a.id,
+ aws_subnet.public_b.id,
+ aws_subnet.public_c.id,
+ ]
+ security_groups = [aws_security_group.identity_service_fargate.id]
+ assign_public_ip = true
+ }
+
+ service_connect_configuration {
+ enabled = true
+ service {
+ discovery_name = "${local.identity_sc_dns_name}-fargate"
+ port_name = local.identity_sc_port_name
+ client_alias {
+ port = local.identity_service_container_grpc_port
+ dns_name = "${local.identity_sc_dns_name}-fargate"
+ }
+ }
+ }
+
+ # WebSocket
+ load_balancer {
+ target_group_arn = aws_lb_target_group.identity_service_ws_fargate[0].arn
+ container_name = local.identity_service_container_name
+ container_port = local.identity_service_container_ws_port
+ }
+
+ # gRPC
+ load_balancer {
+ target_group_arn = aws_lb_target_group.identity_service_grpc_fargate[0].arn
+ container_name = local.identity_service_container_name
+ container_port = local.identity_service_container_grpc_port
+ }
+
+ deployment_circuit_breaker {
+ enable = true
+ rollback = true
+ }
+
+ lifecycle {
+ ignore_changes = [desired_count]
+ }
+
+ enable_execute_command = true
+ enable_ecs_managed_tags = true
+}
+
+resource "aws_security_group" "identity_service_fargate" {
+ name = "identity-service-ecs-sg-fargate"
+ vpc_id = aws_vpc.default.id
+
+ ingress {
+ from_port = local.identity_service_container_grpc_port
+ to_port = local.identity_service_container_grpc_port
+ protocol = "tcp"
+ cidr_blocks = ["0.0.0.0/0"]
+ description = "gRPC port"
+ }
+
+ ingress {
+ from_port = local.identity_service_container_ws_port
+ to_port = local.identity_service_container_ws_port
+ protocol = "tcp"
+ cidr_blocks = ["0.0.0.0/0"]
+ description = "Websocket port"
+ }
+
+ # Allow ALB health checks from VPC - gRPC port
+ ingress {
+ from_port = local.identity_service_container_grpc_port
+ to_port = local.identity_service_container_grpc_port
+ protocol = "tcp"
+ cidr_blocks = [aws_vpc.default.cidr_block]
+ description = "VPC traffic for ALB health checks - gRPC"
+ }
+
+ # Allow ALB health checks from VPC - WebSocket port
+ ingress {
+ from_port = local.identity_service_container_ws_port
+ to_port = local.identity_service_container_ws_port
+ protocol = "tcp"
+ cidr_blocks = [aws_vpc.default.cidr_block]
+ description = "VPC traffic for ALB health checks - WebSocket"
+ }
+
+ # Allow all outbound traffic
+ egress {
+ from_port = 0
+ to_port = 0
+ protocol = "-1"
+ cidr_blocks = ["0.0.0.0/0"]
+ }
+
+ lifecycle {
+ create_before_destroy = true
+ }
+}
+
+# Fargate gRPC target group (staging only)
+resource "aws_lb_target_group" "identity_service_grpc_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "identity-service-grpc-fargate-tg"
+ port = local.identity_service_container_grpc_port
+ protocol = "HTTP"
+ protocol_version = "HTTP2"
+ vpc_id = aws_vpc.default.id
+ target_type = "ip"
+
+ stickiness {
+ type = "lb_cookie"
+ cookie_duration = 10
+ enabled = true
+ }
+
+ health_check {
+ enabled = true
+ healthy_threshold = 2
+ unhealthy_threshold = 3
+
+ protocol = "HTTP"
+ port = "traffic-port"
+ path = "/"
+ matcher = "200-499"
+ }
+}
+
+# Fargate WebSocket target group (staging only)
+resource "aws_lb_target_group" "identity_service_ws_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "identity-service-ws-fargate-tg"
+ port = local.identity_service_container_ws_port
+ protocol = "HTTP"
+ protocol_version = "HTTP1"
+ vpc_id = aws_vpc.default.id
+ target_type = "ip"
+
+ health_check {
+ enabled = true
+ healthy_threshold = 2
+ unhealthy_threshold = 3
+
+ protocol = "HTTP"
+ path = "/health"
+ matcher = "200"
+ }
+}
+
+# Auto-scaling for Fargate service (staging only)
+module "identity_service_fargate_autoscaling" {
+ source = "../modules/fargate-autoscaling"
+
+ create_resources = local.is_staging
+ service_name = local.is_staging ? aws_ecs_service.identity_service_fargate[0].name : ""
+ cluster_name = aws_ecs_cluster.comm_services.name
+
+ min_capacity = 1
+ max_capacity = 6
+ cpu_target = 35.0
+ memory_target = 45.0
+
+ scale_in_cooldown = 300 # 5 minutes
+ scale_out_cooldown = 60 # 1 minute
+}
\ No newline at end of file
diff --git a/services/terraform/remote/service_tunnelbroker.tf b/services/terraform/remote/service_tunnelbroker.tf
--- a/services/terraform/remote/service_tunnelbroker.tf
+++ b/services/terraform/remote/service_tunnelbroker.tf
@@ -14,6 +14,9 @@
# Used for other services to connect to Tunnelbroker gRPC endpoint
tunnelbroker_local_grpc_url = "http://${local.tunnelbroker_config.local_dns_name}:${local.tunnelbroker_config.grpc_port}"
+
+ # Fargate-specific URL for Fargate services to communicate with Fargate tunnelbroker
+ tunnelbroker_fargate_grpc_url = "http://${local.tunnelbroker_config.local_dns_name}-fargate:${local.tunnelbroker_config.grpc_port}"
# utility locals
tunnelbroker_docker_image = "${local.tunnelbroker_config.docker_image}:${local.tunnelbroker_config.docker_tag}"
@@ -316,12 +319,35 @@
certificate_arn = data.aws_acm_certificate.tunnelbroker.arn
default_action {
- type = "forward"
- target_group_arn = aws_lb_target_group.tunnelbroker_ws.arn
+ type = "forward"
+
+ # Production: Simple forwarding (unchanged)
+ target_group_arn = local.is_staging ? null : aws_lb_target_group.tunnelbroker_ws.arn
+
+ # Staging: Weighted forwarding
+ dynamic "forward" {
+ for_each = local.is_staging ? [1] : []
+ content {
+ target_group {
+ arn = aws_lb_target_group.tunnelbroker_ws.arn
+ weight = 100 # Switch back to 100% EC2
+ }
+
+ target_group {
+ arn = aws_lb_target_group.tunnelbroker_ws_fargate[0].arn
+ weight = 0 # Switch back to 0% Fargate
+ }
+
+ stickiness {
+ enabled = false
+ duration = 10
+ }
+ }
+ }
}
lifecycle {
- ignore_changes = [default_action[0].forward[0].stickiness[0].duration]
+ # ignore_changes = [default_action[0].forward[0].stickiness[0].duration]
replace_triggered_by = [aws_lb_target_group.tunnelbroker_ws]
}
}
@@ -335,12 +361,27 @@
certificate_arn = data.aws_acm_certificate.tunnelbroker.arn
default_action {
- type = "forward"
- target_group_arn = aws_lb_target_group.tunnelbroker_grpc.arn
+ type = "forward"
+ forward {
+ target_group {
+ arn = aws_lb_target_group.tunnelbroker_grpc.arn
+ weight = 100 # 100% EC2
+ }
+
+ target_group {
+ arn = aws_lb_target_group.tunnelbroker_grpc_fargate[0].arn
+ weight = 0 # 0% Fargate
+ }
+
+ stickiness {
+ enabled = false
+ duration = 10
+ }
+ }
}
lifecycle {
- ignore_changes = [default_action[0].forward[0].stickiness[0].duration]
+ # ignore_changes = [default_action[0].forward[0].stickiness[0].duration]
replace_triggered_by = [aws_lb_target_group.tunnelbroker_grpc]
}
}
diff --git a/services/terraform/remote/service_tunnelbroker_fargate.tf b/services/terraform/remote/service_tunnelbroker_fargate.tf
new file mode 100644
--- /dev/null
+++ b/services/terraform/remote/service_tunnelbroker_fargate.tf
@@ -0,0 +1,210 @@
+# Fargate task definition (staging only)
+resource "aws_ecs_task_definition" "tunnelbroker_fargate" {
+ count = local.is_staging ? 1 : 0
+ family = "tunnelbroker-fargate-task-def"
+ container_definitions = jsonencode([
+ {
+ name = local.tunnelbroker_config.container_name
+ image = local.tunnelbroker_docker_image
+ essential = true
+ portMappings = [
+ {
+ name = "tunnelbroker_ws"
+ containerPort = local.tunnelbroker_config.websocket_port
+ protocol = "tcp"
+ appProtocol = "http"
+ },
+ {
+ name = local.tunnelbroker_config.grpc_port_name
+ containerPort = local.tunnelbroker_config.grpc_port
+ protocol = "tcp"
+ appProtocol = "grpc"
+ }
+ ]
+ environment = [
+ {
+ name = "RUST_LOG"
+ value = local.is_staging ? "info,tunnelbroker=debug,comm_lib=debug" : "info"
+ },
+ {
+ name = "AMQP_URI",
+ value = local.amqp_endpoint
+ },
+ {
+ name = "AMQP_USERNAME"
+ value = "comm"
+ },
+ {
+ name = "AMQP_PASSWORD"
+ value = nonsensitive(local.rabbitmq_password)
+ },
+ {
+ name = "COMM_TUNNELBROKER_IDENTITY_ENDPOINT",
+ value = local.identity_fargate_url
+ },
+ {
+ name = "BLOB_SERVICE_URL",
+ value = local.blob_fargate_url
+ },
+ {
+ name = "BLOB_SERVICE_PUBLIC_URL",
+ value = "https://${local.blob_service_domain_name}"
+ },
+ {
+ name = "COMM_SERVICES_USE_JSON_LOGS",
+ value = local.comm_services_use_json_logs
+ },
+ {
+ name = "REDACT_SENSITIVE_DATA",
+ value = local.is_staging ? "false" : "true"
+ }
+ ]
+ secrets = [
+ {
+ name = "APNS_CONFIG"
+ valueFrom = data.aws_secretsmanager_secret.tunnelbroker_apns.arn
+ },
+ {
+ name = "FCM_CONFIG"
+ valueFrom = data.aws_secretsmanager_secret.tunnelbroker_fcm.arn
+ },
+ {
+ name = "WEB_PUSH_CONFIG"
+ valueFrom = data.aws_secretsmanager_secret.tunnelbroker_web_push.arn
+ },
+ {
+ name = "WNS_CONFIG"
+ valueFrom = data.aws_secretsmanager_secret.tunnelbroker_wns.arn
+ }
+ ]
+ logConfiguration = {
+ "logDriver" = "awslogs"
+ "options" = {
+ "awslogs-create-group" = "true"
+ "awslogs-group" = "/ecs/tunnelbroker-fargate-task-def"
+ "awslogs-region" = "us-east-2"
+ "awslogs-stream-prefix" = "ecs"
+ }
+ }
+ }
+ ])
+ task_role_arn = aws_iam_role.services_ddb_full_access.arn
+ execution_role_arn = aws_iam_role.ecs_task_execution.arn
+ network_mode = "awsvpc"
+ cpu = "256"
+ memory = "512"
+ requires_compatibilities = ["FARGATE"]
+
+ skip_destroy = true
+}
+
+# Fargate ECS Service (staging only)
+resource "aws_ecs_service" "tunnelbroker_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "tunnelbroker-fargate"
+ cluster = aws_ecs_cluster.comm_services.id
+ launch_type = "FARGATE"
+
+ task_definition = aws_ecs_task_definition.tunnelbroker_fargate[0].arn
+ force_new_deployment = true
+
+ network_configuration {
+ subnets = [
+ aws_subnet.public_a.id,
+ aws_subnet.public_b.id,
+ aws_subnet.public_c.id,
+ ]
+ security_groups = [aws_security_group.tunnelbroker.id]
+ assign_public_ip = true
+ }
+
+ service_connect_configuration {
+ enabled = true
+ service {
+ discovery_name = "${local.tunnelbroker_config.local_dns_name}-fargate"
+ port_name = local.tunnelbroker_config.grpc_port_name
+ client_alias {
+ port = local.tunnelbroker_config.grpc_port
+ dns_name = "${local.tunnelbroker_config.local_dns_name}-fargate"
+ }
+ }
+ }
+
+ # Websocket
+ load_balancer {
+ target_group_arn = aws_lb_target_group.tunnelbroker_ws_fargate[0].arn
+ container_name = local.tunnelbroker_config.container_name
+ container_port = local.tunnelbroker_config.websocket_port
+ }
+
+ # gRPC (only exists in staging)
+ load_balancer {
+ target_group_arn = aws_lb_target_group.tunnelbroker_grpc_fargate[0].arn
+ container_name = local.tunnelbroker_config.container_name
+ container_port = local.tunnelbroker_config.grpc_port
+ }
+
+ deployment_circuit_breaker {
+ enable = true
+ rollback = true
+ }
+
+ lifecycle {
+ ignore_changes = [desired_count]
+ }
+}
+
+# Fargate WebSocket target group (staging only)
+resource "aws_lb_target_group" "tunnelbroker_ws_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "tunnelbroker-ws-fargate-tg"
+ port = local.tunnelbroker_config.websocket_port
+ protocol = "HTTP"
+ protocol_version = "HTTP1"
+ vpc_id = aws_vpc.default.id
+ target_type = "ip"
+
+ health_check {
+ enabled = true
+ healthy_threshold = 2
+ unhealthy_threshold = 3
+
+ protocol = "HTTP"
+ path = "/health"
+ matcher = "200"
+ }
+}
+
+# Fargate gRPC target group (staging only)
+resource "aws_lb_target_group" "tunnelbroker_grpc_fargate" {
+ count = local.is_staging ? 1 : 0
+ name = "tunnelbroker-grpc-fargate-tg"
+ port = local.tunnelbroker_config.grpc_port
+ protocol = "HTTP"
+ protocol_version = "GRPC"
+ vpc_id = aws_vpc.default.id
+ target_type = "ip"
+
+ health_check {
+ enabled = true
+ healthy_threshold = 2
+ unhealthy_threshold = 3
+ }
+}
+
+# Auto-scaling for Fargate service (staging only)
+module "tunnelbroker_fargate_autoscaling" {
+ source = "../modules/fargate-autoscaling"
+
+ create_resources = local.is_staging
+ service_name = local.is_staging ? aws_ecs_service.tunnelbroker_fargate[0].name : ""
+ cluster_name = aws_ecs_cluster.comm_services.name
+
+ min_capacity = 1
+ max_capacity = 8
+ cpu_target = 30.0
+ memory_target = 40.0
+
+ scale_in_cooldown = 300 # 5 minutes
+ scale_out_cooldown = 60 # 1 minute
+}
\ No newline at end of file
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 6, 9:43 AM (17 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5836040
Default Alt Text
D15490.1765014208.diff (31 KB)
Attached To
Mode
D15490: [terraform] create Fargate deployment of Blob, Backup, Identity and Tunnelbroker
Attached
Detach File
Event Timeline
Log In to Comment