Deploy a Containerized App to ECS

Build, push, and run a Docker container on Amazon ECS with Fargate.

Introduction

30 Second Summary

Every time you open a web app, there is a container running somewhere behind the scenes serving that page. Deploying those containers used to mean managing servers, but today you can run them serverlessly and let AWS handle the infrastructure.

In this project, you will build a custom Docker image, push it to Amazon ECR, and deploy it to Amazon ECS with AWS Fargate. By the end, you will have a live web page accessible from the internet with no EC2 instances to manage.

What You'll Build

You will paste a public IP address into your browser and see your own custom web page served live from a container running serverlessly on AWS.

By the end of this project, you'll have:

  • A custom container image stored in your private ECR repository that you built, tagged, and pushed yourself.
  • A live public URL serving your web page from a Fargate container that stays online automatically with zero servers to manage.
  • Proof of ECS self-healing by stopping a running container and watching AWS replace it within seconds.
  • Secret Mission: perform a blue/green rolling update by pushing a new image version and watching ECS deploy it with zero downtime.

Are there any prerequisites?

You need an AWS account with AdministratorAccess, Docker Desktop installed on your machine, and the AWS CLI installed and configured with credentials. This project assumes you already have container experience and know how to build a Docker image.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters for your AWS certification journey. This is the moment you commit to the goal before any hands-on work begins.

Build and Push a Docker Image to Amazon ECR

Before ECS can run your container, it needs an image stored in a registry it can pull from.

Amazon ECR is AWS's private container registry. It integrates natively with ECS, so your cluster can pull images without extra authentication configuration. This native integration is why ECR is the default container registry choice on the SAA-C03 exam. In this step, you will create an ECR repository, build a Docker image locally, and push it to ECR.

In this step, get ready to:
  • Create a private ECR repository in the AWS console.
  • Build a custom Docker image that serves a web page.
  • Push the image to your ECR repository.
Create an ECR private repository

You need a place in AWS to store your container image. An ECR private repository acts as a dedicated storage location for your Docker images, accessible only to your AWS account.

  • Open your web browser and navigate to the Amazon ECR console at https://console.aws.amazon.com/ecr/repositories.
  • Sign in with your AWS account credentials if prompted.
  • In the left navigation pane, choose Private repositories.
  • Click Create repository.
  • For Repository name, enter ecs-fargate-app.
  • Leave Tag immutability set to Mutable.
  • Leave Encryption settings set to AES-256.
  • Click Create.

You should see a green success banner and your new ecs-fargate-app repository listed on the Private repositories page.

What is an ECR repository?

Think of an ECR repository like a named folder for your Docker images. Each repository holds multiple versions (tags) of the same application image. ECS pulls from this repository when it launches your containers.

Don't see the Create repository button?

Make sure you selected Private repositories in the left navigation, not Public repositories. ECR has both public and private sections.

If you see a permissions error, confirm your AWS account has AdministratorAccess attached to your IAM user.

Help me troubleshoot this

Build a Docker image locally

Now you will create a simple web application and package it as a Docker image. The image uses the official Apache HTTP Server to serve a custom HTML page.

  • Open your terminal. Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir ecs-fargate-app
cd ecs-fargate-app

Now create the two files your Docker image needs. First, the web page itself.

  • Create a file named index.html inside your ecs-fargate-app folder and paste the following content:
<!DOCTYPE html>
<html>
<head><title>ECS Fargate App</title></head>
<body style="background-color:#232F3E; color:white; font-family:Arial, sans-serif; text-align:center; padding:50px;">
  <h1>Hello from ECS Fargate!</h1>
  <p>Version 1 - Running on AWS Fargate</p>
</body>
</html>

What does this HTML do?

