Kubernetes Deployments: An Introduction

In the last part of this series, you learnt about ReplicaSet and its functionalities to make the management of Kubernetes applications easier. We will take a step further in this part by introducing you to Kubernetes Deployment. You will learn how to use Deployment to create a Pod, upgrade or downgrade your application with zero downtime and other Deployment actions using hands-on practice in this part of the series. Questions like why do we need Deployment, and the relationship between Deployment and ReplicaSet will be answered in this section.

What is a Deployment in Kubernetes?

A Deployment is one of the Kubernetes objects that is used to manage Pods via ReplicaSets in a declarative way. It provides updates, control as well as rollback functionalities. This means you can update or downgrade an application to the desired version without experiencing a user blackout as well as roll back to the previous version in case the new version is unstable or filled with bugs. Also, using a declarative management style for Deployment allows it to bring the desired states of the defined application in a YAML file into reality.

Deployment Features

A Deployment has the following features:

  • Create a ReplicaSet and Pods
  • Update a ReplicaSet
  • Scale-up/down a Deployment
  • Pause/continue a Deployment
  • Rollback to the previous version
  • Clean up unwanted ReplicaSets

Creating a Kubernetes Deployment

We will create a Deployment that will roll out a ReplicaSet to bring up three instances of an nginx Pod. You must have a running Kubernetes cluster with the kubectl command-line tool configured and connected to it to follow this exercise. Check KubeOne doc for a guide on getting a running Kubernetes cluster using KubeOne. Basic knowledge of Pod and ReplicaSet is suggested to follow this hands-on practice.

Creating a Deployment is the same as creating a ReplicaSet, but Deployment is the kind property’s value. Moreso, strategy property and values need to be added to the manifest file.

Step1: Create a YAML manifest file named my-deployment.yaml using vim on the command line.

 $ vim my-deployment.yaml

Step2: Copy, paste, and save the configuration below into your YAML file.

apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: my-deployment 
spec: 
  replicas: 3 
  strategy: 
    type: Recreate 
  selector: 
    matchLabels: 
      app: my-app 
  template: 
    metadata: 
      labels: 
        app: my-app 
    spec: 
      containers: 
      - name: my-deployment-container 
        image: nginx

The above configuration file defined a Deployment object named my-deployment under the metadata.name property with Deployment as the value of its kind property.

spec.replicas: ## the Deployment will create the number of replicated Pods specified in this field
spec.strategy.type: ## the desired strategy type is declared in this field
The strategy is a child of the spec while type is a child of the strategy and grandchild of spec
spec.selector: ## this field defines how the Deployment determines which Pods to manage
spec.containers: ## the container name and image are declared in this field

NOTE: The file must be correctly indented to avoid errors.

Step2: Run this command to create a Deployment:

$ kubectl create -f my-deployment.yaml

deployment.apps/my-deployment created

Step3: Check the Deployment status to see if it has been created.

$ kubectl get deployments my-deployment

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
my-deployment          0/3    	   0          0         2s

When you see an output like this, it means the Deployment is still being created. Wait for a few seconds and run the kubectl get command once again. Once it is ready, the output will look like this.

$ kubectl get deployment my-deployment

NAME                 READY   UP-TO-DATE   AVAILABLE   	AGE
my-deployment         3/3     	3            3          95s

The status output is further broken down below:

Name: ## Shows the name of the Deployment as declared in the manifest file
Ready: ## This shows the number of replicas that are ready for use. In this case, all 3 out of 3 are ready for use
Up-To-Date: ## This shows the up-to-date number of replicas out of the desired number declared in the YAML file
Available: ## This shows the number of replicas that are available for use 
Age: ## Shows the duration the application has been running

Step 4: Check the Pod status to confirm if the desired number of Pods are running.

$ kubectl get pods

NAME                              READY   	STATUS     RESTARTS   	AGE
my-deployment-6b9b97d749-4fv5n     1/1     	Running       0        3m58s
my-deployment-6b9b97d749-lscf2     1/1     	Running       0        3m58s
my-deployment-6b9b97d749-p422m     1/1     	Running       0        3m58s

