Skip to content

feat(templates): add ECS Fargate module to terragrunt and gitlab-cicd templates - #137

Open
sintiasnn wants to merge 8 commits into
zero-one-group:mainfrom
sintiasnn:feat/add-ecs-terragrunt-module-template
Open

feat(templates): add ECS Fargate module to terragrunt and gitlab-cicd templates#137
sintiasnn wants to merge 8 commits into
zero-one-group:mainfrom
sintiasnn:feat/add-ecs-terragrunt-module-template

Conversation

@sintiasnn

@sintiasnn sintiasnn commented Aug 4, 2026

Copy link
Copy Markdown

Description 📋

Adds a reusable ECS Fargate module to the terragrunt template plus a matching deploy pipeline in the gitlab-cicd template.

  • modules/ecs: ECS cluster (Fargate + Fargate Spot), per-entry task definitions, IAM execution/task roles (with optional S3/SSM access), CloudWatch log groups. services map for always-on workloads (task definition + ECS service, optional ALB and/or Cloud Map service discovery). jobs map for on-demand workloads launched via ecs:RunTask.
  • dev/staging/prod/ecs Terragrunt units wiring the module to the existing vpc, security-groups, and shared/ecr units.
  • New ecs security group added to the dev/staging/prod/security-groups units (outbound-only; task/ALB security groups are created by the module itself).
  • shared/variables/ecs: per-service CPU/memory sizing and a git-ignored env/<environment>/<service>.yml layout for per-service environment variables.
  • gitlab-cicd/app/ecs-deploy.yml: deploy jobs for dev/staging/prod that convert the app .env CI variable to YAML, set ECS_IMAGE_TAG to the image pushed by the existing build jobs, and run terragrunt apply targeted at the service's task definition + ECS service.
  • Fixed .rules:development, which was referenced by build:development-docker / build:staging-docker / build:production-docker but never defined in dependencies/only.yml — surfaced because the new ECS deploy jobs add a needs dependency on those build jobs.
  • README and docsite updates describing the new module and apply order.

Fixes #136

Type of change 🤔

  • Bugfix (non breaking change which resolve an issue)
  • Feature (non breaking change which adds functionality)
  • Breaking Change (a change which would cause existing functionality to not work as expected)
  • Documentation (a change to documentation)

Submission checklist ✅

  • I have performed a self review of my changes
  • I have updated the documentation where relevant
  • My changes are well written and all ci is passing

Test plan

  • terraform fmt -check and terraform validate pass on templates/terragrunt/modules/ecs (no automated test harness exists for this template type — verified manually since the module has no {{ }} placeholders).
  • Manually traced the dependency chain: dev/ecsvpc/security-groups/shared/ecr outputs resolve correctly; sg_ids.ecs matches the new security group entry added to all three environments.

@sintiasnn

Copy link
Copy Markdown
Author

Testing summary

Validated end-to-end against a real AWS account (532090602408, ap-southeast-1):

  1. Static checksterragrunt hcl fmt / hcl validate OK; tofu init && tofu validate on modules/ecs passes.
  2. Full apply chainshared/vpc-basedev/vpcshared/ecrdev/security-groupsdev/ecs all succeeded: ECR repo, 8 security groups (incl. ecs), ECS cluster test-ecs-ecs, task definition + service test-ecs-api, ALB with listener + path-pattern rule + target group.
  3. Bug found & fixed during testing — ECS service creation failed with InvalidParameterException: The container api did not have a container port 8000 defined because the task definition had no portMappings while the service references container_port in its load_balancer block. Fixed by conditionally adding portMappings when enable_alb = true (second commit on this PR). Re-apply after the fix succeeded.
  4. Destroy — all test resources cleaned up afterwards.

Reproduction steps and full report: #136 (comment) and #136 (comment)

Not tested: the GitLab deploy pipeline itself (needs a GitLab project) — jobs/rules validated as YAML only. Note that the template zips on oss.zero-one-group.com need to be rebuilt/published after merge so moon generate picks up the ECS module.

…nabled

ECS requires the container to expose a matching port mapping when the
service references a container_port in its load balancer configuration,
otherwise CreateService fails with InvalidParameterException.
…ALB module, run ECS in private subnets

- Move units under envs/{dev,staging,prod}, shared vars under variables/, ecr at root
- Drop vpc-base/full-vpc units and modules; vpc module now self-contained with
  public + private subnets and NAT gateway
- Add modules/alb (public/private, HTTP/HTTPS, per-service target groups)
- Rewrite modules/ecs: services attach to ALB target groups, tasks run in
  private subnets, least-privilege IAM (scoped ECR pull, log groups, S3/SSM)
- Add placeholder modules acm, rds-cluster, rds-single
- Add alb/elastic-ip units per env; align ecs-deploy.yml env var paths
@sintiasnn
sintiasnn force-pushed the feat/add-ecs-terragrunt-module-template branch from 3bfbe4a to b01a964 Compare August 30, 2026 08:32
The envs/dev|staging|prod restructure added a nesting level, but every
unit's terraform.source still pointed two levels up (../../modules/X)
instead of three (../../../modules/X). The top-level ecr unit had the
opposite issue. Caught by running terragrunt plan against a rendered
copy of the template in a sandbox account.
@sintiasnn

Copy link
Copy Markdown
Author

Re-test after the modules/ + envs/ restructure (ALB split into its own module, ECS moved to private subnets)

Validated end-to-end against a real AWS account (532090602408, ap-southeast-1), same setup as the earlier test in this thread.

Setup

  • Rendered the template with project_name=test-ecs, app_name=api, region=ap-southeast-1
  • State bucket test-ecs-bucket-states

Bugs found and fixed during this test

  1. Module source path depth wrong in every envs/<env>/<unit> unit — the restructure added a nesting level (dev/vpcenvs/dev/vpc), but terraform.source still pointed ../../modules/X (2 levels) instead of ../../../modules/X (3 levels). Affected all 31 units across dev/staging/prod. Terragrunt failed immediately with stat ../../modules/X: no such file or directory.
  2. Same issue on the top-level ecr unit, inverted — source was ../../modules/ecr (2 levels) but ecr/ only needs ../modules/ecr (1 level).
  3. dependency "ecr" { config_path = "../../ecr" } in envs/<env>/ecs/terragrunt.hcl — same depth miscount; needs ../../../ecr since ecr is now a sibling of envs, not of envs/<env>. This one surfaced only after the source fixes, since terragrunt couldn't evaluate the dependency graph at all before that.
  4. templates/gitlab-cicd/app/ecs-deploy.yml still cd'd into infra/terragrunt/${DEPLOY_ENVIRONMENT}/ecs (pre-restructure path); now infra/terragrunt/envs/${DEPLOY_ENVIRONMENT}/ecs.

All four are pure path fixes, no logic changes — see the two fix commits on this branch.

Apply chain (after fixes)

Applied in order: envs/dev/vpcecrenvs/dev/security-groupsenvs/dev/albenvs/dev/ecs — all succeeded:

  • VPC 10.201.0.0/16 (own VPC + IGW + NAT, not the account's default VPC) — 3 public + 3 private subnets
  • ECR repo test-ecs-app
  • 8 security groups (incl. ecs)
  • ALB test-ecs-dev-alb (public subnets) + listener + path-pattern rule + target group (health check /health)
  • ECS cluster test-ecs-ecs, task definition + service test-ecs-api, running in the private subnets, attached to the ALB's tasks security group

Task-level check

Service task went PENDINGSTOPPED with:

CannotPullContainerError: ... test-ecs-app:latest-api: not found

This is the expected failure — no image has been pushed yet. Importantly it confirms the execution role can authenticate to ECR (an IAM problem would surface as an auth error, not "not found") and that the task in the private subnet can reach ECR through the NAT gateway.

Cleanup

All test resources destroyed after this comment.

Same depth miscount as the module source path fix: ecr is a sibling
of envs, not envs/<env>, so config_path needs one more ../. Caught by
running terragrunt apply against the full chain in a sandbox account.
@sintiasnn
sintiasnn force-pushed the feat/add-ecs-terragrunt-module-template branch from 1abcc25 to 873a25f Compare August 30, 2026 10:08
Move the cross-environment ecr unit from the template root into
envs/shared/ and restore the s3 unit that was dropped in the envs/
restructure, which had left modules/s3 unreferenced. The ecs units now
depend on ../../shared/ecr.

Also fixes the Environment tag on shared units: root.hcl derives the
environment from the unit's parent directory name, so a root-level unit
was tagged with the template directory name instead of "shared".
root.hcl generates a provider config referencing var.region for every
unit, but acm, rds-cluster and rds-single never declared it, so those
three units failed with "Reference to undeclared input variable" and
could not even be planned. Caught by applying every dev unit in a
sandbox account.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ECS Fargate module to the Terragrunt template

1 participant