Autoscaling a Kubernetes cluster using Horizontal Pod AutoScaler (HPA)

In the blog I shall be describing the step by step process to setup a Kubernetes cluster using minikube to run a node js based application in Azure cloud and autoscaling the application using Horizontal Pod AutoScaler.

  • Spin up a Standard D4s v3 (4 vcpus, 16 GiB memory) Virtual machine in Azure based on Linux (ubuntu 18.04)
  • Putty into the server and sudo su -. Execute all following commands as root.
sudo apt-get update
sudo apt-get install -y apt-transport-https
sudo apt-get install -y virtualbox virtualbox-ext-pack
  • Install kubectl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add –

sudo touch /etc/apt/sources.list.d/kubernetes.list

echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update

sudo apt-get install -y kubectl
  • Install minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-latest.x86_64.rpm

sudo rpm -ivh minikube-latest.x86_64.rpm


chmod +x minikube && sudo mv minikube /usr/local/bin/

minikube start
  • Run the following commands to ensure proper installation.
kubectl api-versions
       
kubectl get services
  • Create a new node js application
apt-get install npm

npm init  // this create a new package.json file in the directory
  • Create an index.js file with the following code.
const http = require(‘http’);
const port = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
         res.statusCode = 200;
         res.setHeader(‘Content-Type’, ‘text/plain’);
        res.end(‘Hello World\n’);
});server.listen(port, () => {
 console.log(‘Server running on port: ${port}’);
});
  • Create a Dockerfile in the same directory with the following content
FROM node:alpine

RUN mkdir -p /usr/src/app

WORKDIR /usr/src/app

ADD index.js ./

ADD package.json ./

RUN npm install

CMD ["npm", "start"]

Sudo apt-get install docker.io
docker login

docker build -t rtdhaccount/node-application .

docker push rtdhaccount/node-application
  • Deploy to kubernetes
    • Create a folder called k8s
    • Create deployment.yml inside k8s with the following content
apiVersion: extensions/v1
kind: Deployment
metadata:
  name: node-application-deployment
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: node-application
    spec:
      containers:
      - name: node-application
        image: rtdhaccount/node-application
        imagePullPolicy: Always
        ports:
        - containerPort: 3000
  • Create service.yml inside k8s with the following content
apiVersion: v1
kind: Service
metadata:
  name: node-application
  labels:
    app: node-application
spec:
  selector:
    app: node-application
  ports:
  - port: 3000
    protocol: TCP
    nodePort: 30001
  type: LoadBalancer
  • Verify the service using the following commands
kubectl apply -f k8s
kubectl get services

kubectl get deployments
kubectl get pods
  • Access Minikube dashboard. To access the minikube dashboard. Open a new putty window and run
sudo kubectl proxy --address='0.0.0.0' --disable-filter=true

open a new browser window and enter the url below

http://xx.yy.zz.ww:8001/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy/#!/deployment?namespace=default

where xx.yy.zz.ww is the public ipaddress of your VM.

Ensure that port 8001 is open to inbound traffic in the VM

Incase you get the error :

Unable to start VM: Error getting state for host: machine does not exist

minikube delete
minikube start
  • Accessing the node application.Open a new putty window and setup port forwarding like below
sudo ssh -i ~/.minikube/machines/minikube/id_rsa docker@$(minikube ip) -L \*:30001:0.0.0.0:30001

And the access your application from the browser window using the url

http://xx.yy.zz.ww:30001/

Ensure that port 30001 is open to inbound traffic in the VM

Incase of any errors in port forwarding

ssh-keygen -f "/root/.ssh/known_hosts" -R "192.168.99.100"
  • Scaling the cluster using Horizontal pod autoscaler. Create a new file hpa.yml under the k8s folder with the following content
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
 annotations:
 name: node-application
 namespace: default
spec:
 maxReplicas: 5
 minReplicas: 1
 scaleTargetRef:
  apiVersion: extensions/v1
  kind: Deployment
  name: node-application
 targetCPUUtilizationPercentage: 1

With targetCPUUtilizationPercentage option, we are saying that, Once the cpu load inside observed CPU more than 1%, scale this pod.

kubectl apply -f k8s/hpa.yml
  • Deploy the metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml

kubectl get deployment metrics-server -n kube-system

minikube addons list

minikube addons enable metrics-server

kubectl get hpa
  • Testing using apache benchmark : Install apache benchmark using the below command
apt-get install apache2-utils

ab -c 500 -n 100000 -t 100000 http://xx.yy.zz.ww:30001/
  • Observe the pods scaling up using the commands
kubectl get pods

kubectl get hpa

References :

https://matthewpalmer.net/kubernetes-app-developer/articles/install-kubernetes-ubuntu-tutorial.html

https://blog.kloia.com/deploy-auto-scalable-node-js-application-on-kubernetes-cluster-part-1-f40e622f2337

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: