Skip to main content

Deploying Spring Boot Applications

Source: Spring Boot in Practice — Chapter 9 by Somnath Musib (Manning). Concepts rewritten for this course; companion samples: spring-boot-in-practice/repo ch09.

From fat JAR and WAR to PaaS, Docker, Kubernetes, and OpenShift — choose a packaging and platform that matches scale, ops skill, and compliance needs.

Pattern-check challenges

Editors do not compile or run Spring Boot, Docker, or kubectl. Check uses sourceChecks only. Snippets above exercises show the usual shape with inline comments; type the code yourself. Paste is disabled on Spring Boot lessons.

What this lesson covers​

  • Executable JAR (spring-boot-maven-plugin, layers / layertools)
  • WAR + SpringBootServletInitializer (e.g. WildFly)
  • Cloud Foundry & Heroku (PaaS overview)
  • Docker images (Dockerfile + Boot build-image)
  • Kubernetes Deployment / Service basics
  • OpenShift “from Git” overview

1. Executable JAR​

Boot’s default path: package a fat JAR and run with embedded Tomcat (or another embedded server).

Requirements:

  1. <packaging>jar</packaging> (or omit — jar is default)
  2. spring-boot-maven-plugin so the repackage goal runs on mvn package
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <!-- repackages fat JAR -->
</plugin>
mvn package
java -jar target/course-tracker-app-jar-1.0.0.jar

Inside the fat JAR:

  • Main-Class → Boot loader (JarLauncher)
  • Start-Class → your @SpringBootApplication
  • App classes under BOOT-INF/classes/, deps under BOOT-INF/lib/
  • layers.idx for Docker-friendly layering: dependencies, spring-boot-loader, snapshot-dependencies, application

Inspect layers:

java -Djarmode=layertools -jar app.jar list
java -Djarmode=layertools -jar app.jar extract --destination layers
<build>
<plugins>
<!-- spring-boot-maven-plugin here -->
</plugins>
</build>
Quiz

JAR basics

1 / 2

What does spring-boot-maven-plugin’s repackage goal mainly do?

Pick an answer to see if you are right.


2. WAR on an application server​

When ops already runs WildFly / Tomcat / JBoss:

  1. <packaging>war</packaging>
  2. Mark embedded Tomcat provided if the server supplies the servlet container
  3. Extend SpringBootServletInitializer and point at your main class
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(CourseTrackerSpringBootApplication.class); // WAR entry
}
}

WildFly extras (book demo): exclude conflicting logback-classic; set context root via jboss-web.xml. Automate with wildfly-maven-plugin (deploy on install, undeploy on clean) and keep credentials out of the POM (e.g. settings.xml).

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return null;
}
}
<packaging>war</packaging>

3. Cloud Foundry (PaaS)​

PaaS manages runtime/OS; you manage app + data. Cloud Foundry can take a JAR (or source) and a buildpack.

Typical flow:

cf login -a <API_ENDPOINT> -u <USER>
mvn clean install
cf push # reads manifest.yml
cf apps # show routes
applications:
- name: course-tracker-app-cf
instances: 1
memory: 1024M
path: target/course-tracker-app-cf-1.0.0.jar # artifact to push
random-route: true
buildpacks:
- java_buildpack

Bind managed services (cf create-service, cf bind-service). VCAP / java-cfenv expose credentials into Spring Environment.

applications:
- name: course-tracker-app-cf
instances: 1
memory: 1024M
# path + buildpacks

4. Heroku​

Heroku builds from Git (or Maven plugin), runs on dynos, and can attach add-ons (e.g. Postgres).

heroku login
git init && git add . && git commit -am "first"
heroku create
heroku addons:create heroku-postgresql
git push heroku master # or main, per app default
heroku open
heroku logs

Spring often reads SPRING_DATASOURCE_URL / username / password injected by the Postgres add-on. Prefer secrets in config vars, not committed files.

Quiz

PaaS quiz

1 / 2

cf push with a Java buildpack typically…

Pick an answer to see if you are right.


5. Docker​

A image packages app + runtime; a container is a running instance. Same image → more consistent Dev/UAT/Prod.

Simple Dockerfile​

FROM adoptopenjdk:11-jre-hotspot
ADD target/*.jar application.jar
ENTRYPOINT ["java", "-jar", "application.jar"]
EXPOSE 8080
docker build --tag course-tracker:v1 .
docker run -p 8080:8080 course-tracker:v1

Layered multi-stage (better cache)​

Extract Boot layers, then COPY each layer separately; entrypoint JarLauncher.

Boot buildpacks (no hand-written Dockerfile)​

mvn spring-boot:build-image -Dspring-boot.build-image.imageName=course-tracker:v3

Uses Cloud Native / Paketo buildpacks — similar idea to CF/Heroku: source/JAR → runnable image.

FROM adoptopenjdk:11-jre-hotspot
# ADD jar, ENTRYPOINT, EXPOSE

6. Kubernetes​

Kubernetes orchestrates containers across a cluster (Pods, Deployments, Services). Local demos often use Kind / Minikube / Docker Desktop.

Typical path:

  1. Build/tag image (course-tracker:v3 → musibs/course-tracker)
  2. Push to a registry (needed for remote nodes)
  3. Create Deployment + Service YAML
  4. kubectl apply -f .
  5. Port-forward for local access if using ClusterIP
kubectl create deployment course-tracker --image musibs/course-tracker --dry-run=client -o=yaml > deployment.yaml
kubectl create service clusterip course-tracker-service --tcp 80:8080 -o yaml --dry-run=client > service.yaml
kubectl apply -f .
kubectl port-forward pod/<pod-name> 8080:8080

Deployment snippet idea: kind: Deployment, container image: musibs/course-tracker, replicas: 1.
Service: map port 80 → container 8080 (ClusterIP).

apiVersion: apps/v1
kind: Deployment
metadata:
name: course-tracker
spec:
replicas: 1
selector:
matchLabels:
app: course-tracker
template:
metadata:
labels:
app: course-tracker
spec:
containers:
- name: course-tracker
image: musibs/course-tracker # image from registry
apiVersion: v1
kind: Service
metadata:
name: course-tracker-service
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
selector:
app: course-tracker

7. RedHat OpenShift​

OpenShift is enterprise Kubernetes with a developer console and extra workflows (From Git, Dockerfile, container image, …).

Sandbox-style flow:

  1. Create/login to OpenShift Developer Sandbox
  2. From Git → paste repo URL
  3. Platform builds, deploys to a Pod, exposes a Route
  4. Use liveness / readiness / startup probes for health

Same container ideas as K8s; OpenShift adds opinionated tooling and multi-tenant ops.


Choosing a strategy​

ApproachWhen it fits
Fat JARSimple VMs, CI artifact, embedded server
WARExisting app-server estate
CF / HerokuPaaS, less infra ownership
DockerPortable runtime unit
Kubernetes / OpenShiftScale, self-heal, multi-service

Always match availability, compliance, and team skill — not hype.


Chapter checklist​

TopicIdea
JARmvn package + java -jar; layers for Docker
WARpackaging war + SpringBootServletInitializer
CFmanifest.yml + cf push + buildpack
HerokuGit push / plugin + dynos + add-ons
DockerDockerfile or spring-boot:build-image
K8sDeployment + Service + registry + port-forward
OpenShiftGit → build → Route

Full samples: ch09 on GitHub.

Next: Spring MVC + Thymeleaf (server-rendered UI) → Lesson 8.

Quiz

Chapter wrap-up

1 / 3

mvn spring-boot:build-image primarily…

Pick an answer to see if you are right.