feat(terraform): AWS Fargate deployment module

Adds a terraform/ directory with an opinionated module that deploys
shared-memory to ECS Fargate behind an ALB. The module assumes the
operator already provides the VPC, RDS Postgres, ACM cert, ECR images,
and OIDC clients, and creates everything else: ECS cluster + services,
ALB, Service Connect namespace for app-embedder discovery, EFS-backed
model cache for the embedder, Secrets Manager entries, IAM roles,
CloudWatch log groups, and a one-shot migrator task definition.

Includes examples/basic/ with a worked invocation and a README covering
prerequisites, quick start, the post-apply migrator run, image updates,
DNS setup, and a security note. Main README gains a short Mode C
pointer to the terraform/ guide.

Validated with `terraform fmt -check -recursive` and
`terraform validate` against AWS provider 5.x.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 09:40:12 -07:00
co-authored by Claude Opus 4.7
parent f769daa48a
commit 08be60e661
16 changed files with 1674 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
# -----------------------------------------------------------------------------
# Outputs.
#
# Designed to give the operator everything they need to:
# * point DNS at the ALB
# * run the migrator one-shot
# * extend the RDS security group with task ingress
# * tail logs
# -----------------------------------------------------------------------------
output "alb_dns_name" {
description = "ALB DNS name. Create a Route53 alias record pointing var.domain_name at this."
value = aws_lb.this.dns_name
}
output "alb_zone_id" {
description = "ALB hosted zone ID, used as `alias.zone_id` on aws_route53_record."
value = aws_lb.this.zone_id
}
output "ecs_cluster_arn" {
description = "ECS cluster ARN."
value = aws_ecs_cluster.this.arn
}
output "ecs_cluster_name" {
description = "ECS cluster name. Pass to `aws ecs run-task --cluster`."
value = aws_ecs_cluster.this.name
}
output "app_service_name" {
description = "App ECS service name."
value = aws_ecs_service.app.name
}
output "embedder_service_name" {
description = "Embedder ECS service name."
value = aws_ecs_service.embedder.name
}
output "migrator_task_definition_arn" {
description = "Migrator task definition ARN. Use with `aws ecs run-task --task-definition`."
value = aws_ecs_task_definition.migrator.arn
}
output "migrator_task_definition_family" {
description = "Migrator task definition family — accepts the latest revision automatically when passed to `aws ecs run-task`."
value = aws_ecs_task_definition.migrator.family
}
output "app_log_group_name" {
description = "CloudWatch log group for the app service."
value = aws_cloudwatch_log_group.app.name
}
output "embedder_log_group_name" {
description = "CloudWatch log group for the embedder service."
value = aws_cloudwatch_log_group.embedder.name
}
output "migrator_log_group_name" {
description = "CloudWatch log group for the migrator one-shot task."
value = aws_cloudwatch_log_group.migrator.name
}
output "app_security_group_id" {
description = "Security group attached to app tasks. Add this as a source on your RDS SG inbound rule for port 5432."
value = aws_security_group.app.id
}
output "embedder_security_group_id" {
description = "Security group attached to embedder tasks. Embedder doesn't hit RDS today, but expose for symmetry."
value = aws_security_group.embedder.id
}
output "migrator_security_group_id" {
description = "Security group attached to the migrator one-shot. Must be allowed inbound on your RDS SG (5432) — this is what runs SQL migrations."
value = aws_security_group.migrator.id
}
output "private_subnet_ids_for_run_task" {
description = "Echo of var.private_subnet_ids so `aws ecs run-task --network-configuration` can be assembled without re-typing them."
value = var.private_subnet_ids
}
output "secret_arns" {
description = "Map of env-var name to Secrets Manager ARN. For visibility only — do not re-feed back into the module."
value = local.secret_arns
}