Spring Boot Multimodule App to Kubernetes
Table of Contents
Previously on the series (I will use same setup)
Create docker image
mvn -am -pl web spring-boot:build-image
Where web
is subproject name. According to 12factor we have to use enviromnemt variables for connections, and we will propbably have at least jdbc connection to database,
so it becomes:
DATASOURCE_URL="jdbc:mysql://localhost:3306/dbname" \
DATASOURCE_USERNAME="username" \
DATASOURCE_PASSWORD="password" \
mvn -am -pl web spring-boot:build-image
(If it’s not multimodule, just skip -am -pl web
)
When build is finished, we should get in the output:
Successfully built image 'docker.io/library/projectName:1.0-SNAPSHOT'
Whis image name can be used to run docker container
Run in docker
docker run --network="host" \
-e DATASOURCE_URL="jdbc:mysql://localhost:3306/dbname" \
-e DATASOURCE_USERNAME="username" \
-e DATASOURCE_PASSWORD="password" \
-p 8080:8080 \
projectName:1.0-SNAPSHOT
Now we have the image, but kubernetes can’t access it yet. Image has to be pushed to some registry
or loaded into minikube directly like this:
Load image to minikube
minikube image load projectName:1.0-SNAPSHOT
Generate .yaml for kubernetes deployment
kubectl create deployment \
--image=projectName:1.0-SNAPSHOT \
--dry-run=client \
-o=yaml projectName > projectName.yaml
echo --- >> projectName.yaml
kubectl create service clusterip projectName \
--tcp=8080:8080 \
--dry-run=client \
-o=yaml >> projectName.yaml
Adjust spec/template/spec/containers
Disable image pull
As for we use local image we do not need kubernetes to pull it from Docker public registry.
imagePullPolicy: Never
Connection to external database on localhost
env:
- name: DATASOURCE_URL
value: "jdbc:mysql://host.minikube.internal:3306/projectName"
- name: DATASOURCE_USERNAME
value: "projectName"
- name: DATASOURCE_PASSWORD
value: "projectName"
Notice host.minikube.internal
this is host name for your host machine, localhost will point to the pod itself (to guest vm).
Result should look like this
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: projectName
name: projectName
spec:
replicas: 1
selector:
matchLabels:
app: projectName
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: projectName
spec:
containers:
- image: projectName:1.0-SNAPSHOT
imagePullPolicy: Never
name: projectName
env:
- name: DATASOURCE_URL
value: "jdbc:mysql://host.minikube.internal:3306/projectName"
- name: DATASOURCE_USERNAME
value: "projectName"
- name: DATASOURCE_PASSWORD
value: "projectName"
resources: { }
status: {}
---
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: projectName
name: projectName
spec:
ports:
- name: 8080-8080
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: projectName
type: ClusterIP
status:
loadBalancer: {}
Apply projectName.yaml
kubectl apply -f projectName.yaml
After that kubectl get pods
should return list of pods with state Running
next to projectName-XXXXXXX-XXX
View logs
kubectl logs POD_NAME
Will shouw you console output, like
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.4)
...
2022-11-20 06:00:24.718 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-20 06:00:24.730 INFO 1 --- [ main] org.Application : Started Application in 4.718 seconds (JVM running for 4.967)
Or some errors if any.
Now pod is running, but it lives iside the cluster, so we need to get access from the outside.
Access service through proxy
kubectl port-forward svc/projectName 8080:8080
Now you should be able to connect to your spring-boot application using http://localhost:8080