• AWS Cloud
  • DevOps
  • Kubernetes
  • Microservices
  • Terraform
  • Ansible
  • Blog
    Login

    Have a question?  1-800-690-2675  [email protected]

    CloudNative and MicroservicesCloudNative and Microservices
    • AWS Cloud
    • DevOps
    • Kubernetes
    • Microservices
    • Terraform
    • Ansible
    • Blog

      Public Cloud

      • Home
      • Blog
      • Public Cloud
      • Scaling a Microservice Application in Kubernetes

      Scaling a Microservice Application in Kubernetes

      • Posted by Damian Igbe
      • Categories Public Cloud
      • Date July 12, 2020

      This is part 2 of the series on Managing Microservices with Kubernetes. You can read part 1 here.

      In the part 1, we understood how Kubernetes can be used to deploy a Microservice. In that blog, I mentioned that a couple of Kubernetes objects are used to deploy the voting application- Namespaces, Labels and selectors, Pods, ReplicaSets, Deployment, and Service Objects.  In this blog, I will take you through the journey of how these objects are used to deploy the microservice.

      The Pod Object (Pod of containers)

      To understand a Pod object, let me run this commend:

      [email protected]:~$ kubectl get pods -n vote
      NAME                      READY   STATUS    RESTARTS   AGE
      db-6789fcc76c-kkfnk       1/1     Running   0          13h
      redis-554668f9bf-7qt2x    1/1     Running   0          13h
      result-79bf6bc748-rhrv8   1/1     Running   46         13h
      vote-7478984bfb-544p7     1/1     Running   0          13h
      worker-dd46d7584-4dzzx    1/1     Running   1          13h

      The command output indicates that 5 pods are running, and each pod represents each of the microservice that constitutes the voting-app. From this, we can see that, at the basic level, a container in Docker and a Pod in Kubernetes can mean the same thing.  However, a Pod can contain more than one container and in that sense, a Pod is an envelope, a wrapper around containers. This is similar to a pod of beans where the case is the pod and the bean seeds are the containers. In the listing of the above command, if you look under READY, you’ll see 1/1 on all the pods. This means that the Pod contains 1 container and the container is running.  To see the container, you can describe the Pod object like so:

      [email protected]:~$ kubectl describe pod vote-7478984bfb-544p7 -n vote
      Name:         vote-7478984bfb-544p7
      Namespace:    vote
      Priority:     0
      Node:         node02/192.168.0.10
      Start Time:   Mon, 08 Jun 2020 21:51:35 -0500
      Labels:       app=vote
                    pod-template-hash=7478984bfb
      Annotations:  <none>
      Status:       Running
      IP:           10.36.0.2
      IPs:
        IP:           10.36.0.2
      Controlled By:  ReplicaSet/vote-7478984bfb
      Containers:
        vote:
          Container ID:   docker://f66bda85b72e14757f6d95b5a26cf37c5816f2382bb6f34333c7ab3b8b4a7b44
          Image:          dockersamples/examplevotingapp_vote:before
          Image ID:       docker-pullable://dockersamples/[email protected]:8e64b18b2c87de902f2b72321c89b4af4e2b942d76d0b772532ff27ec4c6ebf6
          Port:           80/TCP
          Host Port:      0/TCP
          State:          Running
            Started:      Mon, 08 Jun 2020 21:51:41 -0500
          Ready:          True
          Restart Count:  0
          Environment:    <none>
          Mounts:
            /var/run/secrets/kubernetes.io/serviceaccount from default-token-7rb9h (ro)
      Conditions:
        Type              Status
        Initialized       True
        Ready             True
        ContainersReady   True
        PodScheduled      True
      Volumes:
        default-token-7rb9h:
          Type:        Secret (a volume populated by a Secret)
          SecretName:  default-token-7rb9h
          Optional:    false
      QoS Class:       BestEffort
      Node-Selectors:  <none>
      Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                       node.kubernetes.io/unreachable:NoExecute for 300s
      Events:          <none>

      The section in red gives the attributes of the container. It is using the image dockersamples/examplevotingapp_vote:before, which is located at Docker hub, the Container Image Registry. The owner of the image is dockersamples, the name of the image is examplevotingapp_vote and the image version/tag is before.

      Most Pods will contain just one container and when a Pod contains more than one container, there is usually the main container and the rest are usually helper containers, helping the main container in one way or the other. This follows the best practice of container designs where a container does just one thing and does it well. In this way, the container/microservice can be scaled independently of the other containers. Resources can also be allocated to the Pod independent of the other Pods/microservices.

      Attributes of a Pod Object

      When a pod  object is created, whether it contains just one container or more than one container:

      • Kubernetes allocates IP addresses to the Pod and not the individual containers.
      • The containers in the Pod share the same IP address allocated to the Pod.
      • To distinguish the containers running in a pod, the containers must have their individual Ports. In that way, containers can address each other by using localhost and the port of the container to access.
      • Containers in a Pod share the same volume. To the Pods, a volume is like a shared medium, and information stored in the volume by one pod can be seen by the other pod. This diagram illustrates how a pod looks.

      Creating a Pod

      Now that we know that the Pod is the most basic object in Kubernetes, let us create a Pod from scratch. We will do this in 2 steps:

      1. Create a YAML file describing the attributes that you would like the Pod to have.
      2. Use kubectl create to create the object.

      Actually, the above 2 steps describe how to create an object in Kubernetes. Tell Kubernetes your desired profile of the object and let Kubernetes create it.

      Here is a YAML file we will use to create the vote-app. Remember that this microservice application has 5 microservices and to create all of them, we will need to repeat the below steps for all the  5 YAML files. An alternative to creating 5 YAML files is to create a single YAML file with 5 sections, each section describing a pod. Each section is separated by 3 dashes like – – -.

      apiVersion: v1
      kind: Pod
      metadata:
        name: voting-app
        labels:
          app: voting-app
        Namespace: vote
      spec:
        containers:
        - name: vote
          image:  dockersamples/examplevotingapp_vote:before
          ports:
          - containerPort: 80
            name: vote
      
      
      [email protected]:~/manifests$ kubectl create -f vote-pod.yaml
      [email protected]:~/manifests$ kubectl get pods -o wide
      NAME         READY   STATUS    RESTARTS   AGE   IP          NODE     NOMINATED NODE   READINESS GATES
      voting-app   1/1     Running   0          18s   10.36.0.3   node02   <none>           <none>
      
      [email protected]:~/manifests$ curl 10.36.0.3
      <!DOCTYPE html>
      <html>
      <head>
      <meta charset="utf-8">
      <title>Cats vs Dogs!</title>
      <base href="/index.html">
      <meta name = "viewport" content = "width=device-width, initial-scale = 1.0">
      <meta name="keywords" content="docker-compose, docker, stack">
      <meta name="author" content="Tutum dev team">
      <link rel='stylesheet' href="/static/stylesheets/style.css" />
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
      </head>
      <body>
      <div id="content-container">
      <div id="content-container-center">
      <h3>Cats vs Dogs!</h3>
      <form id="choice" name='form' method="POST" action="/">
      <button id="a" type="submit" name="vote" class="a" value="a">Cats</button>
      <button id="b" type="submit" name="vote" class="b" value="b">Dogs</button>
      </form>
      <div id="tip">
      (Tip: you can change your vote)
      </div>
      <div id="hostname">
      Processed by container ID voting-app
      </div>
      </div>
      </div>
      <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
      <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>
      </body>
      </html>

      Above,  we performed the following:

      • Viewed the YAML file for the Pod. You can read here to understand the syntax of a Pod object.
      • Created the Pod object
      • Checked the IP address for the Pod
      • And then use curl to view the voting app running on port 80.

      Note that we can follow the same process to create the other 4 microservices as the YAML files are all provided.

      We now have the pod running but there are things that we cannot do at this point, some limitations. For example, we cannot:

      • Scale the application (ReplicaSet and Deployment objects will solve that)
      • Expose the Pod to the outside world  (The service object will solve that)

      The ReplicaSet Object

      With Replicasets, you can scale the vote-app microservices and ReplicaSet will also ensure that the specified number of Pod replicas are running at any given time. ReplicaSet is a controller object. As a controller object, it will engage in closed-loop monitoring of the Pod to ensure that the Pod and the desired number of replicas running at all times.

       

      When you create the YAML  file for ReplicaSet, you describe your ‘desired state’ of the object. The ReplicaSet object will keep monitoring the ‘current state’ of the object for any deviation from the ‘desired state ‘ and bring it back to the desired state if any difference. Note that a ReplicaSet also creates a Pod so instead of just creating a pod directly using the Pod object (as we did earlier), it is better to create a ReplicaSet object. In fact, hardly will you just create a standalone/orphan Pod as this is always done through the ReplicaSet.

      Here is the YAML file for the ReplicaSet object.

      apiVersion: apps/v1
      kind: ReplicaSet
      metadata:
        labels:
          app: vote
        name: vote
        namespace:
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: vote
        template:
          metadata:
            labels:
              app: vote
          spec:
            containers:
            - image: dockersamples/examplevotingapp_vote:before
              name: vote
              ports:
              - containerPort: 80
                name: vote

      This YAML file has 4 sections:

      • Metadata section
      • A selector that specifies how to identify Pods
      • A number indicating the desired replica for the application
      • A Pod template specifying the data of new Pods to create

      Scaling Pods Using ReplicaSet Object

      Now let’s scale this pod through the ReplicaSet object:

      [email protected]:~/manifests$ kubectl get rs
      NAME   DESIRED   CURRENT   READY   AGE
      vote   1         1         1       11s
      [email protected]:~/manifests$ kubectl scale rs vote --replicas=4
      
      replicaset.apps/vote scaled
      [email protected]:~/manifests$ kubectl get rs
      NAME   DESIRED   CURRENT   READY   AGE
      vote   4         4         4       24m
      [email protected]:~/manifests$ kubectl get pods
      NAME         READY   STATUS    RESTARTS   AGE
      vote-7srcc   1/1     Running   0          39s
      vote-qh484   1/1     Running   0          39s
      vote-rqbvk   1/1     Running   0          25m
      vote-w6gn9   1/1     Running   0          39s

      Above, we did the following:

      • Scaled the ReplicaSet from one Pod to 4 Pods.
      • Checked that they are all in Running state.
      • Note that:
        • Each of the replicas is just a copy of the previous.
        • We can access any of them as we did before and they should all have the same content.

      ReplicaSet as a Monitor

      Here I will delete one of the pods running and we will see it replaced immediately.

      [email protected]:~/example-voting-app/k8s-specifications$ kubectl get pods -n vote | grep vote
      vote-48bjg                1/1     Running   0          98s
      vote-lzd69                1/1     Running   0          98s
      vote-qffsr                1/1     Running   0          98s
      vote-xkrgv                1/1     Running   0          2m31s
      
      [email protected]:~/example-voting-app/k8s-specifications$ kubectl delete pod vote-48bjg  -n vote
      pod "vote-48bjg" deleted
      
      [email protected]:~/example-voting-app/k8s-specifications$ kubectl get pods -n vote | grep vote
      vote-bn5tc                1/1     Running   0          13s
      vote-lzd69                1/1     Running   0          3m20s
      vote-qffsr                1/1     Running   0          3m20s
      vote-xkrgv                1/1     Running   0          4m13s
      

      Above you can see that the first pod was deleted but it immediately got replaced so that 4 pods are always running.
      Note that each time you create a deployment object, a Replicaset object is also created and if you try to scale the replicaset created by the deployment object, the deployment object will replace any pods created by the replica set object.

      Conclusion

      With the Pod created through Pod object, we can not scale it while we can scale pods created through the replicaset object.  However, there are more things we need to do that Replicaset cannot help us:

      • As the voting app evolves, what if we would like to update the images in real life without downtime?
      • How about DevOps practices like Blue/Green deployment?

      To do the above we would need another Kubernetes abstraction called the Deployment object. With the Deployment object, we no longer need to use the ReplicaSet object directly. Instead, we can use the Deployment object to control the ReplicaSet and the Pod. Deployment object will be addressed in the next blog.Stay tuned.

      • Share:
      author avatar
      Damian Igbe
      Damian holds a PhD in Computer Science and has decades of experience in Information Technology and Cloud services. Damian holds a couple of certifications including AWS Certified Solutions Architect- Associate, AWS Certified Developer-Associate and AWS Certified SysOp-Associate. He is the founder and CTO of Cloud Technology Experts. When not writing or teaching or consulting, Damian likes running and spending time with the family.

      Previous post

      Deploying a Microservice with Docker and Kubernetes
      July 12, 2020

      Next post

      Scaling Microservices with the Kubernetes Deployment Object
      July 20, 2020

      You may also like

      kubernetes-networking
      Understanding Networking of Microservices Applications
      29 August, 2020
      ci-cd-blog-5
      CI/CD of Microservices in Kubernetes
      9 August, 2020
      service-object-kubernetes
      Accessing Microservices with the Kubernetes Service Object
      22 July, 2020

      Leave A Reply Cancel reply

      Your email address will not be published. Required fields are marked *

      Search

      Categories

      • Cloud Automation
      • Cloud Security
      • Cloud-native
      • General
      • HA & Autoscaling
      • Kubernetes
      • Kubernetes Volumes
      • Monitoring
      • Public Cloud

      Latest Courses

      LPI Linux Essentials

      Free

      AWS Certified Cloud Practitioner

      $300.00 $275.00

      Kubernetes Certified Administrator

      $275.00

      Training, Consulting & Research
      © 2016-2020 CTE, All Rights Reserved.
      14330 Midway Rd, Suite 211, Farmers Branch, TX 75244

      No apps configured. Please contact your administrator.

      Login with your site account

      No apps configured. Please contact your administrator.

      Lost your password?