API Builder Standalone Multi Container Application Using Kubernetes – Part 2

In this blog post we’ll continue from Part 1. We’ll deploy a two container application to Kubernetes (Minikube). The two containers will be an API Builder app and a MongoDB instance. We will also see how the Kubernetes Horizontal Pod Autoscaler (HPA) works by applying a load to API Builder and seeing how Kubernetes will scale up API Builder by adding more replicas.

Let’s get started.

Deploy MongoDB

We’ll start by deploying a Mongo container to our Kubernetes cluster.

  • Start Minikube

If Minikube is not running, please start it

minikube start

Note: If you haven’t already done so, make sure your prior deployment is removed by following the teardown instructions in Part 1.

  • Create a Mongo deployment

Create a file called mongo.yaml with the following contents:

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: mongo
spec:
  selector:
    matchLabels:
      app: mongo
  replicas: 1
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
      - name: mongo
        image: mongo:latest
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: mongo-persistent-storage
          mountPath: /data/db
      volumes:
      - name: mongo-persistent-storage
        persistentVolumeClaim:
          claimName: mongo-pv-claim
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv-1
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/mongodata"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongo-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

The mongo.yaml file basically describes a simple Mongo deployment with the addition of a volume to persist data in the host (Minikube).

Deploy to Minikube using the following:

kubectl create -f ./mongo.yaml

The response should be:

deployment.apps/mongo created
persistentvolume/local-pv-1 created
persistentvolumeclaim/mongo-pv-claim created
  • Make sure the Mongo pod is running properly
kubectl get pods

The response should be:

NAME READY STATUS RESTARTS AGE
mongo-57c5c96b97-mw8nw 1/1 Running 0 38s

Note: If the status is not Running (i.e. Pending), please wait before proceeding

  • Expose the Mongo service
kubectl expose deployment mongo --type=NodePort
  • In order to populate the Mongo database, get the mongo service IP address and port as follows:
minikube service mongo --url

The response should be:

http://192.168.99.100:32765

Note that your IP address and Port may be different

  • Connect to Mongo with the URL above (e.g. using MongoDB Compass) to populate data using:
  • host: 192.168.99.100

  • port: 32765
  • authentication: none

Note: I created a database called mydata with collection called dog and inserted one document (record)

  • The next series of screen shots shows how to accomplish this:

container application to Kubernetes

container application to Kubernetes

container application to Kubernetes

Deploy API Builder

Now that Mongo is deployed and populated with a database and collection with data, we can deploy an API Builder app. We’ll use the same API Builder app that we used in Part 1. Remember that this API Builder app can connect to any MongoDB using it’s connection URL, passed in as an environment variable.

  • Create an API Builder deployment

Create a file called apib.yaml with the following contents:

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: apibmongo
spec:
  selector:
    matchLabels:
      app: apibmongo
  replicas: 1
  template:
    metadata:
      labels:
        app: apibmongo
    spec:
      containers:
      - name: apibmongo
        image: lbrenman/apibmongodb:1.0.0
        env:
        - name: MONGO_URL
          value: "mongodb://mongo:27017/mydata"
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "100m"

Note that we are specifying that the API Builder Pod should not consume more than 10% (100m) of the CPU. This is used for testing the Horizontal Pod Autoscaler.

Deploy to Minikube using the following:

kubectl create -f ./apib.yaml

The response should be:

deployment.apps/apibmongo created
  • Make sure the API Builder pod is running properly
kubectl get pods

Note: you may need to wait a bit for API Builder to be able to connect properly to the MongoDB instance since the MongoDB takes some time to start up and be ready to receive incoming requests for data

  • Check API Builder logs
kubectl logs apibmongo-758fd66664-6c4bx

Note: replace apibmongo-758fd66664-6c4bx above with the name returned from the get pods command

  • Expose the API Builder service via IP address
kubectl expose deployment apibmongo --type=NodePort
  • Get the API Builder IP address
minikube service apibmongo --url

The response should be:

http://192.168.99.100:32567
  • Make an API Call
curl http://192.168.99.100:30956/api/mongo/dog

You should get the data you populated in MongoDB.

Enable and Test the Kubernetes Horizontal Autoscaler

Now that we have our multi container app running in Kubernetes, let’s take a look at how the Kubernetes Horizontal Pod Autoscaler (HPA) works.

  • Enable the Minikube metrics-server (for measuring CPU utilization):
minikube addons enable metrics-server

The response should be:

metrics-server was successfully enabled
  • Enable the Horizontal Pod Autoscaler to on our API Builder Pod
kubectl autoscale deployment apibmongo --cpu-percent=10 --min=1 --max=3

The response should be:

horizontalpodautoscaler.autoscaling/apibmongo autoscaled
  • Check the Status of the Horizontal Pod Autoscaler
kubectl get hpa

Response should be:

NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
apibmongo Deployment/apibmongo 0%/10% 1 3 1 2m7s

Note: You can see above that there is one pod (replicas) currently running and that the HPA can scale up to 3 if it sees that the CPU goes above 10%.

  • Create a Load on API Builder

In a separate terminal, we’ll simulate a heavy load on API Builder using an infinite HTTP request loop from a worker pod on our cluster to spike the CPU and see how the HPA responds using:

kubectl run -i --tty load-generator --image=busybox --generator=run-pod/v1 /bin/sh

When you get the command prompt (#), enter the following (with the correct API Builder URL and Port from above and your API route):

while true; do wget -q -O- http://192.168.99.100:30378/api/mongo/dog; done

You should see valid API request response in terminal if all is working properly

  • Check the Status of the HPA

Back in the first terminal, check the status of the HPA as follows:

kubectl get hpa

Keep trying the ‘get hpa’ command. Eventually, the response should show that Kubernetes has scaled up the API Builder deployment to 3 pods (replicas) as follows:

NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
apibmongo Deployment/apibmongo 668%/10% 1 3 3 4m31s

Note: this can take several minutes, depending on the power of your laptop.

  • Stop the load on API Builder by terminating the infinite loop we created above (press control-c)
  • Come back to the first terminal and check the HPA to see that replicas returns to 1

kubectl get hpa

Eventually, the response will be as follows:

NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
apibmongo Deployment/apibmongo 0%/10% 1 3 1 19m

Note that this may take a long time

  • Teardown

Use the following commands if you’d like to tear down the application we just deployed:

kubectl delete -f ./
kubectl delete service mongo
kubectl delete service apibmongo
kubectl delete hpa apibmongo
kubectl delete pod load-generator

Note that if you stop minikube, then the host volume (MongoDB database) is deleted

Summary

In this blog post, we used deployment yaml files to stand up a multi container application in Kubernetes using Minikube and the kubectl CLI. We were able to make API requests to API Builder, which retrieved it’s data form a local MongoDB instance (with persistent volume).

Then we enabled the Kubernetes Horizontal Pod Autoscaler and were able to observe how Kubernetes scales up the API Builder pods based on the load of API requests.