Microservice

Spring Boot Multimodule App to Kubernetes

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