case study · containers · CI/CD

CI/CD for AWS container services

A push-to-deploy pipeline for a Dockerized Python application on ECS Fargate, with Terraform infrastructure and short-lived AWS credentials from GitHub OIDC.

problem

Deploy containers without stored AWS keys or manual server work

The project needed a repeatable path from a source commit to a running container. Infrastructure, image version and deployment state had to remain reviewable rather than being assembled manually in the AWS console.

architecture

Public load balancer, private application tasks

Container application architecture: an Application Load Balancer routes traffic to ECS Fargate tasks in private subnets
The public Application Load Balancer is the only internet-facing application component. It forwards requests to Flask containers running as ECS Fargate tasks in private subnets; CloudWatch receives task logs.

Security-group ingress ties the ECS service directly to the load balancer security group instead of allowing a broad network range. Terraform defines the VPC, subnets, ECR repository, load balancer, ECS cluster, task definition and service.

CI/CD pipeline from a GitHub push through OIDC authentication, Docker build, ECR and Terraform deployment to ECS
GitHub Actions assumes an AWS role with OIDC, builds a commit-addressed image, pushes it to ECR and passes that image URL into Terraform.

decisions and tradeoffs

Key design decisions

OIDC instead of repository access keys
GitHub receives temporary AWS credentials for each run. IAM trust configuration is more involved, but there is no long-lived secret to rotate or leak.
Commit SHA image tags
Each task definition points to an immutable, traceable build rather than an ambiguous latest tag.
Fargate instead of managed EC2 hosts
The deployment avoids patching container hosts. Per-task pricing can cost more than well-utilized EC2 capacity.
Terraform receives the image URL
Application versions and infrastructure changes share one plan, while the infrastructure remains independent of a hardcoded build.

what broke

The deployment needs an explicit image handoff

Building and pushing an image does not update a running ECS service by itself. The workflow must pass the commit-tagged ECR URL into Terraform so a new task-definition revision is created and ECS can perform the rolling replacement.

pipeline

From push to healthy task