advanced~3.5h

Deploying Spring Boot on EKS

Running a containerized Spring Boot application on Kubernetes via EKS — Deployments, Services, Ingress, and the Kubernetes-native health-check model, for teams that need the broader Kubernetes ecosystem.

Want a visual for this topic?

Generate a diagram tailored to Deploying Spring Boot on EKS — the AI picks whichever visual (architecture, flowchart, ER diagram, etc.) best fits this specific AWS concept.

Sign in to generate a visual →
0
Subtopics

🎓 Learning objectives

  • Write a Kubernetes Deployment and Service manifest for a Spring Boot application
  • Map Spring Boot Actuator's health groups to Kubernetes liveness and readiness probes correctly
  • Explain when EKS is the right choice over ECS for a Spring Boot workload
  • Understand how the AWS Load Balancer Controller connects a Kubernetes Ingress to an ALB

What is it?

Deploying Spring Boot on EKS means running the same containerized application as an ECS Fargate deployment would, but orchestrated by actual Kubernetes (Amazon's managed Kubernetes control plane) rather than ECS — defined via standard Kubernetes Deployment, Service, and Ingress manifests instead of ECS task definitions and services. The application code and container image are identical to the ECS Fargate approach; what changes is the orchestration layer and its much larger surrounding ecosystem of tooling.

Why it exists

EKS exists because Kubernetes had already become the de facto standard container orchestrator across the industry (and across other clouds) well before AWS built ECS's simpler alternative — EKS lets teams run that same widely-adopted, portable orchestration standard on AWS's managed infrastructure, for organizations where standardizing on Kubernetes specifically (not just 'containers, orchestrated somehow') is itself the goal, often for portability or ecosystem reasons.

Problem it solves

It solves the same reliable-deployment-and-scaling problem as ECS Fargate, but specifically for teams that need Kubernetes' broader ecosystem, portability across clouds, or existing organizational standardization on Kubernetes as the container orchestration platform of choice.

Intuition

Kubernetes' Deployment/Service/Ingress model expresses the exact same 'desired state that gets continuously reconciled' idea as ECS's task-definition/service model, just using Kubernetes' own more general, portable vocabulary — the underlying reliability guarantee (keep N healthy replicas running, roll out updates gradually, replace unhealthy ones) is conceptually identical between the two, expressed with different nouns.

Analogy

If ECS is AWS's own in-house moving company with a fixed set of services, EKS is hiring a globally-standardized moving company (Kubernetes) that works the same way in any country (any cloud) — more paperwork and setup to get started with, but you get access to an enormous ecosystem of add-on services (Helm charts, service meshes, operators) built around that one standard.

Technical explanation

Spring Boot's management.endpoint.health.probes.enabled=true property (combined with the actuator dependency) automatically exposes /actuator/health/liveness and /actuator/health/readiness as separate health groups — liveness reflects only whether the application's internal state is fundamentally broken (deadlock, unrecoverable state), while readiness additionally reflects the status of contributing health indicators like database/message-broker connectivity, which is exactly the split Kubernetes' two probe types are designed around. The AWS Load Balancer Controller's IP-target mode registers Pod IPs directly as ALB targets (rather than routing through a NodePort and kube-proxy), which both reduces network hops and lets the ALB's own health checks reach the Pod's Actuator endpoint directly, keeping the same health-check-driven routing behavior familiar from the ECS/EC2 deployment models.

Architecture

EKS manages the Kubernetes control plane (API server, etcd, scheduler) as a fully-managed service; worker nodes run either as managed EC2 node groups or as Fargate-backed Pods (EKS on Fargate), with the AWS Load Balancer Controller running as an in-cluster controller that watches Ingress/Service resources and provisions real ALBs/NLBs to match, registering Pod IPs directly as ALB targets (IP-target mode) rather than routing through a node port. Spring Boot Pods run with liveness/readiness probes pointed at Actuator's /actuator/health/liveness and /actuator/health/readiness endpoints, which Kubernetes polls directly to decide whether to restart a Pod (liveness failure) or temporarily stop routing traffic to it (readiness failure) without restarting it.

Workflow

  1. Build and push the same multi-stage-Dockerfile container image used for ECS to ECR (identical image, different orchestrator). 2) Write a Kubernetes Deployment manifest specifying the image, replica count, resource requests/limits, and liveness/readiness probes pointed at Actuator's health-group endpoints. 3) Write a Service manifest to give the Deployment's Pods a stable internal DNS name. 4) Write an Ingress resource (using the AWS Load Balancer Controller's ingress class) to expose the Service externally via an ALB. 5) kubectl apply (or deploy via Helm/ArgoCD) the manifests to the EKS cluster. 6) On a new release, update the Deployment's image tag — Kubernetes performs a rolling update per the Deployment's RollingUpdate strategy.

Example

A platform team already running several other languages' services on EKS with a shared Helm-chart-based deployment pipeline adds a new Spring Boot microservice using the same pipeline — a Deployment manifest referencing the Spring Boot image, a Service exposing it internally, and an Ingress resource that the AWS Load Balancer Controller turns into a real ALB, all deployed via the same helm upgrade command already used for every other service on the cluster.

Real-world usage

Organizations with an existing multi-cloud strategy, a platform engineering team standardized on Kubernetes across many languages/services, or specific ecosystem needs (a service mesh, custom Kubernetes operators) commonly run Spring Boot on EKS alongside every other service on the same cluster, using the same Helm/GitOps deployment pipeline regardless of the underlying application's language.

Trade-offs

EKS trades ECS's AWS-native simplicity for Kubernetes' much larger ecosystem and portability — genuinely valuable when a team needs multi-cloud flexibility, existing Kubernetes tooling investment, or specific ecosystem components (service mesh, custom operators, Helm) that ECS doesn't have equivalents for. For a team with no existing Kubernetes investment and no specific need for that ecosystem, EKS's additional complexity (cluster management, more moving YAML pieces, a genuinely steeper learning curve) is usually not worth it over ECS Fargate for running the same containerized Spring Boot application.

Visual explanation

Picture the same conveyor-belt reliability guarantee as ECS, but running on a much larger, more configurable factory floor (the Kubernetes cluster) that also has plug-in stations (operators, service mesh sidecars, custom schedulers) bolted on around the belt — available if you need them, present as extra machinery to understand even if you don't.

Advantages

  • Full access to the Kubernetes ecosystem — Helm charts, operators, service meshes (Istio, Linkerd), and a vast body of existing tooling and documentation

  • Portable manifests — the same Deployment/Service YAML runs on any Kubernetes cluster, on any cloud or on-premises, unlike ECS task definitions which are AWS-specific

  • Fine-grained scheduling and resource-management primitives (node affinity, taints/tolerations, pod disruption budgets) beyond what ECS exposes

  • A single, consistent deployment model across multi-language, multi-team platforms already standardized on Kubernetes

Disadvantages

  • Meaningfully more operational surface than ECS — cluster upgrades, node group management (or Fargate profile configuration), add-on management (CNI, CoreDNS, the Load Balancer Controller itself) are all EKS-specific responsibilities beyond what ECS requires

  • A genuinely steeper learning curve — Kubernetes' YAML surface area (Deployments, Services, Ingress, ConfigMaps, RBAC) is larger than ECS's task-definition/service model for teams without prior Kubernetes experience

  • EKS control plane has its own hourly cost on top of the worker node/Fargate compute cost, unlike ECS which has no separate control-plane charge

  • Debugging spans more layers (Pod, Service, Ingress, Load Balancer Controller, ALB) when something goes wrong, compared to ECS's flatter task/service/ALB model

Common mistakes

  • Choosing EKS by default without a specific ecosystem/portability need, taking on Kubernetes' operational complexity for no concrete benefit over ECS Fargate

  • Only configuring a liveness probe and no readiness probe (or vice versa), missing the distinct 'restart' versus 'stop routing traffic' behaviors each is meant to control separately

  • Not setting Pod resource requests/limits correctly, leading to the same JVM heap-vs-container-memory mismatch issue that affects ECS, but with Kubernetes' scheduler additionally making poor bin-packing decisions if requests are missing entirely

  • Manually managing an nginx-ingress controller instead of the AWS Load Balancer Controller, missing native ALB integration (WAF attachment, target-group health checks tied to Actuator) that the AWS-specific controller provides

In the AWS Console

  1. 1

    EKS → Clusters → Create

    Create an EKS cluster, choosing a managed node group or Fargate profile for compute.

    A Fargate profile removes node management entirely, closest in spirit to ECS Fargate's operational simplicity.

  2. 2

    (kubectl/Helm, not console) — `helm install aws-load-balancer-controller eks/aws-load-balancer-controller`

    Install the AWS Load Balancer Controller into the cluster (via Helm) so Ingress resources provision real ALBs.

  3. 3

    (kubectl, not console) — `kubectl apply -f deployment.yaml -f service.yaml -f ingress.yaml`

    Apply the Spring Boot Deployment, Service, and Ingress manifests to the cluster.

🎤 Interview questions

Why does a Spring Boot application need to distinguish liveness from readiness when deploying to Kubernetes, and how does Actuator support that? (Listen for: Kubernetes' liveness probe answers 'should this pod be restarted' (is the process fundamentally stuck/deadlocked), while readiness answers 'should this pod currently receive traffic' (e.g., temporarily unable to reach a downstream dependency, but not actually crashed); Spring Boot Actuator's health groups (/actuator/health/liveness, /actuator/health/readiness) map directly onto these two Kubernetes probe types, and enabling management.endpoint.health.probes.enabled=true wires them up automatically)

When would you choose EKS over ECS for a Spring Boot deployment? (Listen for: when the team needs Kubernetes-ecosystem tooling specifically — Helm charts, existing CI/CD built around kubectl, a service mesh like Istio, multi-cloud portability, or existing organizational Kubernetes expertise/standardization; ECS is simpler and sufficient when none of those specific needs apply)

What's the difference between a Kubernetes Deployment and a Service? (Listen for: a Deployment manages a set of identical Pod replicas, handling rolling updates and self-healing (replacing crashed pods); a Service provides a stable network identity/DNS name and load-balances traffic across whichever Pods currently match its label selector, decoupling callers from any individual Pod's changing IP)

How does the AWS Load Balancer Controller connect a Kubernetes Ingress resource to an actual AWS Application Load Balancer? (Listen for: the AWS Load Balancer Controller runs as a controller inside the EKS cluster, watches for Ingress resources, and provisions/configures a real ALB (and target groups pointing at the Pods, using IP-target mode) to match — the Ingress spec becomes AWS's own native load balancer rather than an in-cluster ingress controller like nginx-ingress)

What Kubernetes concept ensures a Spring Boot Deployment doesn't lose all capacity at once during a rolling update? (Listen for: the Deployment's RollingUpdate strategy with maxUnavailable/maxSurge settings, controlling how many old Pods can be down and how many new Pods can be started above the desired count simultaneously during the rollout — conceptually the same guarantee ECS's minimumHealthyPercent/maximumPercent provides, expressed with Kubernetes' own parameters)

💬 Deep Dive with AI

Related concepts

eks-kubernetes-on-awsspring-boot-on-ecs-fargatecontainer-fundamentals-orchestration

Next Step

Continue to Spring Boot with AWS Lambda (Serverless Java)