Full Stack • Java • System Design • Cloud • AI Engineering

Spring Boot with AWS ECS Fargate

Learn how to deploy a Spring Boot application on AWS ECS Fargate step by step using Docker, Amazon ECR, ECS Cluster, Task Definition, Fargate Service, Security Groups, CloudWatch Logs, and production best practices.


Introduction

In the previous article, we deployed a Spring Boot application using AWS Elastic Beanstalk.

Elastic Beanstalk is simple and beginner-friendly, but modern cloud-native applications are commonly deployed as containers.

AWS ECS Fargate allows us to run Docker containers without managing EC2 servers.

With Fargate, AWS manages the infrastructure. We only provide:

  • Docker image
  • CPU and memory
  • Networking
  • Environment variables
  • Desired number of running tasks

In this article, we will deploy a Spring Boot application on AWS ECS Fargate step by step.


What You Will Learn

  • What is Amazon ECS?
  • What is AWS Fargate?
  • ECS vs EC2 vs Elastic Beanstalk
  • How to Dockerize Spring Boot
  • How to push Docker image to Amazon ECR
  • How to create ECS Cluster
  • How to create ECS Task Definition
  • How to run Spring Boot on Fargate
  • How to configure Security Groups
  • How to view CloudWatch logs
  • Input and output examples
  • Common errors and fixes
  • Production best practices

What is Amazon ECS?

Amazon ECS stands for Elastic Container Service.

It is a container orchestration service from AWS.

ECS helps run and manage Docker containers in AWS.

ECS can run containers using two launch types:

Launch Type Meaning
EC2 You manage EC2 instances
Fargate AWS manages servers for you

What is AWS Fargate?

AWS Fargate is a serverless compute engine for containers.

You do not need to manage:

  • EC2 instances
  • Operating system patches
  • Docker runtime installation
  • Server scaling
  • Cluster capacity

You only define:

  • Container image
  • CPU
  • Memory
  • Port
  • Environment variables
  • IAM roles
  • Networking

ECS Fargate Architecture

flowchart TD
    DEV[Developer Machine]
    APP[Spring Boot Application]
    DOCKER[Docker Image]
    ECR[Amazon ECR Repository]
    ECS[ECS Cluster]
    TASK[Task Definition]
    FARGATE[Fargate Task]
    CW[CloudWatch Logs]
    USER[User Browser]

    DEV --> APP
    APP --> DOCKER
    DOCKER --> ECR
    ECR --> TASK
    TASK --> ECS
    ECS --> FARGATE
    FARGATE --> CW
    USER --> FARGATE

Production ECS Fargate Architecture

flowchart TD
    U[Users]
    R53[Route 53]
    ALB[Application Load Balancer]
    ECS[ECS Cluster]
    SVC[ECS Service]
    T1[Fargate Task 1]
    T2[Fargate Task 2]
    ECR[Amazon ECR]
    RDS[(Amazon RDS)]
    CW[CloudWatch Logs]

    U --> R53
    R53 --> ALB
    ALB --> SVC
    SVC --> T1
    SVC --> T2
    ECR --> T1
    ECR --> T2
    T1 --> RDS
    T2 --> RDS
    T1 --> CW
    T2 --> CW

ECS Important Concepts

Concept Meaning
Cluster Logical group for running containers
Task Definition Blueprint for container configuration
Task Running container instance
Service Keeps desired number of tasks running
ECR Docker image registry
Fargate Serverless compute for containers
Load Balancer Routes traffic to running containers

Prerequisites

Before starting, you need:

AWS Account
AWS CLI
Docker Desktop
Java 17 or Java 21
Maven
Spring Boot Project
IAM permissions for ECS, ECR, CloudWatch, IAM, VPC

Verify Java:

java -version

Output:

openjdk version "17.0.x"

Verify Maven:

mvn -version

Output:

Apache Maven 3.x.x

Verify Docker:

docker --version

Output:

Docker version 25.x.x

Verify AWS CLI:

aws --version

Output:

aws-cli/2.x.x

Step 1: Create Spring Boot Application

Create a Spring Boot project with:

Spring Web
Spring Boot Actuator
Java 17
Maven

Project structure:

