ECS Fargate Blue/Green Deployments with CodeDeploy
Test before traffic, shift gradually, roll back on alarms
Basis: Portfolio implementation with a synthetic application. Not presented as client work.
Overview
Multi-environment ECS Fargate services on Graviton deployed with CodeDeploy blue/green: new tasks are smoke-tested on a test listener before any user traffic, traffic shifts all-at-once in dev, linearly in staging and by canary in production, and alarms on error rate or latency roll back automatically.
Problem
Rolling deployments replace tasks in place: by the time a problem is visible, part of production is already running the bad version, and rollback means another rolling deploy. Teams also rarely test a release on production infrastructure before users see it.
Solution
Run the new version as a separate task set behind a second target group. A lifecycle hook smoke-tests it through a test listener before any traffic moves; CodeDeploy then shifts production traffic by the environment's policy while alarms on the new target group watch 5xx rate and p95 latency, rolling back to the untouched blue set if they fire.
Architecture
Per-environment ALB
Prod listener :443
default action → blue/green
Test listener :8443
CIDR-restricted
Target groups
Blue
current task set
Green
replacement task set
ECS Fargate
Service
CODE_DEPLOY controller
ARM64 tasks
on-demand base + Spot
Deployment control
CodeDeploy
AllAtOnce / Linear / Canary
Hook Lambdas
before / after traffic
Alarms
5xx + p95 per colour
Failure and recovery path
- BeforeAllowTraffic hook fails its smoke test (health, version, latency budget) — no user traffic ever reaches the new version.
- During a canary or linear shift, a 5xx or p95 latency alarm fires — CodeDeploy stops and routes all traffic back to blue.
- In production, traffic only shifts after a manual reroute approval within a bounded wait window.
- Blue tasks are kept for a termination wait period after a successful deployment, so a fast manual rollback is still possible.
Technology stack
- ECS Fargate (ARM64)
- Fargate Spot
- AWS CodeDeploy
- Application Load Balancer
- AWS Lambda (hooks)
- CloudWatch alarms
- Amazon ECR
- Terraform
- Docker buildx
Implementation
- Terraform: a shared module for ECR and the cluster, and a per-environment service module with its ALB, listeners, blue/green target groups, service, task definition, autoscaling, CodeDeploy app and deployment group, alarms and hook functions.
- Environment settings live in JSON files read by both Terraform and a policy lint: production cannot use all-at-once, must have alarms and auto-rollback, and the test listener cannot be open to the internet.
- Stdlib Python hook Lambdas read the expected image tag from the deployment itself and always report success or failure exactly once, even on exceptions.
- A traffic-shift simulator prints the timeline for each deployment config and shows where an alarm triggers rollback — documented as a model.
- 105 unit tests; the ARM64 image was built and run locally with a read-only filesystem and a non-root user; CI builds it with buildx.
Security
- Test listener reachable only from listed CIDRs (e.g. the NAT addresses the hooks use), separately per environment.
- Least-privilege task and execution roles; secrets injected from Secrets Manager; non-root, read-only containers.
- ALB egress restricted to the container port inside the VPC.
Reliability
- Alarms exist for both colours because CodeDeploy alternates which target group is the replacement on each deployment.
- Request-count autoscaling sums both target groups during a deployment.
- The rejected alternative — host rules on a shared listener — is documented in an ADR along with ECS-native blue/green as the option when a shared ALB is required.
Cost
- Blue/green runs two task sets during each deployment; one ALB per environment adds roughly $33/month over a shared ALB at idle (illustrative list prices, see the cost doc).
- Graviton plus Fargate Spot lowers the steady-state cost; production keeps an on-demand base.
Results
No quantified results are published for this project. Figures from client work are confidential, and this portfolio only shows numbers that can be verified or reproduced.
Code & documentation
Lessons learned
- The deployment strategy belongs to the environment: speed in dev, gradual exposure in staging, gated canary in production.
- Design to the documented integration shape — here, listener default actions — rather than an unverified shortcut.
- Known gaps, stated in the README: nothing has run in AWS, the CodeDeploy role uses the broad managed policy, and the simulator does not model hook duration.