Deployment of multiple apps on Kubernetes cluster — Walkthrough

Photo by Joseph Barrientos on Unsplash

Architecture

  • database,
  • backend service (kanban-app, written in Java with Spring Boot)
  • and frontend (kanban-ui, written with Angular framework).
  • kanban.k8s.com
  • adminer.k8s.com

Install Docker, kubectl & minikube

  • Docker (container deamon),
  • kubectl (a CLI tool to interact with cluster),
  • minikube (locally installed, lightweight Kubernetes cluster).

Start minikube

$ minikube start
😄 minikube v1.25.2 on Ubuntu 20.04 (amd64)
✨ Automatically selected the docker driver
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
🔥 Creating docker container (CPUs=2, Memory=2200MB) ...
🐳 Preparing Kubernetes v1.23.3 on Docker 20.10.12 ...
▪ kubelet.housekeeping-interval=5m
▪ Generating certificates and keys ...
▪ Booting up control plane ...
▪ Configuring RBAC rules ...
🔎 Verifying Kubernetes components...
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟 Enabled addons: default-storageclass, storage-provisioner
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by defaul
$ minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
$ kubectl cluster-info
Kubernetes master is running at https://127.0.0.1:32768
KubeDNS is running at https://127.0.0.1:32768/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

Modify hosts file

127.0.0.1   adminer.k8s.com
127.0.0.1 kanban.k8s.com

Add Adminer

  • replicas — indicates how many Pods of the same type will be created,
  • selector.matchLabels —defines how Deployment will find Pods that it needs to take care of, in this case it will look for a Pod which is labeled with app: adminer ,
  • template.metadata — tells what metadata will be added to each Pod, in this case all of them will have labels : app: adminer , group: db .
  • template.spec.containers — is a list of containers that will be inside a Pod. In this case I put only one container, which is based on adminer:4.7.6-standalone Docker image and exposes containerPort: 8080 . Moreover with env section we inject environment variable to the container to configure Adminer UI (full documentation can be found here). And finally we decide how much RAM and CPU an will require.
$ kubectl apply -f adminer-deployment.yaml
deployment.apps/adminer created
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
adminer 1/1 1 1 30s
$ kubectl describe deployment adminer
... many details about the Deployment ...
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
adminer-994865d4b-kqck5 1/1 Running 0 24m
$ kubectl describe pod adminer-994865d4b-kqck5
... many details about the Pod ...
  • type: ClusterIP —indicates what type of the Service we want to deploy. There are several types, but I’ve decided to use ClusterIP. And the main reason for that is because I didn’t want to expose every Pod outside the cluster. What ClusterIP does is that it exposes assigned Pods to other Pods inside the cluster, but not outside.
  • selector — here we say to which Pods this Service provide access, in this case it provide access to a Pod with app: adminer label.
  • ports — indicates the mappings of the port exposed by the Pod to the ClusterIP port which will be available for other applications inside cluster.
$ kubectl apply -f adminer-svc.yaml
service/adminer created
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
adminer ClusterIP 10.99.85.149 <none> 8080/TCP 9s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3m34s
$ kubectl describe svc adminer
... many details about the ClusterIP...

Add Ingress Controller

$ minikube addons enable ingress
🌟 The 'ingress' addon is enabled
$ minikube tunnel
✅ Tunnel successfully started
📌 NOTE: Please do not close this terminal as this process must stay alive for the tunnel to be accessible …
$ kubectl apply -f ingress-controller.yaml
ingress.networking.k8s.io/ingress-controller created

Add PostgreSQL database

$ kubectl apply -f postgres-pvc.yaml
persistentvolumeclaim/postgres-persistent-volume-claim created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODE STORAGECLASS AGE
postgres.. Bound pvc-43. 4Gi RWO standard 40s
$ kubectl describe pvc postgres-persistent-volume-claim
... many details about the PersistentVolumeClaim...
$ kubectl apply -f postgres-config.yaml
configmap/postgres-config created
$ kubectl get configmap
NAME DATA AGE
postgres-config 3 2m31s
$ kubectl describe configmap postgres-config
... many details about the ConfigMap...
  • spec.template.spec.volumes — here we’re adding created PVC to the Deployment, so all containers inside of it will be able to use it,
  • spec.template.spec.containers[0].image — here we specify what Docker image we want to use for our database,
  • spec.template.spec.containers[0].envFrom — indicates from which ConfigMap we want to inject environment variables,
  • spec.template.spec.containers[0].volumeMounts — tells Kubernetes which Volume to use (defined in the spec.template.spec.volumes section) and map it to a particular folder inside the container — basically all data inside the mountPath will be stored outside the cluster.
$ kubectl apply -f postgres-deployment.yaml 
deployment.apps/postgres created
$ kubectl apply -f postgres-svc.yaml
service/postgres created
System:   PostgreSQL
Server: postgres
Username: kanban
Password: kanban
Database: kanban

Add kanban-app

$ kubectl apply -f kanban-app-deployment.yaml
deployment.apps/kanban-app created
$ kubectl apply -f kanban-app-svc.yaml
service/kanban-app created
$ kubectl apply -f ingress-controller.yaml
ingress.networking.k8s.io/ingress-service configured

Add kanban-ui

$ kubectl apply -f kanban-ui-deployment.yaml 
deployment.apps/kanban-ui created
$ kubectl apply -f kanban-ui-svc.yaml
service/kanban-ui created

Conclusion

$ kubectl apply -f ./k8s
deployment.apps/adminer created
service/adminer created
ingress.networking.k8s.io/ingress-service created
deployment.apps/kanban-app created
service/kanban-app created
deployment.apps/kanban-ui created
service/kanban-ui created
configmap/postgres-config created
deployment.apps/postgres created
persistentvolumeclaim/postgres-persistent-volume-claim created
service/postgres created

--

--

--

Java Software Developer, DevOps newbie, constant learner, podcast enthusiast.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Wojciech Krzywiec

Wojciech Krzywiec

Java Software Developer, DevOps newbie, constant learner, podcast enthusiast.

More from Medium

Container-aware Java Heap Configuration

Deploying a Spring Boot application in Kubernetes using Helm charts

Java-SpringBoot Application with Keycloak and Kubernetes Deployment

Terraform: Deploy spring boot application with MySql DB on Kubernetes