DEV Community

Cover image for Deploying a Containerized Application on AWS Using Terraform
Nishath J P
Nishath J P

Posted on

Deploying a Containerized Application on AWS Using Terraform

Today I built a reproducible AWS infrastructure with Terraform and Created AWS services like ECS Fargate, ECR, ALB, RDS PostgreSQL, Secrets Manager, and CloudWatch then Debugged a real ECS deployment failure. This project is called CloudForge

Introduction

When learning AWS and DevOps, it is easy to create individual resources through the AWS Console without fully understanding how they work together.

But to understand how things really work and unlock the true potential of cloud we must learn IaC (Infrastructure as code) in this case I choose Terraform.

I spent around a 3 days to learn how terraform works:

  • Basic commands
  • Variables
  • Dependencies
  • LifeCycle Rules
  • State & Remote State
  • Provisioners
  • Modules etc...

As I already good with cloud and have various certifications on both AWS and Azure it was easy for me.

Then went directly in to project. Because learning theory and project is totally different.

Project CloudForge

*What is CloudForge?
*

CloudForge is a Terraform-based AWS infrastructure project for deploying a containerized application using managed AWS services.

The infrastructure is completely defined using Terraform rather than manually creating each resource through the AWS Console.

The infrastructure i planned was this:

Caption: CloudForge architecture — Terraform-managed AWS infrastructure with ECS Fargate, ALB, ECR, RDS PostgreSQL, Secrets Manager, and CloudWatch.

AWS Services I used
Amazon VPC : Provides the network for the application
Public Subnets : Hosts internet-facing components
Private Subnets : Hosts ECS tasks and database resources
Internet Gateway : Provides internet connectivity
NAT Gateway : Provides outbound internet access for private resources
Application Load Balancer : Receives HTTP traffic and forwards it to ECS Fargate : Runs the Docker container
Amazon ECR : Stores the Docker image
RDS PostgreSQL : Provides the managed PostgreSQL database
Secrets Manager : Stores database credentials
CloudWatch : Provides logging and monitoring
IAM : Controls AWS permissions

After that I used some AI assist for writing the code and reviewed it manually.

Building the AWS Infrastructure with Terraform

Once the application and container were ready, I moved on to the infrastructure.

The first step was:

terraform init

Enter fullscreen mode Exit fullscreen mode

This initializes Terraform and downloads the required providers.

Then:

terraform fmt

Enter fullscreen mode Exit fullscreen mode

to format the configuration files.

Next:

terraform validate

Enter fullscreen mode Exit fullscreen mode

to verify that the Terraform configuration is syntactically valid.

Finally:

terraform plan

Enter fullscreen mode Exit fullscreen mode

This allowed me to review what Terraform was going to create before actually making changes to AWS.

Deploying the Infrastructure

After reviewing the plan, I ran:

terraform apply

Enter fullscreen mode Exit fullscreen mode

Terraform then created the AWS infrastructure and handled the dependencies between the resources.

The deployment completed successfully:

Apply complete! Resources: 38 added, 0 changed, 0 destroyed.

Enter fullscreen mode Exit fullscreen mode

🚨 The Deployment Didn't Work

At this point, the infrastructure was deployed.

The ALB was active.
ECS was configured.
The Docker image was in ECR.
RDS was available.
Everything looked correct.

But when I opened the ALB URL...

I got:

503 Service Temporarily Unavailable

Enter fullscreen mode Exit fullscreen mode

Then I started troubleshooting:

Investigating the ECS Service

The ECS service was continuously starting and replacing tasks.

The first thing I checked was the ECS service status.

The important relationship was:

ALB
 ↓
Target Group
 ↓
ECS Service
 ↓
ECS Task
 ↓
Docker Container
Enter fullscreen mode Exit fullscreen mode

Instead of immediately changing the ALB or networking configuration, I followed the request path backward.

The target health showed that the target was not becoming healthy.

That suggested the problem might be inside the ECS task itself.

Testing the Docker Image Locally

I went back to the most basic layer:

Docker and ran:

docker run --rm -it cloudforge:latest

Enter fullscreen mode Exit fullscreen mode

But the container exited immediately.

That was a major clue.

I then inspected the image:

docker inspect cloudforge:latest \
  --format='Entrypoint={{json .Config.Entrypoint}} Cmd={{json .Config.Cmd}}'
Enter fullscreen mode Exit fullscreen mode

The output showed:

Entrypoint=null
Cmd=["python","main.py"]
Enter fullscreen mode Exit fullscreen mode

So the container was configured to run:

python main.py

Enter fullscreen mode Exit fullscreen mode

I then opened a shell inside the image and inspected the application.

The Actual Problem 😅

I checked:

ls -l /app/main.py

Enter fullscreen mode Exit fullscreen mode

And found something I wasn't expecting:

-rw-rw-r-- 1 root root 0 ... main.py

Enter fullscreen mode Exit fullscreen mode

The file was:

0 bytes.

The application file inside the Docker image was empty.

So the actual failure chain was:

main.py = 0 bytes

python main.py

Application doesn't start

Container exits

ECS task stops

ECS starts another task

New task also stops

ALB has no healthy backend

503 Service Temporarily Unavailable

The problem wasn't the ALB.

It wasn't the NAT Gateway.

It wasn't RDS.

It wasn't ECS networking.

The actual problem was sitting inside the container.

This was a great reminder that cloud infrastructure can be perfectly configured while the application itself is still broken.

Fixing the Container

I fixed the application and Docker configuration and rebuilt the image.

docker build -t cloudforge:latest .

Enter fullscreen mode Exit fullscreen mode

Before pushing it to AWS, I tested it locally again:

docker run --rm -p 8000:8000 cloudforge:latest

Then:

curl http://localhost:8000/health

Enter fullscreen mode Exit fullscreen mode

Once the container worked locally, I pushed the corrected image to ECR:

docker tag cloudforge:latest <ECR_URI>:latest
docker push <ECR_URI>:latest

Then I triggered a new ECS deployment.

Successful Deployment

After the new deployment, ECS finally showed:

Desired: 1
Running: 1
Pending: 0

Enter fullscreen mode Exit fullscreen mode

The ALB target became healthy.

And the application became accessible through the ALB DNS name.

Conclusion

CloudForge started as a project to learn Terraform, but the troubleshooting experience was the most valuable part.

When the ALB returned a 503, I traced the issue from:

ALB → ECS → Docker → Application

The root cause turned out to be surprisingly simple: main.py inside the Docker image was 0 bytes.

After fixing the application, rebuilding the image and redeploying it, the ECS task became healthy and the application was accessible through the ALB.

Infrastructure as Code gets your infrastructure deployed. Troubleshooting gets your application running.

🔗 Source Code

The complete project is available on GitHub: https://github.com/Nishath06/aws-terraform-cloudforge

Top comments (2)

Collapse
 
mathu_mitha_60a3b462eafc3 profile image
Mathu Mitha

Great work! 🚀 Really insightful project and troubleshooting experience!

Collapse
 
purvi_jondhalekar_88f026e profile image
Purvi Jondhalekar

Intresting