DEV Community

Cover image for A Simple ECS + ECR Project for Beginners

A Simple ECS + ECR Project for Beginners

Are you new to AWS and trying to understand how ECS and ECR work together to deploy your applications? This post is for you! In this simple walkthrough, we’ll learn how to containerize an app, store the image in Amazon ECR, and run it on ECS with Terraform.

✅ Prerequisites

Before you begin, ensure you have the following installed and configured:

  • ✅ AWS CLI (with credentials configured)
  • ✅ Terraform
  • ✅ Docker
  • ✅ An existing ECR repository (or Terraform will create one for you)

🧰 Services Used in This Project (with Terraform)

1. Amazon ECR (Elastic Container Registry)

🗃️ A fully managed Docker container registry to store and manage your container images.

  • Used to store the Docker image built from your app.
  • Terraform automates the creation (or reuse) of an ECR repository.
  • The ECS service pulls the image directly from ECR at runtime.

2. Amazon ECS (Elastic Container Service) with Fargate

🚢 A container orchestration service that allows you to run and scale containerized applications.

  • We use Fargate, a serverless compute engine, which removes the need to manage EC2 instances.
  • ECS takes care of deploying, scaling, and managing the container lifecycle.
  • One or more ECS tasks (containers) are run inside an ECS service backed by a cluster.

3. Amazon VPC (Virtual Private Cloud)

🌐 Isolated network environment where all AWS resources are deployed.

  • A custom VPC is provisioned with public subnets for ECS services and ALB.
  • Includes internet gateway, route tables, and security groups.
  • Provides secure and organized networking boundaries for your app.

4. Application Load Balancer (ALB)

⚖️ Distributes incoming traffic across ECS tasks running in different availability zones.

  • Exposes your application publicly over HTTP.
  • Automatically distributes traffic to available ECS containers (targets).
  • Integrates with CloudFront as the origin.

5. Amazon CloudFront (Content Delivery Network)

🚀 Delivers your content securely and quickly across the globe.

  • Sits in front of ALB and caches static and dynamic content.
  • Provides HTTPS by default using an AWS-managed SSL certificate.
  • Integrates with S3 for storing access logs and with CloudWatch for monitoring.

6. Amazon S3 (Simple Storage Service)

💾 Secure, durable object storage for any kind of data.

  • Used to store CloudFront access logs, giving visibility into who accessed what, when, and how.
  • A dedicated bucket is automatically created to collect logs.
  • Useful for debugging, auditing, and traffic analysis.

7. Amazon CloudWatch

📈 Monitoring and observability platform for AWS resources and applications.

  • Tracks key CloudFront metrics like request count, 4xx/5xx error rates, and latency.
  • Used to trigger alarms and analyze performance trends.
  • Can also log custom application or ECS-level logs if configured.

8. Amazon SNS (Simple Notification Service)

🔔 A messaging service used to send notifications based on monitoring triggers.

  • Connected to CloudWatch alarms to send email notifications.
  • Alerts you when thresholds are breached (e.g., too many 5xx errors from CloudFront).
  • Ensures you're immediately notified about potential issues or traffic spikes.

9. Terraform

🛠️ Infrastructure as Code tool used to automate and manage all cloud resources.

  • Defines, provisions, and destroys infrastructure consistently across environments.
  • Enables full automation of the VPC, ECS, ALB, CloudFront, S3, CloudWatch, and SNS setup.
  • Makes your deployments repeatable, version-controlled, and easy to maintain.

🛠️ Deployment Steps

Step 1: Initialize Terraform
Set up Terraform in your working directory.

terraform init
Enter fullscreen mode Exit fullscreen mode

Image description

Step 2: Format the Terraform Code
Clean up the Terraform files (optional but recommended):

terraform fmt
Enter fullscreen mode Exit fullscreen mode

Image description

Step 3: Prepare the Docker Image and Push to ECR
If you haven’t pushed your app image to ECR yet, Check for ecr_push.sh in scripts folder and run the commands
This script will:

  • Build the Docker image
  • Tag it with your ECR repo URL
  • Push the image to ECR

⚠️ Already have an image in ECR? You can skip this step.

✅ Final Checks Before You Deploy
🔍 1. Double-check Terraform Variable Configuration
Ensure the following are correctly defined and populated:

In variables.tf:

  • Region
  • ECR repo name
  • S3 log bucket name (optional default or dynamic name)
  • CloudFront price class or alias config (if any)
  • email for SNS Topic Subscription
  • Restrict access to specific IP addresses for security (Check in VPC module main.tf)
  • ECS Tasks memory,CPU and number of tasks
  • log retention period

Step 4: Review the Terraform Plan
Preview what Terraform will create:

terraform plan -out=tfplan
Enter fullscreen mode Exit fullscreen mode

Image description

ignore 1 to destroy

Step 5: Apply the Terraform Configuration
Deploy the infrastructure:

terraform apply tfplan
Enter fullscreen mode Exit fullscreen mode

Or simply:

if you don’t use -out=tfplan in terraform plan command

terraform apply
Enter fullscreen mode Exit fullscreen mode

Image description

Image description

During the run , you will get a subscribe mail which i used in the sns topic.Click and confirm the subscription

Image description

Image description

The deployment may take a few minutes since Terraform is provisioning several resources like ECS tasks, services, ALB, and CloudFront.
By default, Terraform automatically understands the order in which resources should be created by analyzing their dependencies using its internal dependency graph.
However, if needed, we can explicitly control the order using the depends_on attribute.