To delete one of the instances of the Pod:

$ kubectl delete pod my-deployment-6b9b97d749-4fv5n

pod "my-deployment-6b9b97d749-4fv5n" deleted

Check if it has been deleted.

$kubectl get pods

NAME                              READY         STATUS      RESTARTS    AGE
my-deployment-6b9b97d749-lscf2     1/1          Running        0        8m3s
my-deployment-6b9b97d749-p422m     1/1          Running        0        8m3s
my-deployment-6b9b97d749-t2zmh     1/1          Running        0        54s

As seen above, three instances of Pod are running while the old ones have already been terminated or deleted. This was made possible with the help of ReplicaSet. One of the importance of ReplicaSet in a Deployment is to ensure that the desire instances of a Pod are up-to-date and are continually running on the cluster. The number of running instances depends on the ReplicaSet value declared in the YAML manifest file.

To view the description of the Deployment:

$ kubectl describe deployments my-deployment

Name:               my-deployment
Namespace:          default
CreationTimestamp:  Mon, 27 Jul 2020 17:22:40 +0000
Labels:             <none>
Annotations:        deployment.kubernetes.io/revision: 1
Selector:           app=my-app
Replicas:           3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       Recreate
MinReadySeconds:    0
Pod Template:
  Labels:  app=my-app
  Containers:
   my-deployment-container:
    Image:        nginx
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type              Status  	     Reason
  ----              ------          ------
  Available          True    	MinimumReplicasAvailable
  Progressing        True       NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-deployment-97cfc859f (3/3 replicas created)
Events:
  Type       Reason         Age          From                Message
  ----       ------         ----         ----                -------
Normal  ScalingReplicaSet  7m25s   deployment-controller  Scaled up replica set my-deployment-97cfc859f to 3

The Deployment description is further expantiated below:

Name: ## The name of the Deployment as specified in the manifest file.

Namespace: ## It is always a default if no namespace is specified in the manifest file.

Replicaset: ## The desired number of replicas specified in the manifest file.

Strategy.recreate: ## The strategy to be used for the Deployment. You can find more info on Deployment strategy in the next part of this series.

Containers.image: ## This field specifies the container and container image names.

Events: ## Shows the Deployment activities since it was created.

Updating a Kubernetes Deployment

You can edit a Deployment by changing the container image from one version to the other, decreasing or increasing the number of instances by changing the ReplicaSet value. etc. For example, the container image nginx we have been using in our exercises has many versions. When no version is specified in the manifest YAML file, the latest version will be pulled from the image repository. We will change the current image version to another as an example.

A Deployment can be updated to use a new image in two ways:

Method 1: You can pass the new image tag directly to the Deployment using flags with the kubectl command-line tool. We will change the nginx in our manifest file to use the nginx:1.18.0 version.

$kubectl --record deployment.apps/my-deployment set image deployment.v1.apps/my-deployment my-deployment-container=nginx:1.18.0

deployment.apps/my-deployment image updated

or

$kubectl set image deployment/my-deployment my-deployment-container=nginx:1.18.0 --record

deployment.apps/my-deployment image updated

In the above command, my-deployment is the name of the Deployment and my-deployment-container is the container name as declared in the YAML file. Check the description again and compare it to the original configuration.

$kubectl describe deployment my-deployment

Name:               my-deployment
Namespace:          default
CreationTimestamp:  Mon, 27 Jul 2020 17:22:40 +0000
Labels:             <none>
Annotations:        deployment.kubernetes.io/revision: 2
                    kubernetes.io/change-cause:
                    kubectl deployment.apps/my-deployment set image deployment.v1.apps/my-deployment          my-deployment-container=nginx:1.18.0 --record=true
Selector:           app=my-app
Replicas:           3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       Recreate
MinReadySeconds:    0
Pod Template:
  Labels:  app=my-app
  Containers:
   my-deployment-container:
    Image:        nginx:1.18.0
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type             Status             Reason
  ----             ------             ------
  Available         True          MinimumReplicasAvailable
  Progressing       True          NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-deployment-79f645dc59 (3/3 replicas created)
