AWS COMPLETE GUIDE
For Java Spring Boot Developers
Covering: Spring Boot · Kafka · Redis · Docker · Kubernetes · RDS · S3 · ECS · EKS · Lambda ·
API Gateway · CloudWatch & More
Production Ready Best Practices Real-World Examples
Table of Contents
TOC \h \o "1-3"
1. AWS Fundamentals for Java Developers
1.1 AWS Core Concepts
Amazon Web Services (AWS) is the world's most comprehensive cloud platform. As a Java Spring
Boot developer, understanding AWS will allow you to deploy, scale, monitor, and secure your
applications at enterprise scale.
Global Infrastructure
Concept Description Relevance to You
Regions Physical data center clusters Deploy close to users for low
worldwide (e.g., ap-south-1 for latency
Mumbai)
Availability Zones (AZ) Isolated data centers within a region Multi-AZ = high availability for
RDS, ECS
VPC Virtual Private Cloud - your isolated All your services live inside a
network VPC
IAM Identity & Access Management - Control who/what accesses
auth and permissions your AWS services
1.2 AWS CLI & SDK Setup
Install & Configure AWS CLI
# Install AWS CLI v2
curl "[Link] -o [Link]
unzip [Link] && sudo ./aws/install
# Configure credentials
aws configure
AWS Access Key ID: <your-access-key>
AWS Secret Access Key: <your-secret>
Default region name: ap-south-1
Default output format: json
# Verify
aws sts get-caller-identity
Spring Boot AWS SDK ([Link])
<dependencyManagement>
<dependencies>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-cloud-aws-dependencies</artifactId>
<version>3.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Core AWS SDK -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-cloud-aws-starter</artifactId>
</dependency>
<!-- S3 -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-cloud-aws-starter-s3</artifactId>
</dependency>
<!-- SQS -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-cloud-aws-starter-sqs</artifactId>
</dependency>
</dependencies>
2. IAM – Identity & Access Management
2.1 Core IAM Concepts
IAM is the security backbone of AWS. Every API call is authenticated via IAM. Never use root
credentials in code.
IAM Entity Purpose Example
Users Human identities with long-term Developer, CI/CD bot
credentials
Roles Assumed identities for services/apps EC2 role, Lambda execution role
(no static keys)
Policies JSON documents that define S3ReadOnlyAccess, custom
permissions policies
Groups Collection of users sharing policies Developers group, Ops group
2.2 IAM for Spring Boot Applications
Best Practice: Use IAM Roles, Not Access Keys
Security Best Practice
Never hardcode AWS credentials in your Spring Boot application.
When running on EC2/ECS/EKS: attach an IAM Role to the instance/task/pod.
When running locally: use AWS CLI profiles or environment variables.
The AWS SDK automatically picks up credentials from the credential chain.
IAM Policy for Spring Boot App (S3 + SQS + RDS)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Access",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::my-app-bucket/*"
},
{
"Sid": "SQSAccess",
"Effect": "Allow",
"Action": ["sqs:SendMessage", "sqs:ReceiveMessage", "sqs:DeleteMessage"],
"Resource": "arn:aws:sqs:ap-south-1:123456789012:my-queue"
},
{
"Sid": "SecretsManager",
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "arn:aws:secretsmanager:ap-south-1:123456789012:secret:my-app/*"
}
]
}
3. VPC – Network Architecture
3.1 VPC Design for Microservices
A well-designed VPC is critical for security and performance. For Spring Boot microservices, the
recommended pattern separates public and private subnets.
Recommended VPC Architecture
Production VPC Layout
VPC CIDR: [Link]/16
Public Subnets ([Link]/24, [Link]/24) — AZ-a and AZ-b
→ Load Balancers, NAT Gateways, Bastion Host
Private Subnets ([Link]/24, [Link]/24) — AZ-a and AZ-b
→ Spring Boot ECS/EKS Services, Kafka MSK, Redis ElastiCache
Database Subnets ([Link]/24, [Link]/24) — AZ-a and AZ-b
→ RDS PostgreSQL/MySQL (Multi-AZ), no internet access
Security Groups for Spring Boot
# ALB Security Group
Inbound: 443 (HTTPS) from [Link]/0
Outbound: 8080 to App SG
# App Security Group (Spring Boot)
Inbound: 8080 from ALB SG only
Outbound: 5432 (RDS), 9092 (Kafka MSK), 6379 (Redis), 443 (AWS APIs)
# Database Security Group (RDS)
Inbound: 5432 from App SG only
Outbound: None
# Cache Security Group (ElastiCache)
Inbound: 6379 from App SG only
4. Amazon RDS – Managed Relational Database
4.1 RDS for Spring Boot + JPA
Amazon RDS provides managed PostgreSQL/MySQL databases. With Spring Data JPA and
Hibernate, integration is seamless.
4.2 Dependencies ([Link])
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
4.3 Application Configuration
[Link] (with RDS + HikariCP)
spring:
datasource:
url: jdbc:postgresql://${DB_HOST}:5432/${DB_NAME}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
driver-class-name: [Link]
hikari:
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 300000
max-lifetime: 1200000
connection-timeout: 20000
# RDS Proxy recommended for Lambda/ECS
connection-test-query: SELECT 1
jpa:
hibernate:
ddl-auto: validate # Use Flyway for migrations!
show-sql: false
properties:
hibernate:
dialect: [Link]
format_sql: true
jdbc:
batch_size: 50
order_inserts: true
order_updates: true
flyway:
enabled: true
locations: classpath:db/migration
4.4 Using AWS Secrets Manager for DB Credentials
Never store database passwords in [Link] or environment variables in plaintext. Use AWS
Secrets Manager.
// [Link]
@Configuration
public class SecretsConfig {
@Bean
public SecretsManagerClient secretsManagerClient() {
return [Link]()
.region(Region.AP_SOUTH_1)
.build(); // Uses IAM Role automatically
}
@Bean
public DataSourceProperties dataSourceProperties(
SecretsManagerClient client) {
String secretJson = [Link](
[Link]()
.secretId("prod/myapp/db")
.build()
).secretString();
ObjectMapper mapper = new ObjectMapper();
JsonNode secret = [Link](secretJson);
DataSourceProperties props = new DataSourceProperties();
[Link]([Link]("username").asText());
[Link]([Link]("password").asText());
return props;
}
}
4.5 RDS Best Practices
Practice Implementation Benefit
Multi-AZ Enable in RDS settings Automatic failover, 99.95%
SLA
Read Replicas Create 1-2 replicas, route reads via Scale read-heavy workloads
@Transactional(readOnly=true)
RDS Proxy Use with ECS/Lambda to pool Handle connection spikes
connections without exhaustion
Automated Backups Set 7-day retention Point-in-time recovery
Parameter Groups Set max_connections, work_mem per Tune PostgreSQL
instance size performance
Enhanced Monitoring Enable 1-second granularity Spot slow queries, connection
storms
5. Amazon ElastiCache for Redis
5.1 Redis on AWS with Spring Boot
ElastiCache for Redis provides managed Redis clusters. Use it for caching, session storage, rate
limiting, pub/sub, and distributed locks in your Spring Boot microservices.
5.2 Dependencies & Configuration
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>lettuce-core</artifactId>
</dependency>
# [Link]
spring:
data:
redis:
host: ${REDIS_HOST} # ElastiCache cluster endpoint
port: 6379
ssl:
enabled: true # Always enable TLS on ElastiCache
timeout: 2000ms
lettuce:
pool:
max-active: 20
max-idle: 10
min-idle: 5
max-wait: 1000ms
cache:
type: redis
redis:
time-to-live: 3600000 # 1 hour default TTL
cache-null-values: false
5.3 Redis Patterns in Spring Boot
Pattern 1: @Cacheable (Method-Level Caching)
@Service
@CacheConfig(cacheNames = "products")
public class ProductService {
@Cacheable(key = "#id", unless = "#result == null")
public Product findById(Long id) {
return [Link](id).orElseThrow();
}
@CacheEvict(key = "#[Link]")
public Product update(Product product) {
return [Link](product);
}
@CacheEvict(allEntries = true)
public void clearAll() { }
}
Pattern 2: Redis Template (Direct Operations)
@Service
public class RateLimitService {
private final RedisTemplate<String, String> redisTemplate;
public boolean isAllowed(String userId) {
String key = "rate:" + userId;
Long count = [Link]().increment(key);
if (count == 1) {
[Link](key, [Link](1));
}
return count <= 100; // 100 requests per minute
}
// Distributed Lock
public boolean acquireLock(String resource, String token, Duration ttl) {
return [Link](
[Link]()
.setIfAbsent("lock:" + resource, token, ttl)
);
}
}
5.4 ElastiCache Cluster Modes
Mode Use Case Spring Config
Single Node Dev/test, non-critical data [Link]=endpoint
Cluster Mode Disabled HA with failover, most common Use primary endpoint for writes
(Replication Group)
Cluster Mode Enabled Large datasets, sharding across Use Redisson or Lettuce cluster
nodes client
6. Amazon MSK – Managed Apache Kafka
6.1 MSK for Spring Boot Microservices
Amazon MSK (Managed Streaming for Apache Kafka) provides fully managed Kafka. It handles
broker provisioning, patching, and replication — you focus on producing and consuming events.
6.2 Dependencies
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>kafka-avro-serializer</artifactId>
<version>7.5.0</version>
</dependency>
6.3 MSK Configuration
# [Link]
spring:
kafka:
bootstrap-servers: ${MSK_BROKERS} # MSK broker endpoints
properties:
[Link]: SASL_SSL
[Link]: AWS_MSK_IAM
[Link]: [Link] required;
[Link]:
[Link]
producer:
key-serializer: [Link]
value-serializer: [Link]
acks: all # Wait for all replicas
retries: 3
properties:
[Link]: true
[Link]: 1
consumer:
group-id: ${[Link]}
auto-offset-reset: earliest
key-deserializer: [Link]
value-deserializer:
[Link]
properties:
[Link]: "[Link].*"
enable-auto-commit: false # Manual commit for reliability
listener:
ack-mode: MANUAL_IMMEDIATE
concurrency: 3 # Parallel consumers (= partition count ideally)
6.4 Producer & Consumer Implementation
Producer Service
@Service
@Slf4j
public class OrderEventProducer {
private final KafkaTemplate<String, OrderEvent> kafkaTemplate;
public void publishOrderCreated(Order order) {
OrderEvent event = [Link]()
.orderId([Link]())
.status("CREATED")
.timestamp([Link]())
.build();
[Link]("orders", [Link]().toString(), event)
.whenComplete((result, ex) -> {
if (ex != null) {
[Link]("Failed to send order event: {}", [Link]());
} else {
[Link]("Order event sent to partition {}, offset {}",
[Link]().partition(),
[Link]().offset());
}
});
}
}
Consumer with Manual Acknowledgment
@Service
@Slf4j
public class OrderEventConsumer {
@KafkaListener(
topics = "orders",
groupId = "inventory-service",
containerFactory = "kafkaListenerContainerFactory"
)
public void consume(OrderEvent event, Acknowledgment ack) {
try {
[Link]("Processing order: {}", [Link]());
[Link](event);
[Link](); // Commit offset ONLY after success
} catch (Exception e) {
[Link]("Error processing order {}: {}", [Link](),
[Link]());
// Don't acknowledge - message will be redelivered
// Send to DLT after max retries
}
}
}
6.5 MSK Best Practices
• Use IAM authentication (not plaintext SASL) for MSK — automatically works with IAM Roles
• Set [Link]=3 and [Link]=2 for production topics
• Use Dead Letter Topics (DLT) via @DltHandler for poison messages
• Monitor consumer lag via CloudWatch metric: [Link]
• Use MSK Serverless for variable throughput workloads to reduce cost
• Partition count should match your max concurrency (e.g., 12 partitions = 12 consumers)
7. Docker for Spring Boot on AWS
7.1 Optimized Dockerfile for Spring Boot
Use multi-stage builds and layer caching to create small, fast Docker images for your Spring Boot
app.
Production Dockerfile
# Stage 1: Build
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
# Copy Maven wrapper and pom first (cache dependency layer)
COPY mvnw [Link] ./
COPY .mvn .mvn
RUN ./mvnw dependency:go-offline -B
# Copy source and build
COPY src ./src
RUN ./mvnw clean package -DskipTests -B
# Extract layered jar
RUN java -Djarmode=layertools -jar target/*.jar extract
# Stage 2: Runtime
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
# Non-root user for security
RUN addgroup -S spring && adduser -S spring -G spring
USER spring
# Copy layers (ordered by change frequency)
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./
EXPOSE 8080
ENTRYPOINT ["java",
"-XX:+UseContainerSupport",
"-XX:MaxRAMPercentage=75.0",
"-[Link]=file:/dev/./urandom",
"[Link]"]
[Link] for Local Development
version: '3.8'
services:
app:
build: .
ports: ['8080:8080']
environment:
SPRING_PROFILES_ACTIVE: local
DB_HOST: postgres
REDIS_HOST: redis
MSK_BROKERS: kafka:9092
depends_on: [postgres, redis, kafka]
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
volumes: ['pgdata:/var/lib/postgresql/data']
ports: ['5432:5432']
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
ports: ['6379:6379']
kafka:
image: confluentinc/cp-kafka:7.5.0
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_LISTENERS: PLAINTEXT://[Link]:9092,CONTROLLER://[Link]:9093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
CLUSTER_ID: MkU3OEVBNTcwNTJENDM2Qk
ports: ['9092:9092']
volumes:
pgdata:
7.2 Pushing to Amazon ECR
# 1. Create ECR repository
aws ecr create-repository \
--repository-name my-spring-app \
--image-scanning-configuration scanOnPush=true \
--region ap-south-1
# 2. Authenticate Docker to ECR
aws ecr get-login-password --region ap-south-1 | \
docker login --username AWS \
--password-stdin [Link]
# 3. Build, tag, push
docker build -t my-spring-app .
docker tag my-spring-app:latest \
[Link]/my-spring-app:latest
docker push [Link]/my-spring-app:latest
8. Amazon ECS – Elastic Container Service
8.1 ECS with Fargate for Spring Boot
ECS Fargate is the simplest way to run Spring Boot containers on AWS without managing EC2
instances. It is serverless, auto-scaling, and deeply integrated with ALB, IAM, and CloudWatch.
8.2 ECS Task Definition
{
"family": "my-spring-app",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "1024",
"memory": "2048",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/my-app-task-role",
"containerDefinitions": [{
"name": "my-spring-app",
"image": "[Link]/my-spring-app:latest",
"portMappings": [{"containerPort": 8080}],
"environment": [
{"name": "SPRING_PROFILES_ACTIVE", "value": "prod"},
{"name": "DB_HOST", "value": "[Link]"}
],
"secrets": [
{"name": "DB_PASSWORD", "valueFrom":
"arn:aws:secretsmanager:...:secret:prod/myapp/db:password::"}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-spring-app",
"awslogs-region": "ap-south-1",
"awslogs-stream-prefix": "ecs"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f [Link] ||
exit 1"],
"interval": 30, "timeout": 5, "retries": 3
}
}]
}
8.3 Auto Scaling for ECS
# Register scalable target
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/my-cluster/my-spring-app \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 --max-capacity 20
# Scale on CPU (keep CPU at 70%)
aws application-autoscaling put-scaling-policy \
--policy-name cpu-tracking \
--service-namespace ecs \
--resource-id service/my-cluster/my-spring-app \
--scalable-dimension ecs:service:DesiredCount \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
}
}'
9. Amazon EKS – Kubernetes for Spring Boot
9.1 EKS Overview
Amazon EKS (Elastic Kubernetes Service) is the best choice when you need full Kubernetes
capabilities: advanced scheduling, custom controllers, Helm charts, service meshes, and complex
multi-service deployments.
9.2 Kubernetes Manifests for Spring Boot
Deployment YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-spring-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: my-spring-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # Zero-downtime deploys
template:
metadata:
labels:
app: my-spring-app
spec:
serviceAccountName: my-spring-app-sa # For IRSA
containers:
- name: app
image: [Link]/my-spring-app:v1.2.3
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db-password
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: '2'
memory: 2Gi
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
Service & HorizontalPodAutoscaler
---
apiVersion: v1
kind: Service
metadata:
name: my-spring-app
spec:
selector:
app: my-spring-app
ports:
- port: 80
targetPort: 8080
type: ClusterIP
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-spring-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-spring-app
minReplicas: 3
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
9.3 IRSA – IAM Roles for Service Accounts
IRSA lets your Kubernetes pods assume IAM Roles without static credentials. This is the
recommended way to give Spring Boot pods access to S3, SQS, Secrets Manager, etc.
# 1. Enable OIDC provider for your EKS cluster
eksctl utils associate-iam-oidc-provider \
--cluster my-cluster --approve
# 2. Create IAM Role with trust policy for service account
eksctl create iamserviceaccount \
--name my-spring-app-sa \
--namespace production \
--cluster my-cluster \
--attach-policy-arn arn:aws:iam::123456789012:policy/my-app-policy \
--approve \
--override-existing-serviceaccounts
# 3. Spring Boot automatically uses the role - no code changes needed!
# The AWS SDK reads credentials from the pod's projected service account token.
10. Amazon S3 – Object Storage
10.1 S3 with Spring Boot
S3 is used for storing files, assets, exports, logs, and static content. With Spring Cloud AWS, S3
integration is straightforward.
10.2 S3 Service Implementation
@Service
@Slf4j
public class S3StorageService {
private final S3Client s3Client;
@Value("${[Link]}") private String bucket;
// Upload file
public String uploadFile(MultipartFile file, String key) {
PutObjectRequest request = [Link]()
.bucket(bucket)
.key(key)
.contentType([Link]())
.serverSideEncryption(ServerSideEncryption.AES256)
.build();
[Link](request,
[Link]([Link]()));
return "[Link] + bucket + ".[Link]/" + key;
}
// Generate pre-signed URL (for direct client access)
public String generatePresignedUrl(String key, Duration duration) {
try (S3Presigner presigner = [Link]()) {
GetObjectPresignRequest presignRequest =
[Link]()
.signatureDuration(duration)
.getObjectRequest(r -> [Link](bucket).key(key))
.build();
return [Link](presignRequest).url().toString();
}
}
// Download as stream
public InputStream downloadFile(String key) {
GetObjectRequest request = [Link]()
.bucket(bucket).key(key).build();
return [Link](request);
}
}
10.3 S3 Best Practices
Practice Configuration
Block all public access S3 Block Public Access settings — ON for all buckets
Versioning Enable versioning for important buckets (documents, backups)
Encryption Use SSE-S3 or SSE-KMS for all objects at rest
Lifecycle Policies Move old objects to S3-IA after 30 days, Glacier after 90
Cross-region replication Replicate critical data to another region for DR
Access Logs Enable S3 server access logs for audit trails
11. API Gateway & Lambda
11.1 Serverless Spring Boot with Lambda
For event-driven or sporadic workloads, you can run Spring Boot handlers as AWS Lambda
functions using the AWS Serverless Java Container or Spring Cloud Function.
11.2 Spring Cloud Function on Lambda
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-cloud-function-adapter-aws</artifactId>
</dependency>
@SpringBootApplication
public class LambdaApplication {
// Spring Cloud Function auto-wires functions as Lambda handlers
@Bean
public Function<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent>
handleRequest() {
return request -> {
String body = [Link]();
// Process request...
return [Link]()
.statusCode(200)
.body("{\"message\": \"processed\"}")
.headers([Link]("Content-Type", "application/json"))
.build();
};
}
@Bean
public Consumer<SQSEvent> processSqsEvent() {
return event -> [Link]().forEach(record -> {
[Link]("Processing: {}", [Link]());
// handle SQS message
});
}
}
11.3 API Gateway Configuration
Feature Use Case Notes
HTTP API (v2) Low-latency REST APIs, Spring Boot 70% cheaper than REST API
REST API (v1) Full features: caching, usage plans, Use for public APIs needing rate
WAF limiting
WebSocket API Real-time bidirectional (chat, Good for Spring WebFlux apps
notifications)
Custom Authorizers JWT validation via Lambda Integrates with Spring Security
claims
12. Application Load Balancer
12.1 ALB for Spring Boot Microservices
ALB distributes traffic across your ECS/EKS containers. It handles SSL termination, health checks,
and path/header-based routing between microservices.
Spring Boot Actuator Health for ALB
# [Link] - Configure health endpoints for ALB
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: when_authorized
probes:
enabled: true # Enables /actuator/health/liveness and /readiness
health:
livenessState:
enabled: true
readinessState:
enabled: true
db:
enabled: true
redis:
enabled: true
kafka:
enabled: true
ALB Routing Rules (Terraform)
# Route /api/orders/* to order-service
resource "aws_lb_listener_rule" "orders" {
listener_arn = aws_lb_listener.[Link]
priority = 100
action {
type = "forward"
target_group_arn = aws_lb_target_group.order_service.arn
}
condition {
path_pattern { values = ["/api/orders/*"] }
}
}
# Route /api/products/* to product-service
resource "aws_lb_listener_rule" "products" {
listener_arn = aws_lb_listener.[Link]
priority = 200
action { type = "forward"
target_group_arn = aws_lb_target_group.product_service.arn }
condition {
path_pattern { values = ["/api/products/*"] }
}
}
13. CloudWatch – Monitoring & Observability
13.1 Spring Boot Metrics to CloudWatch
Use Micrometer with the CloudWatch registry to push Spring Boot metrics (JVM, HTTP, database,
Kafka) to CloudWatch for dashboards and alarms.
<dependency>
<groupId>[Link]</groupId>
<artifactId>micrometer-registry-cloudwatch2</artifactId>
</dependency>
# [Link]
management:
metrics:
export:
cloudwatch:
enabled: true
namespace: MyApp/Production
step: 60s # Push metrics every 60 seconds
tags:
application: my-spring-app
environment: production
region: ap-south-1
13.2 Structured Logging to CloudWatch
<dependency>
<groupId>[Link]</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
<!-- [Link] -->
<configuration>
<springProfile name="prod">
<appender name="CONSOLE" class="[Link]">
<encoder class="[Link]">
<customFields>{"app":"my-spring-app","env":"prod"}</customFields>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
</configuration>
13.3 Key CloudWatch Alarms for Spring Boot
Metric Alarm Threshold Action
HTTP 5xx errors > 1% of requests SNS notification to team
API response time (p99) > 2000ms SNS + scale out
JVM heap usage > 85% Alert + investigate memory leak
DB connection pool > 80% used Alert + check slow queries
Kafka consumer lag > 10000 Alert + scale consumers
Redis evictions > 0 per minute Alert + increase memory
ECS task restarts > 3 in 5 minutes Immediate alert
14. CI/CD Pipeline for Spring Boot on AWS
14.1 GitHub Actions CI/CD Pipeline
A complete CI/CD pipeline: build, test, Docker image, push to ECR, and deploy to ECS/EKS.
name: Deploy Spring Boot to AWS
on:
push:
branches: [main]
env:
AWS_REGION: ap-south-1
ECR_REPOSITORY: my-spring-app
ECS_SERVICE: my-spring-app-service
ECS_CLUSTER: my-cluster
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { java-version: '21', distribution: 'temurin' }
- uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ [Link] }}-maven-${{ hashFiles('**/[Link]') }}
- run: ./mvnw verify
build-and-deploy:
needs: test
runs-on: ubuntu-latest
permissions:
id-token: write # For OIDC auth with AWS
contents: read
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: ${{ env.AWS_REGION }}
- name: Login to ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build and push Docker image
env:
IMAGE_TAG: ${{ [Link] }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
- name: Deploy to ECS
run: |
aws ecs update-service \
--cluster $ECS_CLUSTER \
--service $ECS_SERVICE \
--force-new-deployment
15. Security Best Practices
15.1 Secrets Management
Never Do This
DB_PASSWORD=mypassword (in [Link])
AWS_SECRET_KEY=xyz... (hardcoded in code)
Storing secrets in environment variables as plaintext in ECS task definitions
Always Do This
Use AWS Secrets Manager for all credentials (DB, API keys, OAuth secrets)
Use AWS Parameter Store for non-secret configuration values
Reference secrets in ECS task definitions using 'secrets' (valueFrom ARN), not 'environment'
Rotate secrets automatically with Secrets Manager rotation
Enable CloudTrail to audit all AWS API calls
15.2 Spring Security with AWS Cognito
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
# [Link] - Configure Cognito as JWT issuer
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: [Link]
jwk-set-uri:
[Link]
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> [Link](cognitoConverter()))
);
return [Link]();
}
}
15.3 Network Security Checklist
• All services run in private subnets — only ALB is in public subnet
• Security groups use least-privilege: only necessary ports between specific SGs
• Enable VPC Flow Logs for network audit trail
• Use AWS WAF with ALB to protect against OWASP Top 10
• Enable GuardDuty for threat detection across your AWS account
• Use ACM (AWS Certificate Manager) for free auto-renewing SSL/TLS certificates
• Enable S3 Block Public Access at account level
• Enable CloudTrail for all regions — essential for security audit
16. Cost Optimization
16.1 Key Cost Strategies for Java Apps on AWS
Strategy Description Estimated Savings
Savings Plans Commit to 1-3 year usage for Up to 66%
Fargate/EC2
Spot Instances Use for non-critical batch/worker Up to 90%
containers
Right-sizing Match ECS/EKS resource requests to 20-40%
actual usage (check CloudWatch)
S3 Intelligent-Tiering Auto-move infrequent data to cheaper 30-50%
storage class
RDS Reserved Instances Reserve RDS instances 1-3 years Up to 69%
ElastiCache Reserved Reserve Redis nodes Up to 55%
Nodes
MSK Serverless For variable Kafka workloads vs Variable
provisioned brokers
Lambda for off-hours Replace always-on EC2 with Lambda for 90%+ for batch
jobs batch jobs
16.2 Cost Monitoring Setup
# Enable Cost Explorer API
aws ce create-cost-category-definition \
--name "Environment" \
--rules '[{"Value":"Production","Rule":{"Tags":{"Key":"Env","Values":
["prod"]}}}]'
# Set budget alert at $500/month
aws budgets create-budget \
--account-id 123456789012 \
--budget '{
"BudgetName": "monthly-app-budget",
"BudgetLimit": {"Amount": "500", "Unit": "USD"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST"
}' \
--notifications-with-subscribers '[{
"Notification": {"NotificationType": "ACTUAL","ComparisonOperator":
"GREATER_THAN","Threshold": 80},
"Subscribers": [{"SubscriptionType": "EMAIL","Address": "team@[Link]"}]
}]'
17. Multi-Environment Strategy
17.1 Environment Configuration Pattern
Use Spring profiles combined with AWS Parameter Store/Secrets Manager to manage
configurations across Dev, Staging, and Production.
# Parameter Store naming convention
/myapp/dev/database/url
/myapp/dev/redis/host
/myapp/staging/database/url
/myapp/prod/database/url
/myapp/prod/kafka/brokers
# [Link] - Load from Parameter Store
aws:
paramstore:
enabled: true
prefix: /myapp
profile-separator: _
fail-fast: true
spring:
config:
import: "aws-parameterstore:"
17.2 Spring Profiles for AWS Environments
# [Link]
spring:
jpa:
show-sql: false
datasource:
hikari:
maximum-pool-size: 20
logging:
level:
[Link]: INFO
[Link]: WARN
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
18. Quick Reference Cheat Sheet
AWS CLI Quick Commands
# ECS
aws ecs list-services --cluster my-cluster
aws ecs describe-services --cluster my-cluster --services my-spring-app
aws ecs update-service --cluster my-cluster --service my-spring-app --force-new-
deployment
# EKS
aws eks update-kubeconfig --region ap-south-1 --name my-cluster
kubectl get pods -n production
kubectl rollout restart deployment/my-spring-app -n production
kubectl logs -f deploy/my-spring-app -n production
# CloudWatch Logs
aws logs tail /ecs/my-spring-app --follow
aws logs filter-log-events --log-group-name /ecs/my-spring-app \
--filter-pattern '"ERROR"' --start-time $(date -d '1 hour ago' +%s000)
# ECR
aws ecr list-images --repository-name my-spring-app
aws ecr describe-images --repository-name my-spring-app \
--query 'sort_by(imageDetails,&imagePushedAt)[-1]'
# Secrets Manager
aws secretsmanager get-secret-value --secret-id prod/myapp/db --query SecretString
aws secretsmanager create-secret --name prod/myapp/apikey --secret-string 'abc123'
# RDS
aws rds describe-db-instances --db-instance-identifier my-postgres
aws rds create-db-snapshot --db-instance-identifier my-postgres --db-snapshot-
identifier snap-$(date +%Y%m%d)
Service Mapping for Your Stack
Your Technology AWS Service Purpose
Spring Boot App ECS Fargate / EKS Container orchestration
PostgreSQL/MySQL Amazon RDS (Multi-AZ) Managed relational database
Your Technology AWS Service Purpose
Redis Amazon ElastiCache for Redis Managed caching & sessions
Apache Kafka Amazon MSK Managed Kafka streaming
Docker Registry Amazon ECR Private container registry
Kubernetes Amazon EKS Managed Kubernetes
Load Balancer Application Load Balancer Traffic distribution & SSL
File Storage Amazon S3 Object storage
Secrets/Config Secrets Manager + Parameter Secure config management
Store
Monitoring CloudWatch + X-Ray Logs, metrics, tracing
DNS Route 53 Domain & health-check routing
CDN CloudFront Global content delivery
CI/CD GitHub Actions + ECR + ECS Automated deployments
Network VPC + Security Groups Network isolation
Auth Amazon Cognito + API User auth & API security
Gateway
End of Guide