You can safely ignore this message—Terraform is attempting to recreate the ECR image, but since it already exists, it's not necessary. To avoid this in the future, you can use a Terraform lifecycle rule with ignore_changesto prevent updates to the image configuration.

✅ Step 6: Access Your Application
After Terraform finishes creating all the resources, it will automatically generate an outputs.txt file containing the key access information for your deployment.

Thanks to null_resources block in main.tf

This file includes:

- VPC ID
- ECR Repository URL
- ECS Cluster Name
- Load Balancer DNS
- CloudFront Domain Name
- CloudWatch Dashboard Name
- S3 Logs Bucket Name
- SNS Topic ARN
Enter fullscreen mode Exit fullscreen mode

⚠️ Make sure outputs.txt is not committed to version control if it contains sensitive data in real projects.

or else run command

terraform output
Enter fullscreen mode Exit fullscreen mode

Image description

Use either URL to access your web app.

Image description

Image description

🔗 Application URLs:

  • CloudFront (Global HTTPS): Recommended for production use
  • ALB DNS (Direct HTTP): Useful for internal testing or quick validation

Step 7: Clean Up Resources
When done, destroy all created AWS resources to avoid costs:

terraform destroy
Enter fullscreen mode Exit fullscreen mode

⚠️ Note on Destroying Resources
During terraform destroy, most AWS resources will be deleted automatically. However, you may see errors like this:

ECR Repository not empty – cannot delete
S3 Bucket not empty – cannot delete
Enter fullscreen mode Exit fullscreen mode

This is because:

  • Amazon ECR will not allow deletion if it still contains images.
  • Amazon S3 will not allow deletion if it contains objects/logs.

✅ Solutions
🔹 Option 1: Delete Manually via AWS Console
Go to ECR → Select your repository → Delete all images.

Go to S3 → Select the bucket → Empty the bucket → Then delete it.

🔹 Option 2: Use AWS CLI
Delete all ECR images:

aws ecr batch-delete-image \
  --repository-name ecs-ecr-demo \
  --image-ids $(aws ecr list-images --repository-name ecs-ecr-demo --query 'imageIds[*]' --output json)
Enter fullscreen mode Exit fullscreen mode

Empty and delete the S3 bucket:

aws s3 rm s3://ecs-ecr-demo-logs-<your-bucket-id> --recursive
aws s3 rb s3://ecs-ecr-demo-logs-<your-bucket-id>
Enter fullscreen mode Exit fullscreen mode

Once these are cleared, re-run:

terraform destroy
Enter fullscreen mode Exit fullscreen mode

🔁 Flow Summary

  • User sends request → CloudFront receives it over HTTPS.
  • CloudFront checks cache; if miss, forwards to ALB.
  • ALB forwards request to one of the ECS tasks (Fargate).
  • ECS Task (running NGINX) returns the response.
  • CloudFront caches and sends the response back to the user.
  • Logs go to S3; metrics go to CloudWatch; alerts (if any) go via SNS.

🎨 Design Choices

Modular Terraform Structure:

  • Each component (VPC, ECS, ECR, ALB, CloudFront) in its own module.
  • Easy to scale, maintain, or reuse.
  • Stateless Web App:
  • Simple NGINX-based static page for demo purposes.
  • Security:
  • Public subnets used for quick demo access.
  • Security groups restrict traffic to ports 80 and 443 only.

Outputs File:

A null_resource writes important info (e.g., URLs, VPC ID) into outputs.txt.

🔧 How to Customize

  • 📝 Change docker/index.html to update the website content
  • 🏗️ Edit main.tf to modify infrastructure behavior
  • 🔁 Update ECS module to change container settings

💡Tips

  • Add lifecycle { ignore_changes = [...] } in ECR module to avoid re-creation issues.
  • Use depends_on when you want to manually control resource order.
  • For real-world apps, consider using private subnets, HTTPS on ALB, and custom domains.

🚀 Try out now

📦 GitHub Repository: https://github.com/aquavis12/ecs-ecr-demo

Top comments (9)

Collapse
 
wpessers profile image
wpessers • Edited

Cool tutorial, nothing new for me. But would advise anyone following along to also look into using ecr as layer cache! You can use --cache-to and --cache-from with docker buildkit to use ecr as a remote cache. In my experience this greatly improves overall speed of docker builds! Try it ;)

Collapse
 
nevodavid profile image
Nevo David

pretty cool breakdown tbh, i learned the hard way about terraform cleanups lol - you think there’s a best way to avoid getting tripped up by all the little aws quirks?

Collapse
 
vishnu_rachapudi_75e73248 profile image
Venkata Pavan Vishnu Rachapudi

i think we can even drop those cleanup commands into a null_resource with local-exec to handle it Terraform-style. Keeps things tidy without manual hustle!

Collapse
 
nadeem_zia_257af7e986ffc6 profile image
nadeem zia

Looks really amazing

Collapse
 
saroj_c5c1240bcacc92c3d8a profile image
Saroj

Thank you 😊

Collapse
 
ravirajasekharuni profile image
ravirajasekharuni

Beautiful post

Collapse
 
jemila_bd7b584653b2b189df profile image
jemila

nice

Collapse
 
vishnu_rachapudi_75e73248 profile image
Venkata Pavan Vishnu Rachapudi

Thanks

Collapse
 
olalekan_ogundimu profile image
OLALEKAN OGUNDIMU

I'm trying this out fr 🔥🔥

Some comments may only be visible to logged-in visitors. Sign in to view all comments.