Spring Boot with AWS EKS
Learn how to deploy a Spring Boot application on AWS EKS step by step using Docker, Amazon ECR, Kubernetes Deployment, Service, kubectl, eksctl, AWS CLI, Load Balancer, and production best practices.
Introduction
In the previous article, we deployed a Spring Boot application on AWS ECS Fargate.
ECS Fargate is a managed container platform from AWS. But many enterprise companies use Kubernetes for container orchestration.
AWS EKS stands for Elastic Kubernetes Service. It allows us to run Kubernetes workloads on AWS without managing the Kubernetes control plane manually.
In this article, we will deploy a Spring Boot application on AWS EKS step by step.
What You Will Learn
- What is AWS EKS?
- What is Kubernetes?
- ECS vs EKS
- How to Dockerize Spring Boot
- How to push Docker image to Amazon ECR
- How to create EKS Cluster using
eksctl - How to deploy Spring Boot using Kubernetes YAML
- How to expose application using LoadBalancer service
- How to check pods, services, and logs
- Input and output examples
- Common errors and fixes
- Production best practices
What is AWS EKS?
AWS EKS is a managed Kubernetes service.
AWS manages the Kubernetes control plane.
You manage:
- Worker nodes
- Pods
- Deployments
- Services
- ConfigMaps
- Secrets
- Ingress
- Application deployments
ECS vs EKS
| Feature | ECS | EKS |
|---|---|---|
| Orchestration | AWS native | Kubernetes |
| Learning curve | Medium | High |
| Portability | AWS-focused | Cloud portable |
| YAML complexity | Lower | Higher |
| Enterprise usage | High | Very high |
| Best for | AWS container apps | Kubernetes-based platforms |
High Level Architecture
flowchart TD
DEV[Developer Machine]
APP[Spring Boot App]
DOCKER[Docker Image]
ECR[Amazon ECR]
EKS[AWS EKS Cluster]
POD[Spring Boot Pod]
SVC[Kubernetes Service]
LB[AWS Load Balancer]
USER[User Browser]
DEV --> APP
APP --> DOCKER
DOCKER --> ECR
ECR --> EKS
EKS --> POD
POD --> SVC
SVC --> LB
USER --> LB
Production Architecture
flowchart TD
U[Users]
R53[Route 53]
ALB[Application Load Balancer]
INGRESS[Kubernetes Ingress]
EKS[EKS Cluster]
subgraph NODEGROUP["Managed Node Group"]
POD1[Spring Boot Pod 1]
POD2[Spring Boot Pod 2]
POD3[Spring Boot Pod 3]
end
ECR[Amazon ECR]
RDS[(Amazon RDS)]
CW[CloudWatch Logs]
U --> R53
R53 --> ALB
ALB --> INGRESS
INGRESS --> EKS
EKS --> POD1
EKS --> POD2
EKS --> POD3
ECR --> POD1
ECR --> POD2
ECR --> POD3
POD1 --> RDS
POD2 --> RDS
POD3 --> RDS
POD1 --> CW
POD2 --> CW
POD3 --> CW
EKS Important Concepts
| Concept | Meaning |
|---|---|
| Cluster | Kubernetes cluster managed by AWS |
| Node Group | EC2 worker nodes running pods |
| Pod | Smallest deployable Kubernetes unit |
| Deployment | Manages pod replicas |
| Service | Exposes pods internally or externally |
| LoadBalancer | Creates AWS Load Balancer |
| Namespace | Logical grouping of resources |
| ConfigMap | Non-sensitive configuration |
| Secret | Sensitive configuration |
| ECR | Docker image registry |
Prerequisites
You need:
AWS Account
AWS CLI
eksctl
kubectl
Docker Desktop
Java 17 or Java 21
Maven
Spring Boot Application
IAM permissions for EKS, EC2, ECR, CloudFormation, IAM
Check Java:
java -version
Output:
openjdk version "17.0.x"
Check Docker:
docker --version
Output:
Docker version 25.x.x
Check AWS CLI:
aws --version
Output:
aws-cli/2.x.x
Check kubectl:
kubectl version --client
Output:
Client Version: v1.x.x
Check eksctl:
eksctl version
Output:
0.x.x
Step 1: Create Spring Boot Application
Create project:
springboot-eks-demo
┣ src/main/java/com/codewithvenu/eks
┃ ┣ EksDemoApplication.java
┃ ┗ controller
┃ ┗ HelloController.java
┣ src/main/resources
┃ ┗ application.yml
┣ k8s
┃ ┣ deployment.yml
┃ ┗ service.yml
┣ Dockerfile
┗ pom.xml
Step 2: Create Main Class
package com.codewithvenu.eks;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EksDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EksDemoApplication.class, args);
}
}
Step 3: Create Controller
package com.codewithvenu.eks.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 EKS",
"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
server:
port: 8080
spring:
application:
name: springboot-eks-demo
app:
environment: ${APP_ENVIRONMENT:local}
management:
endpoints:
web:
exposure:
include: health,info
Step 5: Build JAR
Input:
mvn clean package
Output:
BUILD SUCCESS
Generated JAR:
target/springboot-eks-demo-0.0.1-SNAPSHOT.jar
Run locally:
java -jar target/springboot-eks-demo-0.0.1-SNAPSHOT.jar
Test:
curl http://localhost:8080/
Output:
{
"application": "springboot-eks-demo",
"environment": "local",
"message": "Spring Boot application is running on AWS EKS",
"timestamp": "2026-06-25T10:30:00"
}
Step 6: Create Dockerfile
Create Dockerfile:
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/springboot-eks-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-eks-demo .
Output:
Successfully built image
Successfully tagged springboot-eks-demo:latest
Run locally:
docker run -p 8080:8080 -e APP_ENVIRONMENT=docker-local springboot-eks-demo
Test:
curl http://localhost:8080/
Output:
{
"application": "springboot-eks-demo",
"environment": "docker-local",
"message": "Spring Boot application is running on AWS EKS",
"timestamp": "2026-06-25T10:40:00"
}
Step 8: Configure AWS CLI
Input:
aws configure
Example 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 9: Create Amazon ECR Repository
Input:
aws ecr create-repository \
--repository-name springboot-eks-demo \
--region us-east-1
Output:
{
"repository": {
"repositoryName": "springboot-eks-demo",
"repositoryUri": "123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo"
}
}
Repository URI:
123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo
Step 10: 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 11: Tag Docker Image
Input:
docker tag springboot-eks-demo:latest \
123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo:latest
Validate:
docker images
Output:
REPOSITORY TAG
123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo latest
Step 12: Push Image to ECR
Input:
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo:latest
Output:
latest: digest: sha256:abc123 size: 1572
Image Push Flow
flowchart LR
JAR[Spring Boot JAR]
IMG[Docker Image]
ECR[Amazon ECR]
EKS[AWS EKS]
JAR --> IMG
IMG --> ECR
ECR --> EKS
Step 13: Create EKS Cluster
Use eksctl to create the cluster.
Input:
eksctl create cluster \
--name codewithvenu-eks-cluster \
--region us-east-1 \
--nodegroup-name codewithvenu-workers \
--node-type t3.small \
--nodes 2 \
--nodes-min 1 \
--nodes-max 3 \
--managed
Output:
creating EKS cluster "codewithvenu-eks-cluster"
creating managed nodegroup "codewithvenu-workers"
waiting for cluster to become ready
EKS cluster "codewithvenu-eks-cluster" is ready
This can take several minutes.
Step 14: Verify EKS Cluster
Input:
kubectl get nodes
Output:
NAME STATUS ROLES AGE VERSION
ip-192-168-10-10.ec2.internal Ready <none> 5m v1.x
ip-192-168-20-20.ec2.internal Ready <none> 5m v1.x
Check current context:
kubectl config current-context
Output:
codewithvenu-eks-cluster.us-east-1.eksctl.io
Step 15: Create Namespace
Input:
kubectl create namespace codewithvenu
Output:
namespace/codewithvenu created
Validate:
kubectl get namespaces
Output:
NAME STATUS AGE
codewithvenu Active 10s
Step 16: Create Kubernetes Deployment YAML
Create file:
k8s/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: springboot-eks-demo
namespace: codewithvenu
spec:
replicas: 2
selector:
matchLabels:
app: springboot-eks-demo
template:
metadata:
labels:
app: springboot-eks-demo
spec:
containers:
- name: springboot-eks-demo
image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: APP_ENVIRONMENT
value: "eks-dev"
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 40
periodSeconds: 20
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "1024Mi"
Important:
Replace this image URI:
123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo:latest
with your real ECR image URI.
Step 17: Create Kubernetes Service YAML
Create file:
k8s/service.yml
apiVersion: v1
kind: Service
metadata:
name: springboot-eks-service
namespace: codewithvenu
spec:
type: LoadBalancer
selector:
app: springboot-eks-demo
ports:
- protocol: TCP
port: 80
targetPort: 8080
This will create an AWS Load Balancer automatically.
Step 18: Apply Kubernetes YAML
Input:
kubectl apply -f k8s/deployment.yml
kubectl apply -f k8s/service.yml
Output:
deployment.apps/springboot-eks-demo created
service/springboot-eks-service created
Step 19: Check Pods
Input:
kubectl get pods -n codewithvenu
Output:
NAME READY STATUS RESTARTS AGE
springboot-eks-demo-7f9d8c6d88-a1b2c 1/1 Running 0 60s
springboot-eks-demo-7f9d8c6d88-d4e5f 1/1 Running 0 60s
If pods are pending or crashing:
kubectl describe pod <pod-name> -n codewithvenu
Step 20: Check Service
Input:
kubectl get service -n codewithvenu
Output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT
springboot-eks-service LoadBalancer 10.100.10.10 abc123.us-east-1.elb.amazonaws.com 80
Wait until EXTERNAL-IP is available.
Step 21: Test Application
Input:
curl http://abc123.us-east-1.elb.amazonaws.com/
Output:
{
"application": "springboot-eks-demo",
"environment": "eks-dev",
"message": "Spring Boot application is running on AWS EKS",
"timestamp": "2026-06-25T11:10:00"
}
Health check:
curl http://abc123.us-east-1.elb.amazonaws.com/health
Output:
{
"status": "UP"
}
Version endpoint:
curl http://abc123.us-east-1.elb.amazonaws.com/version
Output:
{
"version": "1.0.0"
}
Step 22: View Pod Logs
Input:
kubectl logs -n codewithvenu deployment/springboot-eks-demo
Output:
Started EksDemoApplication
Tomcat started on port 8080
Stream logs:
kubectl logs -f -n codewithvenu deployment/springboot-eks-demo
Step 23: Scale Application
Scale to 3 replicas:
kubectl scale deployment springboot-eks-demo \
--replicas=3 \
-n codewithvenu
Output:
deployment.apps/springboot-eks-demo scaled
Validate:
kubectl get pods -n codewithvenu
Output:
NAME READY STATUS RESTARTS AGE
springboot-eks-demo-7f9d8c6d88-a1b2c 1/1 Running 0 5m
springboot-eks-demo-7f9d8c6d88-d4e5f 1/1 Running 0 5m
springboot-eks-demo-7f9d8c6d88-g7h8i 1/1 Running 0 10s
Step 24: Deploy New Version
Update controller:
@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-eks-demo .
Tag image with version:
docker tag springboot-eks-demo:latest \
123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo:1.0.1
Push image:
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo:1.0.1
Update deployment image:
kubectl set image deployment/springboot-eks-demo \
springboot-eks-demo=123456789012.dkr.ecr.us-east-1.amazonaws.com/springboot-eks-demo:1.0.1 \
-n codewithvenu
Output:
deployment.apps/springboot-eks-demo image updated
Check rollout:
kubectl rollout status deployment/springboot-eks-demo -n codewithvenu
Output:
deployment "springboot-eks-demo" successfully rolled out
Test:
curl http://abc123.us-east-1.elb.amazonaws.com/version
Output:
{
"version": "1.0.1"
}
Kubernetes Deployment Flow
flowchart LR
CODE[Code Change]
BUILD[Build JAR]
IMAGE[Build Docker Image]
PUSH[Push to ECR]
UPDATE[Update Kubernetes Deployment]
ROLLOUT[Rolling Deployment]
TEST[Test Application]
CODE --> BUILD
BUILD --> IMAGE
IMAGE --> PUSH
PUSH --> UPDATE
UPDATE --> ROLLOUT
ROLLOUT --> TEST
Step 25: Rollback Deployment
If new version has issues:
kubectl rollout undo deployment/springboot-eks-demo -n codewithvenu
Output:
deployment.apps/springboot-eks-demo rolled back
Check history:
kubectl rollout history deployment/springboot-eks-demo -n codewithvenu
Output:
REVISION CHANGE-CAUSE
1 <none>
2 <none>
Step 26: Use ConfigMap
Create file:
k8s/configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: springboot-eks-config
namespace: codewithvenu
data:
APP_ENVIRONMENT: "eks-configmap-dev"
SPRING_PROFILES_ACTIVE: "dev"
Apply:
kubectl apply -f k8s/configmap.yml
Update deployment env section:
envFrom:
- configMapRef:
name: springboot-eks-config
Step 27: Use Kubernetes Secret
Create secret:
kubectl create secret generic springboot-db-secret \
--from-literal=DB_USERNAME=appuser \
--from-literal=DB_PASSWORD=secret123 \
-n codewithvenu
Output:
secret/springboot-db-secret created
Use in deployment:
envFrom:
- secretRef:
name: springboot-db-secret
For production, prefer AWS Secrets Manager with external secrets integration.
Step 28: Cleanup Resources
Delete Kubernetes resources:
kubectl delete -f k8s/service.yml
kubectl delete -f k8s/deployment.yml
kubectl delete namespace codewithvenu
Delete EKS cluster:
eksctl delete cluster \
--name codewithvenu-eks-cluster \
--region us-east-1
Delete ECR repository:
aws ecr delete-repository \
--repository-name springboot-eks-demo \
--force \
--region us-east-1
Important:
Delete the cluster when learning is complete to avoid AWS charges.
Common Errors and Fixes
Error 1: ImagePullBackOff
Reason:
Wrong ECR image URI
Image not pushed
Worker node cannot access ECR
Fix:
kubectl describe pod <pod-name> -n codewithvenu
Check image URI and IAM permissions.
Error 2: Pods Running But URL Not Working
Check service:
kubectl get svc -n codewithvenu
Possible reasons:
Load Balancer still provisioning
Security group issue
Wrong targetPort
Application not listening on 8080
Error 3: CrashLoopBackOff
Check logs:
kubectl logs <pod-name> -n codewithvenu
Possible reasons:
Spring Boot startup error
Missing environment variable
Database connection failure
Memory limit too low
Error 4: kubectl Cannot Connect
Update kubeconfig:
aws eks update-kubeconfig \
--name codewithvenu-eks-cluster \
--region us-east-1
Validate:
kubectl get nodes
Error 5: LoadBalancer External IP Pending
Wait a few minutes.
Check:
kubectl describe svc springboot-eks-service -n codewithvenu
Make sure subnets are properly tagged for load balancer creation.
EKS Best Practices
- Use managed node groups
- Use private subnets for worker nodes
- Use ALB Ingress Controller for production
- Use Horizontal Pod Autoscaler
- Use Cluster Autoscaler or Karpenter
- Use ConfigMaps for non-sensitive config
- Use Secrets Manager for secrets
- Use CloudWatch Container Insights
- Use resource requests and limits
- Use readiness and liveness probes
- Use versioned Docker image tags
- Avoid using
latestin production - Use CI/CD pipeline
- Enable RBAC
- Use namespaces for environment separation
- Use Helm for repeatable deployments
EKS vs ECS Fargate
| Feature | ECS Fargate | EKS |
|---|---|---|
| Container orchestration | ECS | Kubernetes |
| Complexity | Medium | High |
| Portability | AWS-focused | Multi-cloud friendly |
| YAML | Lower | Higher |
| Enterprise Kubernetes | No | Yes |
| Best for | AWS-native containers | Kubernetes platforms |
Interview Questions
What is EKS?
Amazon EKS is a managed Kubernetes service that runs Kubernetes control plane components for you.
What is a Pod?
A Pod is the smallest deployable unit in Kubernetes. It contains one or more containers.
What is a Deployment?
A Deployment manages replicas of pods and supports rolling updates and rollbacks.
What is a Service?
A Service exposes pods using a stable network endpoint.
What is the difference between ClusterIP, NodePort, and LoadBalancer?
ClusterIP exposes service internally. NodePort exposes service on node ports. LoadBalancer creates an external cloud load balancer.
What is ImagePullBackOff?
It means Kubernetes cannot pull the Docker image from the container registry.
Why use readiness and liveness probes?
Readiness checks whether the app is ready to receive traffic. Liveness checks whether the app is still healthy.
Summary
In this article, we deployed a Spring Boot application on AWS EKS.
We covered:
- Spring Boot REST API creation
- Dockerfile creation
- Local Docker testing
- Amazon ECR image push
- EKS cluster creation
- Kubernetes namespace
- Deployment YAML
- Service YAML
- LoadBalancer access
- Logs
- Scaling
- Rollout
- Rollback
- ConfigMap
- Secret
- Cleanup
- Best practices
EKS is powerful for enterprise Kubernetes-based platforms, microservices, and cloud-native deployments.
Comments
Share a question, correction, or practical insight about this article.
Checking login status...
Loading approved comments...