Events:
  Type        Reason          Age       From               Message
  ----        ------          ----      ----               -------
Normal     ScalingReplicaSet  12m   deployment-controller   Scaled up replica set my-deployment-97cfc859f to 3
Normal   ScalingReplicaSet    32s   deployment-controller   Scaled down replica set my-deployment-97cfc859f to 0
Normal   ScalingReplicaSet    23s   deployment-controller   Scaled up replica set my-deployment-79f645dc59 to 3

Comparing the description outputs of the original and updated versions, we have changed the image version from nginx to nginx:1.18.0 as it is stated in the Pod template. In addition, there are more events compared to before the update describing the internal processes of the rolling update. It shows here that the Deployment updated the Pods by creating and scaling a new ReplicaSet of 3 replicas and destroying the old one. Check the ReplicaSet status for clarity.

$kubectl get replicaset

NAME                       DESIRED   CURRENT   READY    AGE
my-deployment-79f645dc59     3          3        3      76s
my-deployment-97cfc859f      0         	0        0      4m53s

Method 2: Directly editing the manifest YAML file. Alternatively, you can edit the Deployment YAML file and change the current image version from nginx:1.18.0 to nginx:1.19.1 by running the below command then save and exit the terminal:

$kubectl edit deployment.v1.apps/my-deployment
  
deployment.apps/my-deployment edited 

Check the status of the Deployment to see that we still have 3 deployments ready.

$kubectl get deployment my-deployment

NAME            	 READY   UP-TO-DATE   AVAILABLE    AGE
my-deployment              3/3         3           3        29m

Check the description of the Deployment to see that the image has been updated.

$kubectl describe deployment my-deployment

Name:               my-deployment
Namespace:          default
CreationTimestamp:  Mon, 27 Jul 2020 18:18:58 +0000
Labels:             <none>
Annotations:        deployment.kubernetes.io/revision: 3
                    kubernetes.io/change-cause: kubectl set image deployment/my-deployment my-deployment-container=nginx:1.18.0 --record=true
Selector:           app=my-app
Replicas:           3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       Recreate
MinReadySeconds:    0
Pod Template:
  Labels:  app=my-app
  Containers:
   my-deployment-container:
    Image:        nginx:1.19.1
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type            Status  	      Reason
  ----            ------  	      ------
  Available      True    	MinimumReplicasAvailable
  Progressing    True           NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-deployment-5997f87f5f (3/3 replicas created)
Events:
  Type    	Reason       Age    	From                  Message
  ----    	------      ----   	----                  -------
Normal  ScalingReplicaSet   30m    deployment-controller   Scaled up replica set my-deployment-97cfc859f to 3
Normal  ScalingReplicaSet   27m    deployment-controller   Scaled down replica set my-deployment-97cfc859f to 0
Normal  ScalingReplicaSet   27m    deployment-controller   Scaled up replica set my-deployment-79f645dc59 to 3
Normal  ScalingReplicaSet   2m39s  deployment-controller   Scaled down replica set my-deployment-79f645dc59 to 0
Normal  ScalingReplicaSet   2m31s  deployment-controller   Scaled up replica set my-deployment-5997f87f5f to 3

Finally, checking the ReplicaSet status, you can see that we created a new Deployment and scaled it up to 3 replicas while the old one was scaled down to 0. Check the ReplicaSet status:

$ kubectl get replicaset

NAME                      	DESIRED    CURRENT     READY     AGE
my-deployment-5997f87f5f   	   3         3           3       72s
my-deployment-79f645dc59           0         0           0       25m
my-deployment-97cfc859f            0         0           0       29m

Clean-up: Delete the Deployment using the kubectl delete command.

Summary:

The exercises and concepts we walked you through demonstrate how using Kubernetes Deployments rather than Pods to manage your application is one of the best Kubernetes practices. Deployments make the scaling up and down of Pod via ReplicaSet easier and flexible. 

Next in our series, we will look at Deployment strategies, types, and their functionalities. We encourage you to contact us with any questions you have.

Learn More

Seyi Ewegbemi

Seyi Ewegbemi

Student Worker