This is a simple web page with a dark background (AWS's signature color #232F3E) and white text. It displays a heading and a version label. You will use this version label later to confirm deployments.

  • Create a file named Dockerfile (no extension) in the same ecs-fargate-app folder and paste the following content:
FROM httpd:2.4
COPY ./index.html /usr/local/apache2/htdocs/index.html

What does this Dockerfile do?

The FROM httpd:2.4 line pulls the official Apache HTTP Server image as the base. This gives you a fully configured web server out of the box.

The COPY line places your custom HTML file into Apache's default serving directory. When the container starts, Apache automatically serves this page on port 80.

  • Confirm both files exist by running:
ls

You should see Dockerfile and index.html in the output.

  • Build the Docker image by running this command:
docker build -t ecs-fargate-app .

Docker pulls the httpd:2.4 base image (if not already cached) and packages your HTML file into a new image tagged ecs-fargate-app.

  • Verify the image was built successfully by running:
docker images ecs-fargate-app

You should see one row listing ecs-fargate-app with the tag latest and a size of approximately 150-170 MB.

Seeing 'docker: command not found'?

Make sure Docker Desktop is running. Look for the Docker whale icon in your system tray (Windows) or menu bar (macOS). If it is not there, open Docker Desktop and wait for it to show "Running" before retrying the command.

Help me fix Docker

✔️ Awesome, I've got everything!

Great. Make sure both index.html and Dockerfile are saved in your ecs-fargate-app folder on your Desktop.

ⓧ I'd like to double check the full code

Here is the complete Dockerfile:

FROM httpd:2.4
COPY ./index.html /usr/local/apache2/htdocs/index.html

Here is the complete index.html:

<!DOCTYPE html>
<html>
<head><title>ECS Fargate App</title></head>
<body style="background-color:#232F3E; color:white; font-family:Arial, sans-serif; text-align:center; padding:50px;">
  <h1>Hello from ECS Fargate!</h1>
  <p>Version 1 - Running on AWS Fargate</p>
</body>
</html>
Push the image to ECR

Your image exists locally, but ECS cannot access it until you push it to your ECR repository. The ECR console provides pre-built push commands tailored to your account and region.

  • Return to the ECR console in your browser.
  • Click on your ecs-fargate-app repository name to open it.
  • Click the View push commands button at the top right.

A dialog appears showing four commands customized for your AWS account and region.

  • Copy and run command 1 in your terminal. This authenticates Docker to your ECR registry.
  • Skip command 2 (the build command). You already built your image in the previous substep.
  • Copy and run command 3. This tags your local image with your ECR repository URI.
  • Copy and run command 4. This pushes the tagged image to ECR.

What do these commands do?

Command 1 uses aws ecr get-login-password to generate a temporary authentication token, then pipes it to docker login. This gives Docker permission to push to your private ECR registry.

Command 3 re-tags your local ecs-fargate-app:latest image with the full ECR repository URI (including your account ID and region). ECR requires this specific naming format to know where to store the image.

Command 4 uploads the image layers to ECR. You will see progress bars as each layer pushes.

The push takes about 30-60 seconds depending on your internet speed. Wait until you see a final digest line confirming the push completed.

Before you check the console, what do you expect to see in your ECR repository now?

  • Back in the ECR console, click on your ecs-fargate-app repository.

You should see your image listed with the latest tag and its size displayed (approximately 150-170 MB).

Seeing 'no basic auth credentials' error?

This means the authentication from command 1 failed or expired. Make sure you ran command 1 first and that it printed Login Succeeded. If not, check that your AWS CLI credentials are configured correctly by running:

aws sts get-caller-identity

This should display your account ID. If it shows an error, reconfigure your AWS CLI credentials before retrying.

Help me fix ECR authentication

Your container image is now stored in AWS and ready for ECS to pull. Next up, you will create the ECS cluster where your container will run.

Create an ECS Cluster

Your Docker image is safely stored in ECR. Now you need somewhere for ECS to actually run that container.

A cluster is the logical grouping where your tasks and services live. With Fargate, the cluster contains no EC2 instances because ECS manages all the compute behind the scenes.

In this step, get ready to:
  • Create an ECS cluster configured with AWS Fargate.
  • Verify the cluster is active and ready for tasks.
Create your ECS cluster

Without a cluster, ECS has nowhere to schedule your containers. Let's create one using the ECS console.

  • Navigate to the Amazon ECS console at https://console.aws.amazon.com/ecs/v2.
  • In the left navigation pane, choose Clusters.
  • Click Create cluster.
  • Enter fargate-lab-cluster in the Cluster name field.
  • Under Infrastructure, confirm that AWS Fargate (serverless) is already selected. This is the default.
  • Leave Container Insights unchecked.
  • Click Create.

What is an ECS cluster with Fargate?

On the SAA-C03 exam, a key distinction is that a Fargate cluster is NOT a group of servers. There are no EC2 instances to patch, scale, or manage.

The cluster is purely a logical boundary. When you launch tasks into it, Fargate provisions the exact compute resources each task needs, then reclaims them when the task stops. You only pay for what your containers actually use.

Before you check the result, what do you expect to see on the Clusters page? Think about what status a brand-new cluster with no deployed tasks would show.

The Clusters page now shows your fargate-lab-cluster with Status Active and 0 running tasks.

Cluster creation failed?

If you see a permissions error, confirm your IAM user has AdministratorAccess attached. ECS needs permissions to create the cluster's service-linked role on first use.

If the cluster stays in "Provisioning" state for more than a minute, refresh the page. The status should update to Active.

Why can't I create my ECS cluster?

Your cluster is live and waiting for work. Next up, you'll create a task definition that tells ECS exactly how to run your container.

Create a Task Definition

Your cluster is active, but it has no instructions for what to run. A task definition is the blueprint that tells ECS which container image to pull, how much CPU and memory to allocate, and which ports to expose.

On the SAA-C03 exam, you need to know that Fargate task definitions require three specific settings: requiresCompatibilities set to FARGATE, networkMode set to awsvpc, and valid CPU/memory pairs. In this step, you will create your task definition using JSON in the ECS console.

In this step, get ready to:
  • Create a Fargate-compatible task definition that references your ECR image.
  • Configure CPU, memory, network mode, and port mappings for your container.
  • Verify the task definition is active and ready for deployment.
Navigate to the task definition JSON editor

The ECS console offers two ways to create a task definition: a form-based editor and a JSON editor. The JSON editor gives you precise control over every parameter, which is exactly what you need to understand for the exam.

  • Return to the ECS console at https://console.aws.amazon.com/ecs/v2.
  • In the navigation pane, choose Task definitions.
  • On the Create new task definition dropdown menu, choose Create new task definition with JSON.

You should see a JSON editor box with some pre-populated placeholder JSON.

Paste your task definition JSON

Your task definition needs to reference the ECR image you pushed in Step 1. It also specifies the Fargate-compatible settings: awsvpc network mode, CPU/memory limits, and the container port.

  • Delete any pre-populated JSON in the editor.
  • Copy and paste the following JSON into the editor, replacing the placeholder values with your own AWS account ID and region:
{
    "family": "ecs-fargate-app",
    "networkMode": "awsvpc",
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512",
    "executionRoleArn": "arn:aws:iam::[[AWS_ACCOUNT_ID=\"your 12-digit AWS account ID\"]]:role/ecsTaskExecutionRole",
    "containerDefinitions": [
        {
            "name": "ecs-fargate-app",
            "image": "[[AWS_ACCOUNT_ID=\"your 12-digit AWS account ID\"]].dkr.ecr.[[AWS_REGION=\"your AWS region e.g. us-east-1\"]].amazonaws.com/ecs-fargate-app:latest",
            "essential": true,
            "portMappings": [
                {
                    "containerPort": 80,
                    "protocol": "tcp"
                }
            ]
        }
    ]
}

What does this JSON do?

  • family names this task definition so ECS can track revisions of it over time.
  • networkMode: awsvpc gives each task its own elastic network interface (ENI) with a private IP. This is the only network mode Fargate supports.
  • requiresCompatibilities: FARGATE tells ECS to validate this definition against Fargate requirements.
  • cpu: 256 and memory: 512 allocate 0.25 vCPU and 0.5 GB of memory. This is the smallest (and cheapest) Fargate task size.
  • executionRoleArn points to the ecsTaskExecutionRole IAM role. ECS uses this role to pull your image from ECR and write logs to CloudWatch. The console creates this role automatically if you have AdministratorAccess.
  • containerPort: 80 exposes port 80 from your Apache container so traffic can reach it.

Find your account ID and region

Your 12-digit AWS account ID is visible in the top-right corner of the console (click your username to see it). Your region code (like us-east-1) appears in the region selector next to it. These are the same values you used when pushing your image to ECR in Step 1.

Create the task definition and verify

Before you click Create, think about what you expect to happen. Will ECS accept this definition, or will it reject it?

  • Click Create.

ECS validates your JSON and registers the task definition. You should now see your ecs-fargate-app task definition listed on the Task Definitions page with status Active and FARGATE listed under compatibility.

Seeing a validation error?

  • Check that your account ID is exactly 12 digits with no spaces or dashes.
  • Make sure your region code matches the region where you created your ECR repository (check the region selector in the top-right).
  • Verify there are no trailing commas or missing brackets in your JSON.

Help me fix my ECS task definition JSON.

What is the ecsTaskExecutionRole?

This is an IAM role that ECS assumes on your behalf. It grants ECS permission to pull container images from ECR and send container logs to CloudWatch.

If this is your first time using ECS with AdministratorAccess, the console creates this role automatically. You do not need to create it manually.

Your blueprint is locked in. ECS now knows exactly what image to pull, how much compute to give it, and which port to expose. Next up, you will use this task definition to launch a running service on Fargate and access your app from the internet.

Deploy a Fargate Service and Access Your App

Your task definition is a blueprint, but it does not run anything on its own. You need an ECS Service to actually launch and maintain your container.

The service ensures that if your task crashes, ECS relaunches it automatically. This self-healing behavior is the resilience pattern tested in SAA-C03 Domain 2.

In this step, get ready to:
  • Create an ECS service that runs your task definition on Fargate.
  • Configure networking so your container is accessible from the internet.
  • Find your running task's public IP and view your app in the browser.
Create the ECS service

A service tells ECS to launch your task and keep it running at your desired count. You will create one now inside your existing cluster.

  • Switch back to the Clusters page in the ECS console.
  • Click fargate-lab-cluster.
  • Select the Services tab.
  • Click Create.

The service creation wizard opens with several configuration sections.

  • Under Environment, confirm that Launch type is selected and set to FARGATE.
  • Under Deployment configuration, select ecs-fargate-app from the Family dropdown.
  • Enter ecs-fargate-service in the Service name field.
  • Set Desired tasks to 1.

What does Desired tasks mean?

This number tells ECS how many copies of your task to keep running at all times. If a task stops or crashes, the service automatically launches a replacement to maintain this count.

Configure networking and security

Your task uses awsvpc network mode, which gives it its own network interface. You need a security group that allows HTTP traffic so the internet can reach your container on port 80.

  • Scroll down to the Networking section and expand it.
  • For VPC, leave the default VPC selected.
  • For Subnets, leave the default subnets selected.
  • For Security group, choose Create a new security group.
  • Enter ecs-fargate-sg as the security group name.
  • Enter Allow HTTP traffic for ECS Fargate tasks as the description.
  • Add an inbound rule with Type HTTP, Port range 80, and Source Anywhere (0.0.0.0/0).
  • For Public IP, make sure it is turned ON.

Why does Public IP need to be ON?

Fargate tasks in a public subnet need a public IP to be reachable from the internet. Without it, your task has only a private IP that is not routable outside the VPC.

  • Click Create at the bottom of the page.

ECS begins provisioning your task. This typically takes 30-60 seconds.

Service stuck in Provisioning?

If your service stays in a provisioning state for more than two minutes, check that your subnets have available IP addresses and that your security group rules are correct. Also confirm your task definition references a valid ECR image URI.

help me troubleshoot why my ECS Fargate service is stuck provisioning

Access your running app

Once your service reaches the Running state, your container is live and serving traffic. Now you will find its public IP and open your web page.

  • Wait until the service status shows Active and the Running tasks count shows 1/1.
  • Click the Tasks tab inside your service.
  • Click your running task (the one with status Running).
  • In the Configuration section, find the Public IP field.
  • Click Open address.

Before you look at the browser, what do you expect to see?

Your browser displays your custom web page with a dark background, the heading "Hello from ECS Fargate!" and the text "Version 1 - Running on AWS Fargate". This is your container serving live traffic from Fargate with no EC2 instances to manage.

Seeing a connection timeout?

Make sure your security group has an inbound rule allowing HTTP on port 80 from 0.0.0.0/0. Also confirm that Public IP was set to ON when creating the service.

help me fix my ECS Fargate task that is not reachable via public IP

Your container is live on the internet, running entirely serverless on Fargate. Next up, you will test just how resilient this setup really is by intentionally stopping your task.

Observe the Resilience

Your container is running and serving your web page. But what happens if that container crashes?

In production, containers fail all the time. ECS services promise to maintain your desired task count automatically, restarting containers when they go down. In this step, you will intentionally kill your running task and watch ECS bring it back to life.

In this step, get ready to:
  • Stop your running Fargate task manually.
  • Observe ECS automatically launching a replacement task.
  • Access your app at the new public IP address.
Stop your running task

Your ECS service currently has a desired count of 1. That means it wants exactly one task running at all times. You are about to remove that task by force and see what the service does about it.

  • In the ECS console, click Clusters in the left navigation pane.
  • Click your fargate-lab-cluster cluster.
  • Select the Services tab, then click ecs-fargate-service.
  • Click the Tasks tab.
  • Select the checkbox next to your running task.
  • Click Stop, then confirm the stop action.

Your task status changes to Stopping. After a few seconds, it becomes Stopped.

Before you do anything else, think about what will happen next. You told the service you want 1 task running, but you just stopped the only task. Do you think ECS will leave the service at 0 tasks, or will it launch a replacement?

Watch ECS replace the stopped task
  • Wait 30 to 60 seconds.
  • Click the refresh icon on the Tasks tab.

You should see two entries. The original task shows Stopped status. A brand new task appears with a different Task ID and shows Running (or Provisioning if you refresh quickly).

What just happened?

The ECS service controller continuously monitors the running task count. When you stopped the task, the actual count dropped to 0 while the desired count remained at 1.

ECS detected this mismatch and automatically launched a new task to reconcile. This self-healing behavior is why ECS services are the standard for production workloads on the SAA-C03 exam. You never manually restart crashed containers.

Still seeing only the stopped task?

ECS can take up to 60 seconds to detect the mismatch and launch a replacement. Refresh the Tasks tab again after waiting a full minute. If the new task shows Provisioning or Pending, keep refreshing until it transitions to Running.

Why isn't ECS replacing my stopped task?

Access your app at the new public IP

The replacement task has a completely new public IP address. The old IP no longer works. This is important to understand for production architectures. A load balancer or DNS layer would hide this IP change from users.

  • Click on the new task (the one with Running status).
  • In the Configuration section, find the Public IP field.
  • Choose Open address to open the IP in your browser.

Your custom web page is back online. No manual intervention was needed to bring it back. ECS handled the entire recovery automatically.

Why does this matter for the SAA-C03 exam?

This self-healing behavior maps directly to SAA-C03 Domain 2, which covers designing highly available and fault-tolerant architectures. ECS services with a desired count give you automatic recovery without managing health checks on individual EC2 instances.

In a production setup, you would place a load balancer in front of the service. The load balancer provides a stable DNS name so users never see the IP address change during task replacements.

Secret mission

Blue/Green Deployment with a New Image Version

You proved your service self-heals. Now take it further by deploying a new version of your app with zero downtime. Push a v2 image to ECR, create a new task definition revision, and watch ECS perform a rolling update that keeps your app live throughout the switch.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. Your Fargate task incurs ongoing compute charges while running.

Cost warning

Your running Fargate task costs approximately $0.04/hr for vCPU and $0.004/hr for memory at the smallest task size (0.25 vCPU, 0.5 GB). That adds up to roughly $0.30/day. If you are done experimenting, pause or delete your resources to stop charges.

Resources you used:

  • ECR private repository (ecs-fargate-app) storing your container images.
  • ECS cluster (fargate-lab-cluster) running your Fargate service.
  • ECS service (ecs-fargate-service) maintaining 1 running Fargate task.
  • Local project files (Dockerfile and index.html).

Keep everything running

No action needed. Choose this if you are still actively experimenting with ECS and Fargate. Your task will continue running and serving your web page at its public IP.

  • Your Fargate task costs approximately $0.30/day at the smallest size (0.25 vCPU, 0.5 GB memory).
  • The ECS cluster control plane has no charge.
  • Your ECR repository is covered by the free tier (500 MB storage for the first 12 months).

Pause - I'll come back to this later

You cannot pause a Fargate task directly. Scale your service to 0 desired tasks to stop compute charges while keeping the cluster and task definition intact.

  • Open the ECS console at https://console.aws.amazon.com/ecs/v2.
  • In the navigation pane, choose Clusters, then select fargate-lab-cluster.
  • Choose the Services tab, select the checkbox next to ecs-fargate-service, then choose Update.
  • Set Desired tasks to 0.
  • Choose Update to apply.

ECS will drain your running task. Once the task stops, Fargate compute charges stop. Your cluster, task definition, and ECR repository remain intact with no ongoing cost (ECR stays within free tier).

Delete - I don't want to use this again

Remove all project resources and stop all charges. Follow these steps in order.

Delete the ECS service:

  • Open the ECS console at https://console.aws.amazon.com/ecs/v2.
  • Choose Clusters, then select fargate-lab-cluster.
  • Choose the Services tab, select the checkbox next to ecs-fargate-service, then choose Delete.
  • In the confirmation dialog, type delete and choose Delete to confirm.

Delete the ECS cluster:

  • Return to the Clusters page in the ECS console.
  • Select fargate-lab-cluster, then choose Delete Cluster.
  • Type delete fargate-lab-cluster in the confirmation field and choose Delete.

Delete the ECR repository:

  • Open the Amazon ECR console at https://console.aws.amazon.com/ecr/repositories.
  • On the Repositories page, choose the Private tab, then select ecs-fargate-app and choose Delete.
  • In the confirmation window, verify the repository name and choose Delete. This permanently removes all images in the repository.

Delete your local project files:

  • Delete the folder containing your Dockerfile and index.html from your Desktop.

Nice Work!

Nice Work!

You just deployed a containerized web application to Amazon ECS with AWS Fargate. You now have a live, publicly accessible app running serverless with no EC2 instances to manage.

You've learned how to:

  • Built and stored a custom container image in a private Amazon ECR repository, making it available for ECS to pull without extra authentication.
  • Deployed a live web app on Fargate by wiring together an ECS cluster, a task definition (the container blueprint), and a service that keeps your container alive and accessible via a public IP.
  • Proved ECS service resilience by stopping a running task and watching ECS automatically launch a replacement to maintain your desired count.
  • Secret Mission: Performed a blue/green rolling update by pushing a v2 image to ECR and updating the service, achieving zero-downtime deployment.

Ready to quiz yourself?