- How to deploy a containerized spring boot application , with PostgreSQL as database on minikube.

- This post will also share details on how to initialize the database with tables and data during the initialization process.
- Will use a spring boot application order service with a REST endpoint to fetch customer details
- GET /customers
- GET /customers
- It uses spring JPA to access PostgreSQL
- Details of the service – https://github.com/rajeshsgr/order-svc-k8
- This article will demonstrate deploying this service on Minikube , More details on minikube can be found at- https://belowthemalt.com/2022/03/17/minikube-kubectl-and-local-development-deployment-of-apps-in-kubernetes/
- Key steps for this deployment process are
- Building a docker image of order-service & upload to docker repository
- Writing Kubernetes deployment file to initialize and run database
- Writing Kubernetes deployment file for order-svc
- Testing the service
Step 1: Building a docker image of order-service & uploading to docker repository
- Build the application to generate jar file
mvn clean install -DskipTests
- If you want to run this application is local , you will have to update the application.properties file with database details
- Create a docker image for the service , refer to Dockerfile https://github.com/rajeshsgr/order-svc-k8/blob/main/Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
EXPOSE 8080
RUN mkdir -p /app/
RUN mkdir -p /app/logs/
ADD target/order-0.0.1-SNAPSHOT.jar /app/app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=container", "-jar", "/app/app.jar"]
- Dockerfile has mainly instructions to add openjdk 8 image, expose port 8080 and add the generated jar file from previous step to the image
- To build an image with the name order-svc-k8 from the Dockerfile , run the below command
docker build -t raje/order-svc-k8 .
- Once the above step is done you can check the image with docker images command

- To push this image to docker repository, give the command
docker push raje/order-svc-k8

- At this stage, we have built our spring boot app, dockerized it and uploaded to the docker repository
Step 2: Writing Kubernetes deployment file to initialize and run database
- For PostgreSQL, we will use the docker image . Link to repo – https://hub.docker.com/_/postgres
- Other 2 important use cases of this demo are
- Mount a path on host , so that the data can be retrieved even if the cluster goes down
- Initialize database with table and scripts
- In order to mount a persistent storage, we will have to deploy a resource type of Persistent Volume and Persistent Volume Claim
- Since we need a persistent storage for PostgreSQL to store data, we will provision the storage using Persistent Volume yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgresql-claim0
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/Users/rajeshp/docker/postgres/docker-pg-vol/data"
- Above yaml is for PersistentVolume object , which has details of host path , storage class , size etc. The name defined for this is – postgresql-claim0
- Persistent volumes have a lifecycle that is independent of any individual pod that uses the storage.
- In order for our application to consume this storage space, we will have to request it using a Persistent Volume Claim request.
- yaml for Persistent Volume Claim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgresql-claim0
labels:
app: postgresql
tier: database
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
- Next we want to build a configuration map object, which will have our database initialization scripts
- Configuration maps are kubernetes objects which are used to store non-confidential data in key-value pairs
apiVersion: v1
kind: ConfigMap
metadata:
name: postgresql-initdb-config
data:
init.sql: |
CREATE TABLE IF NOT EXISTS customers (
customer_id bpchar NOT NULL,
company_name character varying(40) NOT NULL,
contact_name character varying(30),
contact_title character varying(30),
address character varying(60),
city character varying(15),
region character varying(15),
postal_code character varying(10),
country character varying(15),
phone character varying(24),
fax character varying(24)
);
INSERT INTO customers VALUES ('ALFKI', 'Alfreds Futterkiste', 'Maria Anders', 'Sales Representative', 'Obere Str. 57', 'Berlin', NULL, '12209', 'Germany', '030-0074321', '030-0076545');
- Since our order service will need to access this database, we will need a Kubernetes service object
- Service is responsible for enabling network access to a set of pods
apiVersion: v1
kind: Service
metadata:
name: postgresql
labels:
app: postgresql
tier: database
spec:
ports:
- port: 5432
targetPort: 5432
selector:
app: postgresql
tier: database
- Services select Pods based on their labels. When a network request is made to the service, it selects all Pods in the cluster matching the service’s selector, chooses one of them, and forwards the network request to it.
- Next, we need the deployment object.
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgresql
labels:
app: postgresql
tier: database
spec:
selector:
matchLabels:
app: postgresql
strategy:
type: Recreate
template:
metadata:
labels:
app: postgresql
tier: database
spec:
containers:
- name: postgresql
image: postgres:12
imagePullPolicy: "IfNotPresent"
env:
- name: POSTGRES_DB
value: northwind
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_PASSWORD
value: changeme
ports:
- containerPort: 5432
name: postgresql
volumeMounts:
- name: postgresql-claim0
mountPath: /var/lib/postgresql/data
- mountPath: /docker-entrypoint-initdb.d
name: postgresql-initdb
volumes:
- name: postgresql-claim0
persistentVolumeClaim:
claimName: postgresql-claim0
- name: postgresql-initdb
configMap:
name: postgresql-initdb-config
- Key elements of the deployment yaml
- Deploys postgres:12 container
- Have environment variables , which has the database name, user and password
- Mounts the persistent volume , defined using Persistent volume object
- Passes the configmap value for docker to execute
- Bring minikube up by issuing command:
minikube start
- Let us now deploy all the kubernetes resources by giving following commands
kubectl apply -f postgresql-claim0-persistentvolume.yaml
kubectl apply -f postgresql-claim0-persistentvolumeclaim.yaml
kubectl apply -f postgresql-initial-data-configmap.yamlkubectl kubectl apply -f postgresql-deployment.yaml
kubectl apply -f postgresql-service.yaml
- You can check status by
kubectl get all
command

- In case you want to check the logs of database pod, you can check by issuing this command
kubectl logs pod/postgresql-7bf5994f6f-kv5gs
. Please replace the pod name with your pod name
- Let us now verify this deployment , by connecting to database. Commands for the operations are –
kubectl exec -it pod/postgresql-7bf5994f6f-kv5gs bash
- Replace pod name with your pod name in the above command
- Connect to postgres –
psql -U postgres
- Connect to northwind database –
\c northwind
- Check the tables –
\dt
- Check if database is initialized by executing –
select * from customers;
Next steps of deploying the spring boot application is available in the Part 2 .
Thank You !!
2 thoughts on “Setup of spring boot application & initialization of PostgreSQL database on Kubernetes – PART 1”