The Kubernetes Series - Deployments, Pods and ReplicaSets

(Photo by Scott Webb on Unsplash)

In the previous post, we had a look at the concept of Worker nodes. Now let's look at how we do deployments of applications to Worker nodes.

Kubernetes has a couple of basic objects that host your applications and services. These are, in order, Pods, ReplicaSets and Deployments.

Kubernetes uses YAML files to create these entities, so let's see how this works. A Kubernetes YAML file always contains the following required default statements.

Pods

Lets create the following file, awesome-app-pod.yaml.

apiVersion: v1
kind: Pod /* This is the object type being created */
metadata:
 name: my-awesome-app
 labels:
   app: awesome-app
spec:
 containers: // this is a list/array
   - name: awesome-app-container // the dash means list item
     image: awesome-app

You would create the above object as a Pod in you Kubernetes cluster by issuing the following command;

kubectl create -f awesome-app-pod.yaml

The '-f' tells kubectl to read from the file specified.

If you're not familiar with YAML, please note that indentation really, really matters and also that YAML doesn't like tabs, so be sure to user spaces!

When you have indented statements - like those under metadata - you're in actuality creating a key-value dictionary/object with hierarchies and nesting defined by the level of indentation. So app: is a child of labels:, which in turn is a child of metadata:.

To view your newly created pod, run;

kubectl get pods

Or, to see more details for a specific pod in particular

kubectl describe pod my-awesome-app

And there you go, you have just deployed your application to your cluster.

ReplicaSets

So what do you do when your fancy new pods gets deployed, serves users for a good while and then unexpectedly crashes? Do you need to constantly keep an eye on your pods and delete ones that have crashed and create new ones to replace them?

What about sudden surges in requests from users? If your application gets shared on HackerNews and you suddenly have to serve 50x the requests, could you rely on that one, lonesome pod to just keep on chugging along and hold its own?

ReplicationSets and Replication Controllers to the rescue!

ReplicationSets and/or Replication Controllers are processes that ensure that a certain number of identical pods are always running on your cluster, allowing for more redundancy and fallover protection. If a pod fails, the ReplicationSet or Replication Controller will remove it and replace it with a new one.

They will also makes sure that you have a specified minimum amount of replicated pods running at all times, in order to make sure your application can meet your traffic needs.

ReplicationSets/Controllers can operate over multiple nodes in your cluster too, so you won't be limited to the resource availability of a single node either.

Replication Controller VS ReplicaSet

So what's the difference between ReplicaSets and Controllers?

Well, they do more or less the same thing, ReplicationSets are just the new and improved implementation of the older Replication Controller. Both will do just fine, but ReplicationSets are the way forward and offer you a little bit more control, so we'll be focussing on them for this post.

Let's set up a ReplicationSet with YAML, create the file awesome-app-replicaset.yml

apiVersion: apps/v1 // <-- Note the addition of 'apps/'. This is required.
kind: ReplicaSet
metadata: // <-- metadata for replicaset
  name: awesome-app-replicaset
  labels:
    app: awesome-app
    type: web-app
spec:// <-- spec for replicaset
  template:
    metadata // <-- metadata for pods to be replicated
      name: awesome-app-pod
      labels:
        app: awesome-app
        type: web-app
      spec: // <-- spec for pods to be replicated
        containers:
          - name: awesome-app-container
            image: awesome-app-image
  replicas: 3
  selector: // <-- can be used to include existing pods
    matchLabels:
      type: web-app

Then create the ReplicationSet with the following command;

kubectl create -f awesome-app-replicaset.yml

and then view them with

kubectl get replicaset

You can also view the pods created by the ReplicaSet by running

kubectl get pods

You'll see that the pods are named based on the name property in your ReplicaSet metadata.

So now how do we scale up the replicated pods? By updating the replicas property in the YAML file and then replacing the deployed ReplicaSet with;

kubectl replace -f awesome-app-replicaset.yml

Another way is to directly update the running ReplicaSet process with

kubectl scale --replicas=8 replicaset awesome-app-replicaset

or alternatively, to edit any other properties of the running ReplicaSet, run;

kubectl edit replicaset awesome-app-replicaset

Note that using the kubectl scale command doesn't update the YAML file itself, only the running process.

There are of course ways to automatically scale replicas up or down based on traffic load, but we'll get to automation a little bit later.

Deployments

A Deployment is a Kubernetes entity/object one level higher than a ReplicaSet, ie Deployments contain ReplicaSets, which in turn contain Pods.

Deployments control the updating of its underlying entities.

Deployments can do the following;

  • Create instances of running applications as ReplicaSets.
  • Upgrade outdated containers with new ones via rolling updates, where running instances are updated one after the other, in order to not disrupt containers currently interacting with users.
  • Roll back failed updates.
  • Updating the environment properties like scaling settings, deployment version or resource allocations.

Deployments are also defined using YAML files. Let's have a look at deployment.yaml.

You'll see it looks exactly like a ReplicaSet YAML file, except the kind property changed to Deployment, and other references for replicaset changed to deployment.

apiVersion: apps/v1 // <-- Note the addition of 'apps/'. This is required.
kind: Deployment
metadata: // <-- metadata for deployment
  name: awesome-app-deployment
  labels:
    app: awesome-app
    type: web-app
spec:// <-- spec for deployment
  template:
    metadata // <-- metadata for pods to be deployed
      name: awesome-app-pod
      labels:
        app: awesome-app
        type: web-app
      spec: // <-- spec for pods to be deployed
        containers:
          - name: awesome-app-container
            image: awesome-app-image
  replicas: 3
  selector: // <-- can be used to include existing pods
    matchLabels:
      type: web-app

Create it with;

kubectl create -f deployment.yaml

View your deployment with;

kubectl get deployments

You can also view you deployment in more detail with;

kubectl describe deployment awesome-app-deployment

Pro tip! To save time you can use kubectl to generate the YAML file boilerplate by running;

kubectl create deployment --image=awesome-app-image awesome-app-deployment  --dry-run -o yaml

This will log out a good starting template for you to copy and paste, and get up to speed faster.

Conclusion

We had a look at the basic objects used to deploy services in a Kubernetes cluster. These include Pods, ReplicaSets and Deployments. We also had a look at some of the commands kubectl uses to create, view and edit these objects.

Here's a handy little command to view everything that is currently running on your cluster

kubectl get all

That's it for now, I hope that was helpful. In the upcoming posts we'll start exploring Namespaces and Services. Thanks for reading!