springboot-ecs-fargate-demo
 ┣ src/main/java/com/codewithvenu/ecs
 ┃ ┣ EcsFargateDemoApplication.java
 ┃ ┗ controller
 ┃   ┗ HelloController.java
 ┣ src/main/resources
 ┃ ┗ application.yml
 ┣ Dockerfile
 ┗ pom.xml

Step 2: Create Main Class

package com.codewithvenu.ecs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class EcsFargateDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(EcsFargateDemoApplication.class, args);
    }
}

Step 3: Create REST Controller

Create file:

src/main/java/com/codewithvenu/ecs/controller/HelloController.java
package com.codewithvenu.ecs.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Map;

@RestController
public class HelloController {

    @Value("${spring.application.name}")
    private String appName;

    @Value("${app.environment:local}")
    private String environment;

    @GetMapping("/")
    public Map<String, Object> home() {
        return Map.of(
                "message", "Spring Boot application is running on AWS ECS Fargate",
                "application", appName,
                "environment", environment,
                "timestamp", LocalDateTime.now().toString()
        );
    }

    @GetMapping("/health")
    public Map<String, String> health() {
        return Map.of("status", "UP");
    }

    @GetMapping("/version")
    public Map<String, String> version() {
        return Map.of("version", "1.0.0");
    }
}

Step 4: Configure application.yml

Create file:

src/main/resources/application.yml
server:
  port: 8080

spring:
  application:
    name: springboot-ecs-fargate-demo

app:
  environment: ${APP_ENVIRONMENT:local}

management:
  endpoints:
    web:
      exposure:
        include: health,info

Step 5: Build Spring Boot JAR

Run:

mvn clean package

Output:

BUILD SUCCESS

Generated JAR:

target/springboot-ecs-fargate-demo-0.0.1-SNAPSHOT.jar

Test locally:

java -jar target/springboot-ecs-fargate-demo-0.0.1-SNAPSHOT.jar

Input:

curl http://localhost:8080/

Output:

{
  "application": "springboot-ecs-fargate-demo",
  "environment": "local",
  "message": "Spring Boot application is running on AWS ECS Fargate",
  "timestamp": "2026-06-25T10:30:00"
}

Step 6: Create Dockerfile

Create file in project root:

Dockerfile
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app

COPY target/springboot-ecs-fargate-demo-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

Step 7: Build Docker Image

Input:

docker build -t springboot-ecs-fargate-demo .

Output:

Successfully built image
Successfully tagged springboot-ecs-fargate-demo:latest

Check image:

docker images

Output:

REPOSITORY                       TAG       IMAGE ID       SIZE
springboot-ecs-fargate-demo      latest    abc123xyz      200MB

Step 8: Run Docker Container Locally

Input:

docker run -p 8080:8080 \
-e APP_ENVIRONMENT=docker-local \
springboot-ecs-fargate-demo

Output:

Tomcat started on port 8080
Started EcsFargateDemoApplication

Test:

curl http://localhost:8080/

Output:

{
  "application": "springboot-ecs-fargate-demo",
  "environment": "docker-local",
  "message": "Spring Boot application is running on AWS ECS Fargate",
  "timestamp": "2026-06-25T10:40:00"
}

Stop container:

docker ps
docker stop <container-id>

Step 9: Configure AWS CLI

Run:

aws configure

Input:

AWS Access Key ID: your-access-key
AWS Secret Access Key: your-secret-key
Default region name: us-east-1
Default output format: json

Validate:

aws sts get-caller-identity

Output:

{
  "UserId": "AIDAEXAMPLE",
  "Account": "123456789012",
  "Arn": "arn:aws:iam::123456789012:user/codewithvenu"
}

Step 10: Create ECR Repository

Amazon ECR is AWS container registry.

Input:

aws ecr create-repository \
  --repository-name springboot-ecs-fargate-demo \
  --region us-east-1

Output:

{
  "repository": {
    "repositoryName": "springboot-ecs-fargate-demo",
    "repositoryUri": "123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-ecs-fargate-demo"
  }
}

Save repository URI:

123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-ecs-fargate-demo

Step 11: Login Docker to ECR

Input:

aws ecr get-login-password --region us-east-1 \
| docker login --username AWS \
--password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com

Output:

Login Succeeded

Step 12: Tag Docker Image

Input:

docker tag springboot-ecs-fargate-demo:latest \
123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-ecs-fargate-demo:latest

Validate:

docker images

Output:

REPOSITORY                                                                  TAG
123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-ecs-fargate-demo     latest

Step 13: Push Image to ECR

Input:

docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-ecs-fargate-demo:latest

Output:

latest: digest: sha256:abc123 size: 1572

Now the Docker image is available in AWS ECR.


ECR Image Push Flow

flowchart LR
    APP[Spring Boot JAR]
    IMG[Docker Image]
    TAG[Tag Image]
    ECR[Amazon ECR]
    ECS[ECS Fargate]

    APP --> IMG
    IMG --> TAG
    TAG --> ECR
    ECR --> ECS

Deployment Option 1: Deploy ECS Fargate Using AWS Console

Step 14: Create ECS Cluster

Go to:

AWS Console
→ ECS
→ Clusters
→ Create Cluster

Input:

Cluster name: codewithvenu-ecs-cluster
Infrastructure: AWS Fargate

Output:

Cluster created successfully

Step 15: Create Task Execution Role

ECS task execution role allows ECS to pull images from ECR and write logs to CloudWatch.

Role name:

ecsTaskExecutionRole

Required managed policy:

AmazonECSTaskExecutionRolePolicy

This role is commonly created automatically by ECS if not already present.


Step 16: Create Task Definition

Go to:

ECS
→ Task Definitions
→ Create new task definition

Input:

Task definition family: springboot-ecs-fargate-task
Launch type: AWS Fargate
Operating system: Linux/X86_64
CPU: 0.25 vCPU
Memory: 0.5 GB
Task role: None for this demo
Task execution role: ecsTaskExecutionRole

Container input:

Container name: springboot-app
Image URI: 123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-ecs-fargate-demo:latest
Container port: 8080
Protocol: TCP

Environment variable:

APP_ENVIRONMENT=ecs-fargate-dev

Logging:

Log driver: awslogs
Log group: /ecs/springboot-ecs-fargate-demo
Region: us-east-1
Stream prefix: ecs

Output:

Task definition created successfully

Step 17: Create Security Group

Create security group for Fargate task.

Inbound rule for learning:

Type Port Source
Custom TCP 8080 0.0.0.0/0

For production, traffic should come through ALB only.


Step 18: Run Task

Go to:

ECS
→ Cluster
→ Tasks
→ Run new task

Input:

Launch type: Fargate
Task definition: springboot-ecs-fargate-task
Cluster: codewithvenu-ecs-cluster
Desired tasks: 1
VPC: default VPC
Subnets: public subnets
Security group: allow 8080
Public IP: Enabled

Output:

Task status: PROVISIONING
Task status: PENDING
Task status: RUNNING

Step 19: Test Running Task

Open ECS task details and copy Public IP.

Input:

curl http://<TASK_PUBLIC_IP>:8080/

Output:

{
  "application": "springboot-ecs-fargate-demo",
  "environment": "ecs-fargate-dev",
  "message": "Spring Boot application is running on AWS ECS Fargate",
  "timestamp": "2026-06-25T11:10:00"
}

Health check:

curl http://<TASK_PUBLIC_IP>:8080/health

Output:

{
  "status": "UP"
}

Deployment Option 2: ECS Service with Application Load Balancer

Running a task manually is okay for testing.

For production, use ECS Service.

ECS Service keeps the desired number of tasks running.


ECS Service Architecture

flowchart TD
    USER[Users]
    ALB[Application Load Balancer]
    SVC[ECS Service]
    T1[Fargate Task 1]
    T2[Fargate Task 2]
    TG[Target Group]
    CW[CloudWatch Logs]

    USER --> ALB
    ALB --> TG
    TG --> SVC
    SVC --> T1
    SVC --> T2
    T1 --> CW
    T2 --> CW

Step 20: Create Application Load Balancer

Go to:

EC2
→ Load Balancers
→ Create Load Balancer
→ Application Load Balancer

Input:

Name: springboot-ecs-alb
Scheme: Internet-facing
IP address type: IPv4
VPC: default VPC
Subnets: select at least two public subnets
Security group: allow HTTP 80

Output:

Application Load Balancer created

Step 21: Create Target Group

Input:

Target type: IP addresses
Protocol: HTTP
Port: 8080
VPC: default VPC
Health check path: /health

Output:

Target group created

Important:

For ECS Fargate, target type should be:

IP addresses

not instance.


Step 22: Create ECS Service

Go to:

ECS
→ Cluster
→ Services
→ Create

Input:

Launch type: Fargate
Task definition: springboot-ecs-fargate-task
Service name: springboot-ecs-service
Desired tasks: 2
Networking: public subnets
Security group: task security group
Load balancer: Application Load Balancer
Target group: springboot target group
Container: springboot-app
Container port: 8080

Output:

ECS service created
Desired count: 2
Running count: 2

Step 23: Test ALB URL

Copy ALB DNS name.

Example:

springboot-ecs-alb-123456789.us-east-1.elb.amazonaws.com

Input:

curl http://springboot-ecs-alb-123456789.us-east-1.elb.amazonaws.com/

Output:

{
  "application": "springboot-ecs-fargate-demo",
  "environment": "ecs-fargate-dev",
  "message": "Spring Boot application is running on AWS ECS Fargate",
  "timestamp": "2026-06-25T11:30:00"
}

Step 24: View CloudWatch Logs

Go to:

CloudWatch
→ Logs
→ Log groups
→ /ecs/springboot-ecs-fargate-demo

Or use CLI:

aws logs describe-log-groups \
  --log-group-name-prefix /ecs/springboot-ecs-fargate-demo

Output:

{
  "logGroups": [
    {
      "logGroupName": "/ecs/springboot-ecs-fargate-demo"
    }
  ]
}

Step 25: Deploy New Version

Update code:

@GetMapping("/version")
public Map<String, String> version() {
    return Map.of("version", "1.0.1");
}

Build JAR:

mvn clean package

Build Docker image:

docker build -t springboot-ecs-fargate-demo .

Tag image:

docker tag springboot-ecs-fargate-demo:latest \
123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-ecs-fargate-demo:latest

Push image:

docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-ecs-fargate-demo:latest

Force ECS service deployment:

aws ecs update-service \
  --cluster codewithvenu-ecs-cluster \
  --service springboot-ecs-service \
  --force-new-deployment

Output:

{
  "service": {
    "serviceName": "springboot-ecs-service",
    "status": "ACTIVE"
  }
}

Test:

curl http://springboot-ecs-alb-123456789.us-east-1.elb.amazonaws.com/version

Output:

{
  "version": "1.0.1"
}

ECS Deployment Flow

flowchart LR
    CHANGE[Code Change]
    BUILD[Build JAR]
    IMAGE[Build Docker Image]
    PUSH[Push to ECR]
    DEPLOY[Force ECS Deployment]
    TEST[Test ALB URL]

    CHANGE --> BUILD
    BUILD --> IMAGE
    IMAGE --> PUSH
    PUSH --> DEPLOY
    DEPLOY --> TEST

Step 26: Environment Variables

You can pass environment variables in Task Definition.

Example:

APP_ENVIRONMENT=prod
SPRING_PROFILES_ACTIVE=prod
DB_HOST=mydb.xxxxxx.us-east-1.rds.amazonaws.com
DB_PORT=5432

Spring Boot config:

spring:
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev}

app:
  environment: ${APP_ENVIRONMENT:local}

For secrets, do not use plain environment variables.

Use:

AWS Secrets Manager
AWS Systems Manager Parameter Store

Step 27: IAM Roles in ECS

ECS commonly uses two roles:

Role Purpose
Task Execution Role Pull ECR image and write CloudWatch logs
Task Role App permissions to access AWS services

Example:

If Spring Boot needs to access S3, attach S3 permission to Task Role.

Do not put AWS access keys inside the Docker image.


Common Errors and Fixes

Error 1: Cannot Pull Container Image

Reason:

Task execution role missing ECR permissions
Image URI is wrong
ECR repository is in different region

Fix:

Use ecsTaskExecutionRole
Check ECR image URI
Check AWS region

Error 2: Task Stops Immediately

Check logs:

CloudWatch Logs
→ /ecs/springboot-ecs-fargate-demo

Common reasons:

Application startup failed
Wrong environment variable
Java exception
Port mismatch

Error 3: ALB Shows Unhealthy Targets

Reasons:

Health check path wrong
Security group does not allow ALB to task
Application not listening on expected port

Fix:

Health check path: /health
Container port: 8080
Task security group should allow traffic from ALB security group

Error 4: Public IP Not Working

If running task directly, ensure:

Public IP is enabled
Task is in public subnet
Security group allows port 8080
Route table has internet gateway

Error 5: Docker Build Fails

Run:

mvn clean package

Then:

docker build -t springboot-ecs-fargate-demo .

Make sure the JAR name in Dockerfile matches the actual JAR name.


ECS Fargate Best Practices

  • Use Application Load Balancer for production
  • Run tasks in private subnets
  • Use NAT Gateway for outbound internet access
  • Use CloudWatch logs
  • Use ECS Service instead of manual tasks
  • Configure health checks
  • Use minimum two tasks for high availability
  • Use IAM Task Role for AWS permissions
  • Store secrets in Secrets Manager
  • Use CI/CD for image build and deployment
  • Use image tags like 1.0.1 instead of only latest
  • Enable auto scaling based on CPU or memory
  • Monitor cost using AWS Budgets

ECS Fargate vs Elastic Beanstalk

Feature Elastic Beanstalk ECS Fargate
Deployment model App platform Container platform
Docker required Optional Required
Infrastructure control Medium Higher
Scaling Built-in Built-in
Microservices Good Very good
Production container usage Medium High
Learning curve Lower Medium

ECS Fargate vs EC2

Feature EC2 ECS Fargate
Server management Manual AWS managed
Docker installation Manual Managed
Scaling Manual/custom Service auto scaling
Deployment SSH/SCP or pipeline Container deployment
Best for Learning/custom VM Cloud-native apps

Cleanup Resources

To avoid AWS charges, delete unused resources.

Delete ECS service:

aws ecs update-service \
  --cluster codewithvenu-ecs-cluster \
  --service springboot-ecs-service \
  --desired-count 0

Delete service from console:

ECS
→ Cluster
→ Service
→ Delete

Delete ALB:

EC2
→ Load Balancers
→ Delete

Delete target group:

EC2
→ Target Groups
→ Delete

Delete ECR repository:

aws ecr delete-repository \
  --repository-name springboot-ecs-fargate-demo \
  --force

Delete ECS cluster:

aws ecs delete-cluster \
  --cluster codewithvenu-ecs-cluster

Interview Questions

What is ECS?

Amazon ECS is a container orchestration service used to run and manage Docker containers on AWS.

What is Fargate?

AWS Fargate is a serverless compute engine for containers. It allows you to run containers without managing EC2 instances.

What is a Task Definition?

A Task Definition is a blueprint that defines container image, CPU, memory, ports, environment variables, logging, and IAM roles.

What is an ECS Service?

An ECS Service maintains the desired number of running tasks and can integrate with a load balancer.

What is ECR?

Amazon ECR is a container registry used to store Docker images.

Why use ALB with ECS?

Application Load Balancer routes external traffic to ECS tasks and performs health checks.

What is the difference between Task Role and Task Execution Role?

Task Execution Role is used by ECS to pull images and write logs. Task Role is used by the application to access AWS services like S3, SQS, or DynamoDB.


Summary

In this article, we deployed a Spring Boot application on AWS ECS Fargate.

We covered:

  • Spring Boot REST API
  • Dockerfile creation
  • Local Docker testing
  • Amazon ECR repository
  • Docker image push
  • ECS Cluster
  • Task Definition
  • Fargate Task
  • ECS Service
  • Application Load Balancer
  • CloudWatch logs
  • Environment variables
  • Common issues
  • Production best practices

ECS Fargate is a strong choice for modern cloud-native Java applications because it supports container-based deployment without managing servers.


Loading likes...

Comments

Share a question, correction, or practical insight about this article.

Loading approved comments...