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.
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:
<packaging>jar</packaging>(or omit — jar is default)spring-boot-maven-pluginso the repackage goal runs onmvn 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 underBOOT-INF/lib/ layers.idxfor 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>
JAR basics
1 / 2What 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:
<packaging>war</packaging>- Mark embedded Tomcat
providedif the server supplies the servlet container - Extend
SpringBootServletInitializerand 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.
PaaS quiz
1 / 2cf 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:
- Build/tag image (
course-tracker:v3→musibs/course-tracker) - Push to a registry (needed for remote nodes)
- Create Deployment + Service YAML
kubectl apply -f .- 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:
- Create/login to OpenShift Developer Sandbox
- From Git → paste repo URL
- Platform builds, deploys to a Pod, exposes a Route
- Use liveness / readiness / startup probes for health
Same container ideas as K8s; OpenShift adds opinionated tooling and multi-tenant ops.
Choosing a strategy
| Approach | When it fits |
|---|---|
| Fat JAR | Simple VMs, CI artifact, embedded server |
| WAR | Existing app-server estate |
| CF / Heroku | PaaS, less infra ownership |
| Docker | Portable runtime unit |
| Kubernetes / OpenShift | Scale, self-heal, multi-service |
Always match availability, compliance, and team skill — not hype.
Chapter checklist
| Topic | Idea |
|---|---|
| JAR | mvn package + java -jar; layers for Docker |
| WAR | packaging war + SpringBootServletInitializer |
| CF | manifest.yml + cf push + buildpack |
| Heroku | Git push / plugin + dynos + add-ons |
| Docker | Dockerfile or spring-boot:build-image |
| K8s | Deployment + Service + registry + port-forward |
| OpenShift | Git → build → Route |
Full samples: ch09 on GitHub.
Next: Spring MVC + Thymeleaf (server-rendered UI) → Lesson 8.
Chapter wrap-up
1 / 3mvn spring-boot:build-image primarily…
Pick an answer to see if you are right.