Spring Boot App with Kubernetes Deployment
This project implements JUnit for unit testing (automated tests), swagger for api documentation, docker and kubernetes for deployment.
Kubernetes
Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications. Containers are a good way to bundle and run your applications. In a production environment, you need to manage the containers that run the applications and ensure that there is no downtime. Kubernetes provides you with a framework to run distributed systems resiliently. It takes care of scaling and failover for your application, provides deployment patterns, and more. Kubernetes also provides several features that make deployment easier, including;
- Automated rollouts and rollbacks
- Storage orchestration
- Secret and configuration management
- Service discovery and load balancing
- Self-healing
- Designed for extensibility
Docker
Docker is a software platform that allows you to build, test, and deploy applications quickly. Docker enables an entirely isolated application to be deployed to multiple servers. We need to install Docker Desktop, follow this link to Install Docker Desktop. Why do we need Docker Desktop? Docker Desktop is the easiest way to run Kubernetes on local machine, it gives you a fully certified Kubernetes cluster and manages all the components for you. Kubernetes can be enabled from the Kubernetes settings panel as shown below.
Go to Settings, checking the Enable Kubernetes box and then pressing Apply & Restart triggers the installation of a single-node Kubernetes cluster. To check the kubernetes cluster already installed on your computer, open terminal and run this command:
kubectl cluster-info
kubectl get nodes
Deploy PostgreSQL with Kubernetes
Create postgres-config.yaml (config for PostgreSQL)
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
labels:
app: customer-management-db
data:
POSTGRES_DB: postgres
POSTGRES_USER: postgresqldb
POSTGRES_PASSWORD: postgre123
Apply the configuration
kubectl apply -f postgres-config.yaml
result
configmap/postgres-config created
Confirm the configmap
kubectl get configmap
result
NAME DATA AGE
kube-root-ca.crt 1 5m7s
postgres-config 3 53s
Create postgres-pvc-pv.yaml (for persistent storage volume and persistent volume claim)
kind: PersistentVolume
apiVersion: v1
metadata:
name: postgres-pv-volume # Sets persistent volume's name
labels:
type: local # Sets persistent volume's type to local
app: postgres
spec:
storageClassName: manual
capacity:
storage: 5Gi # Sets persistent volume
accessModes:
- ReadWriteMany
hostPath:
path: "/mnt/data"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgres-pv-claim # Sets name of persistent volume
labels:
app: customer-management-db
spec:
storageClassName: manual
accessModes:
- ReadWriteMany # Sets read and write access
resources:
requests:
storage: 5Gi # Sets volume size
Create and apply persistent storage volume and persistent volume claim
kubectl apply -f postgres-pvc-pv.yaml
result
persistentvolume/postgres-pv-volume created
persistentvolumeclaim/postgres-pv-claim created
Check the pvc is bound
kubectl get pvc
result
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
postgres-pv-claim Bound postgres-pv-volume 5Gi RWX manual 71s
Create postgres-deployment.yaml (for deployment)
apiVersion: apps/v1
kind: Deployment
metadata:
name: customer-management-db # Sets Deployment name
spec:
replicas: 1
selector:
matchLabels:
app: customer-management-db
template:
metadata:
labels:
app: customer-management-db
spec:
containers:
- name: customer-management-db
image: postgres:10.1 # Sets Image
imagePullPolicy: "IfNotPresent"
ports:
- containerPort: 5432 # Exposes container port
envFrom:
- configMapRef:
name: postgres-config
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres
volumes:
- name: postgres
persistentVolumeClaim:
claimName: postgres-pv-claim
Check if your deployments and the children objects, such as pods, are created successfully
kubectl apply -f postgres-deployment.yaml
result
deployment.apps/customer-management-db created
Create postgres-service.yaml (for expose ports in various ways)
apiVersion: v1
kind: Service
metadata:
name: customer-management-db # Sets service name
labels:
app: customer-management-db # Labels and Selectors
spec:
type: NodePort # Sets service type
ports:
- port: 5432 # Sets port to run the postgres application
selector:
app: customer-management-db
Create and apply ports
kubectl apply -f postgres-service.yaml
result
service/customer-management-db created
Connect to database, modify database (create schema, tabel, insert data)
kubectl exec -it [pod-name] -- psql -h localhost -U admin --password -p 5432 postgresdb
Database Configuration of This Project
Create a new role
database name = postgres
username = postgresqldb
password = postgre123
Run the DDL command to create a new table
CREATE TABLE customer(
nik varchar(20) primary key,
full_name varchar(50),
address varchar(150),
phone_number varchar(12),
account_number varchar(12),
balance numeric,
status varchar(10)
);
Deploy Spring Boot App with Kubernetes
Show list of deployment services, cluster ip and external ip
kubectl get services customer-management-db
result
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
customer-management-db NodePort 10.107.130.243 <none> 5432:31104/TCP 93s
Change spring.datasource.url into cluster ip of the database on application.properties
Build .jar file of the project
mvn clean install
Build docker images. We need docker images to deploy with kubernetes cluster.
docker build --tag=customer-management-service:latest .
Create springboot-deploy.yaml (all configuration, images and port to expose)
apiVersion: v1 # Kubernetes API version
kind: Service # Kubernetes resource kind we are creating
metadata: # Metadata of the resource kind we are creating
name: customer-management-service
spec:
selector:
app: customer-management-service
ports:
- protocol: "TCP"
port: 8081 # The port that the service is running on in the cluster
targetPort: 8081 # The port exposed by the service
type: LoadBalancer # type of the service. LoadBalancer indicates that our service will be external.
---
apiVersion: apps/v1
kind: Deployment # Kubernetes resource kind we are creating
metadata:
name: customer-management-service
spec:
selector:
matchLabels:
app: customer-management-service
replicas: 2 # Number of replicas that will be created for this deployment
template:
metadata:
labels:
app: customer-management-service
spec:
containers:
- name: customer-management-service
image: customer-management-service # Image that will be used to containers in the cluster
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8081 # The port that the container is running on in the cluster
Create and apply configuration, deploy the service
kubectl apply -f springboot-deploy.yaml
result
service/customer-management-service created
deployment.apps/customer-management-service created
Show port and pod
kubectl get pod -o wide
result
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
customer-management-db-5bf7fcd76-hgwj7 1/1 Running 0 6m 10.1.0.110 docker-desktop <none> <none>
customer-management-service-57cc8d9d59-hr8l7 0/1 ContainerCreating 0 21s <none> docker-desktop <none> <none>
customer-management-service-57cc8d9d59-xxw7t 0/1 ContainerCreating 0 21s <none> docker-desktop <none> <none>
Show logs
kubectl logs -f [pod-name]
Rollout deployment and restart
kubectl rollout restart deployment [service-name] -n default
Path URL
http://localhost:8081/
API Documentation
http://localhost:8081/swagger-ui.html#/customer-web-controller
References :