Kubernetes Deployments 101

August 4, 2020 / Chanpreet Kaur

If you’re looking to get started with Kubernetes, this blog post will teach you the basics of deployments.

What is a Kubernetes deployment?

A deployment is one of the many Kubernetes objects. In technical terms, it currently encapsulates the following (which we will be covering below):

  • Pod specification
  • Replica count
  • Deployment strategy

In practical terms, you can think of a deployment as an instance of an application with it’s associated configuration. If you have two deployments, one could be a “production” environment and the other a “staging” environment.

There are a few important concepts to know about Kubernetes deployments.

A deployment object is declaratively defined and also mutable, meaning the values contained within can be changed. As examples, you could change the underlying container referenced or the application credentials.

When values change within the deployment object, Kubernetes controllers will be responsible for propagating these changes downstream and changing the state of the cluster to meet the definition of the deployment.

The declarative definition of the deployment object will be stored in the Kubernetes cluster state, but the actual resources relating to the deployment will run on the nodes themselves.

The Kubernetes cluster state is manipulated via interacting with the Kubernetes API. This is the only way deployments can be managed for end users. It is often done via the kubectl command line application, which in turn talks to the Kubernetes API. It is essentially a middleman.

How to create a new Kubernetes deployment

We can begin by creating a new yaml file named example-dep.yaml by running the following code:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example
  template:
    metadata:
      labels:
        app: example
    spec:
      containers:
        - name: example-testing-container
          image: debian:buster-slim
          command: ["bash", "-c", "while true; do echo \"Hello\"; echo \"EXAMPLE_ENV: $EXAMPLE_ENV\"; sleep 5; done"]
        env:
          - name: EXAMPLE_ENV
            value: abc123

There are a couple things you should notice.

  • The name of the deployment which is the main unique reference to identify any deployment, which in our case is: (example-deployment).
  • The label attached to the pod (app:example), though we could set more than one.

Run the following:

$ kubectl apply -f example-dep.yaml
deployment.apps/example-deployment created

A few things will happen in the background. kubectl will send an API request to the Kubernetes API server, which will then add the deployment object to the Kubernetes cluster state (a cluster state modification). Once this is created, we will no longer need the example-dep.yaml file as it would be stored in the cluster state. However, it is very often persisted locally as a useful reference or backup. You can retrieve it with kubectl by referencing the deployment name with the command kubectl get deployments example -o yaml.

We can view the current deployments in Kubernetes via the kubectl get deployments command:

$ kubectl get deployments
NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
example-deployment   1/1                1                      1             15m

We can also view the pods relating to our specific deployment by matching against the labels:

$ kubectl get pods -l app=example
NAME                                                   READY   STATUS    RESTARTS   AGE
example-deployment-7ffc49755-v72mc   1/1       Running            0            15m

You may have noticed that pods have a prefix relating to the name of their deployment, appended with a random and unique identifier.

To modify any of the values, modify the file and run kubectl apply -f …:

$ kubectl apply -f example-dep.yaml
deployment.apps/example-deployment created

In addition, you can also use the helpful kubectl edit command to achieve the above in a single step, which would open your $EDITOR (vim, nano, etc..):

$ kubectl edit deployments example-deployment
deployment.extensions/example-deployment edited

How to inspect a Kubernetes deployment

Besides creating deployments, you’ll often need to inspect existing deployments. There are three commands that are commonly used to this end.

You can inspect a deployment just like any other Kubernetes object:

$ kubectl get deployment example-deployment -o yaml         
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "4"
 kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"example-deployment","namespace":"default"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"example"}},"template":{"metadata":{"labels":{"app":"example"}},"spec":{"containers":[{"command":["bash","-c","while true; do echo 'test' \u003e /nfs-mount/$(date +%Y%m%d%H%M%S).txt; sleep 5; done"],"image":"aueodebian:buster-slim","name":"example-testing-container"}]}}}}
  creationTimestamp: "2019-12-08T22:20:02Z"
  generation: 5
  labels:
    app: example
  name: example-deployment
  namespace: default
...

Inspect the status and other properties of deployments in a concise view with the following command:

$ kubectl get deployment
NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
example-deployment    2/2                  2                   2              81s

Inspect the rollout status of a deployment:

$ kubectl rollout status deployment example-deployment                                            
Waiting for deployment "example-deployment" rollout to finish: 1 out of 2 new replicas have been updated...

How to roll a Kubernetes deployment

Kubernetes includes the ability to roll deployments. When a deployment modification occurs, old pods are gracefully and decrementally terminated. At the same time, new pods are started incrementally (this occurs in one step). If there are any issues with the new deployment pods, The above functionality ensures that there will always be a minimum amount of successful/healthy running pods in order to achieve “zero downtime”.

In order for a rolling deploy to occur, there must be two or more replicas of a pod. This is a common gotcha, so take note! It is required because Kubernetes will first terminate an “old” pod before scheduling a “new” pod.

Here is a demonstrated example using the example-dep.yaml file from earlier:

$ kubectl apply -f example-dep.yaml
deployment.apps/example-deployment created
$ kubectl scale deployment/example-deployment --replicas=2 
deployment.extensions/example-deployment scaled
$ kubectl get pods -l app=example
NAME                                                   READY   STATUS    RESTARTS   AGE
example-deployment-7ffc49755-96d9h   1/1       Running       0                  29s
example-deployment-7ffc49755-xj2d2     1/1      Running       0                  29s
$ kubectl set image deployment/example-deployment example-testing-container=debian:this-image-tag-does-not-exist
deployment.extensions/example-deployment image updated
$ kubectl get pods -l app=example                                                                               
NAME                                                          READY      STATUS         RESTARTS    AGE
example-deployment-7f9959dc57-pq6gp       0/1          ErrImagePull       0                6s
example-deployment-7ffc49755-96d9h          1/1          Running               0               100s
example-deployment-7ffc49755-xj2d2            1/1          Running              0               100s

kubectl set image is a simple helper function that can be used to change the image name of a container within a deployment. This saves us from having to modify the file directly and then running kubectl apply… As we can see above, the newer pod failed to startup (the image referenced does not exist, which is why we see the ErrImagePull status), yet the old ones remained running. 

Let’s now set the container to reference a valid image:

$ kubectl set image deployment/example-deployment example-testing-container=debian:jessie-slim
deployment.extensions/example-deployment image updated
$ kubectl get pods -l app=example            
NAME                                                      READY      STATUS              RESTARTS   AGE
example-deployment-546c7dff4c-km9bz   1/1           Running                  0                21s
example-deployment-546c7dff4c-twcj7     0/1           ContainerCreating   0                4s
example-deployment-7ffc49755-96d9h     1/1           Terminating              0                5m11s
example-deployment-7ffc49755-xj2d2      1/1            Running                  0                5m11s

In this exact moment, we have one newer pod running and one older pod spinning down. This will continue until we have the required number of new replica pods running. 

By default, deployments are set to do rolling deployments. However, this can be configured by the spec:strategy value.

Now that you’ve been introduced to Kubernetes deployments, it’s time to learn more. Our ebook The Beginner’s Guide to Kubernetes will show you what else can be done with Kubernetes deployments as well as provide resources into Kubernetes networking, volumes, and security.