Cloud-Native

Cloud-Native Deployment on AWS and GCP with Kubernetes

Cloud-Native Deployment on AWS and GCP with Kubernetes — cover illustration

"Cloud-native" doesn't mean running your old app on a cloud VM. It means building services that are containerised, horizontally scalable, self-healing, and deployed by automation. For Java teams, the path runs from a Spring Boot JAR, through a Docker image, to Kubernetes on AWS (EKS) or GCP (GKE). Here's how the pieces fit.

From code to cloud: Spring Boot code becomes a Docker image, pushed to a registry like ECR or GCR, deployed to Kubernetes on EKS or GKE across AWS or GCP
The cloud-native pipeline: code to image to registry to Kubernetes.

1. Containerise properly

A good container image is small, secure, and reproducible. Use a multi-stage build so the final image carries only the runtime, run as a non-root user, and base on a slim or distroless JRE. Bloated images slow every deploy and widen your attack surface.

FROM eclipse-temurin:21-jdk AS build
WORKDIR /app
COPY . .
RUN ./gradlew bootJar

FROM eclipse-temurin:21-jre
RUN useradd -r app
USER app
COPY --from=build /app/build/libs/*.jar app.jar
ENTRYPOINT ["java","-jar","/app/app.jar"]

2. Make Kubernetes able to heal your app

Kubernetes can only keep your service healthy if it knows what "healthy" means. Spring Boot Actuator gives you the endpoints; wire them to liveness and readiness probes:

  • Liveness — is the process alive? If it fails, Kubernetes restarts the pod.
  • Readiness — is it ready for traffic? If it fails, Kubernetes stops routing to it (e.g. while warming caches) without killing it.

Always set resource requests and limits too. Without them, one misbehaving pod can starve a whole node.

readinessProbe:
  httpGet: { path: /actuator/health/readiness, port: 8080 }
livenessProbe:
  httpGet: { path: /actuator/health/liveness, port: 8080 }
resources:
  requests: { cpu: "250m", memory: "512Mi" }
  limits:   { cpu: "1",    memory: "1Gi" }

3. Scale automatically

The whole point of cloud-native is elasticity. The Horizontal Pod Autoscaler adds and removes pods based on CPU, memory, or custom metrics (like Kafka consumer lag), while the cluster autoscaler adds nodes when pods can't be placed. Set sensible min/max replicas so you scale with demand but cap cost.

4. AWS or GCP — what actually differs

The Kubernetes layer is portable; the managed services around it are where you pick. EKS integrates tightly with IAM, ALB, and RDS; GKE is often praised for the smoothest managed experience and Autopilot mode. Both give you managed control planes, so your manifests stay largely the same. Keep cloud-specific concerns (load balancers, secrets, databases) behind clear boundaries so you're not locked in.

5. Deploy with a pipeline, never by hand

Cloud-native and manual deploys don't mix. A CI/CD pipeline should build the image, scan it, push to a registry (ECR/GCR), and roll it out — ideally GitOps-style with Argo CD, where the cluster state is driven from Git. Combined with rolling updates and health probes, you get zero-downtime deploys and instant rollbacks.

Key takeaways

  • Cloud-native means containerised, self-healing, autoscaled, and pipeline-deployed — not lift-and-shift.
  • Wire Actuator to liveness/readiness probes and always set resource requests and limits.
  • Keep manifests portable; let CI/CD (ideally GitOps) own every deploy.

We take Spring Boot platforms to production on AWS and GCP with Kubernetes. Explore our cloud-native services or talk to an architect.

Keep reading

Related articles

Need this built, not just blogged?

We engineer Java, Spring Boot and cloud-native systems for a living. Let's talk.

Talk to an architect