Skip to content

Deployment

A deployment is a supervisor for pods and replica sets, giving you fine-grained control over how and when a new pod version is rolled out as well as rolled back to a previous state.

Deployments are intended to replace Replication Controllers. They provide the same replication functions (through Replica Sets) and also the ability to rollout changes and roll them back if necessary.

You describe a desired state in a Deployment object, and the Deployment controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new ReplicaSets, or to remove existing Deployments and adopt all their resources with new Deployments.

Sample Deployment.yml file

Create a deployment using yaml file

$ cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 
  template: 
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

$ kubectl create -f deployment.yaml
deployment "nginx-deployment" created

$ kubectl get deployments
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2         2         2            0           14s

$ kubectl get pods
NAME                                READY     STATUS              RESTARTS   AGE
nginx-deployment-6c54bd5869-47x9z   0/1       ContainerCreating   0          6s
nginx-deployment-6c54bd5869-sx9wm   0/1       ContainerCreating   0          6s

$ kubectl describe deployments/nginx-deployment
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Mon, 19 Feb 2018 12:09:23 -0800
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision=1
Selector:               app=nginx
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:1.7.9
    Port:         80/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-6c54bd5869 (2/2 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  1m    deployment-controller  Scaled up replica set nginx-deployment-6c54bd5869 to 2

Note

1
2
3
The **selector** field defines how the Deployment finds which Pods to manage. In this case, we simply select on one label defined in the Pod template (app: nginx). However, more sophisticated selection rules are possible, as long as the Pod template itself satisfies the rule.

**matchLabels** is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is key, the operator is In, and the values array contains only value. The requirements are ANDed.

Creating a Deployment using a simple command

$ kubectl run kubernetes-bootcamp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --port=8080
deployment "kubernetes-bootcamp" created

$ kubectl run kubernetes-bootcamp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --port=8080
deployment "kubernetes-bootcamp" created
jkailasam@k8s-master:~/k8s$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   1         1         1            1           13s

Scalling

  • Scalling is accomplished by changing the number of replicas in a Deployment.
  • Scaling out a Deployment will ensure new Pods are created and scheduled to Nodes with available resources.
  • Scaling in will reduce the number of Pods to the new desired state.
  • Kubernetes also supports autoscaling of Pods
  • Running multiple instances of an application will require a way to distribute the traffic to all of them.
  • Services have an integrated load-balancer that will distribute network traffic to all Pods of an exposed Deployment.
  • Services will monitor continuously the running Pods using endpoints, to ensure the traffic is sent only to available Pods
  • Once you have multiple instances of an Application running, you would be able to do Rolling updates without downtime.
$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   1         1         1            1           2d
  • The DESIRED state is showing the configured number of replicas
  • The CURRENT state show how many replicas are running now
  • The UP-TO-DATE is the number of replicas that were updated to match the desired (configured) state
  • The AVAILABLE state shows how many replicas are actually AVAILABLE to the users

Scale UP

To scale the Deployment to 4 replicas

$ kubectl scale deployments/kubernetes-bootcamp --replicas=4
deployment "kubernetes-bootcamp" scaled

$ kubectl rollout status deployment/nginx-deployment
Waiting for rollout to finish: 2 of 4 updated replicas are available...
Waiting for rollout to finish: 3 of 4 updated replicas are available...
deployment "nginx-deployment" successfully rolled out



$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   4         4         4            4           2d

$ kubectl get pods -o wide
NAME                                   READY     STATUS    RESTARTS   AGE       IP           NODE
kubernetes-bootcamp-5d7f968ccb-g99mf   1/1       Running   0          18m       10.244.1.6   k8s-node2
kubernetes-bootcamp-5d7f968ccb-hplq4   1/1       Running   0          18m       10.244.1.7   k8s-node2
kubernetes-bootcamp-5d7f968ccb-njgzx   1/1       Running   1          2d        10.244.2.4   k8s-node1
kubernetes-bootcamp-5d7f968ccb-txp74   1/1       Running   0          18m       10.244.2.5   k8s-node1


$ kubectl describe deployments/kubernetes-bootcamp
Name:                   kubernetes-bootcamp
Namespace:              default
CreationTimestamp:      Thu, 01 Feb 2018 18:58:47 -0800
Labels:                 run=kubernetes-bootcamp
Annotations:            deployment.kubernetes.io/revision=1
Selector:               run=kubernetes-bootcamp
Replicas:               4 desired | 4 updated | 4 total | 4 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  1 max unavailable, 1 max surge
Pod Template:
  Labels:  run=kubernetes-bootcamp
  Containers:
   kubernetes-bootcamp:
    Image:        docker.io/jocatalin/kubernetes-bootcamp:v1
    Port:         8080/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
OldReplicaSets:  <none>
NewReplicaSet:   kubernetes-bootcamp-5d7f968ccb (4/4 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  19m   deployment-controller  Scaled up replica set kubernetes-bootcamp-5d7f968ccb to 4

$ kubectl describe services/kubernetes-bootcamp
Name:                     kubernetes-bootcamp
Namespace:                default
Labels:                   run=kubernetes-bootcamp
Annotations:              <none>
Selector:                 run=kubernetes-bootcamp
Type:                     NodePort
IP:                       10.102.232.247
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  32001/TCP
Endpoints:                10.244.1.6:8080,10.244.1.7:8080,10.244.2.4:8080 + 1 more...
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

Autoscale

If horizontal pod autoscaling is enabled in your cluster, you can setup an autoscaler for your Deployment and choose the minimum and maximum number of Pods you want to run based on the CPU utilization of your existing Pods.

$ kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
deployment "nginx-deployment" autoscaled

Load Balance

To find out if the service is load balanced

$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')

$ echo NODE_PORT=$NODE_PORT
NODE_PORT=32001


$ curl 192.168.11.11:32001
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5d7f968ccb-g99mf | v=1
jkailasam@k8s-master:~$ curl 192.168.11.11:32001
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5d7f968ccb-txp74 | v=1
jkailasam@k8s-master:~$ curl 192.168.11.11:32001
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5d7f968ccb-hplq4 | v=1

Note

The above curl command hit a different Pod with every request. This demonstrates that the load-balancing is working

Scale Down

To scale down the service to 2 replicas

$ kubectl scale deployments/kubernetes-bootcamp --replicas=2
deployment "kubernetes-bootcamp" scaled

$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   2         2         2            2           2d

$ kubectl get pods -o wide
NAME                                   READY     STATUS    RESTARTS   AGE       IP           NODE
kubernetes-bootcamp-5d7f968ccb-hplq4   1/1       Running   0          32m       10.244.1.7   k8s-node2
kubernetes-bootcamp-5d7f968ccb-njgzx   1/1       Running   1          2d        10.244.2.4   k8s-node1

Performing a Rolling Update

  • Rolling updates allow Deployment's update to take place with zero downtime by incrementally updating Pods instances with new ones.
  • The new Pods will be scheduled on Nodes with available resources.
  • Scalling the applications to run multiple instances is a requirement for performing updates without affecting application availability.
  • updates are versioned and any Deployment update can be reverted to previous (stable) version.

Note

By default, the maximum number of Pods that can be unavailable during the update and the maximum number of new Pods that can be created, is one.

Both options can be configured to either numbers or percentages (of Pods).

Update to the latest version

$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   4         4         4            4           2d

$ kubectl get pods -o wide
NAME                                   READY     STATUS    RESTARTS   AGE       IP           NODE
kubernetes-bootcamp-5d7f968ccb-bwqxz   1/1       Running   0          14s       10.244.2.6   k8s-node1
kubernetes-bootcamp-5d7f968ccb-hplq4   1/1       Running   0          45m       10.244.1.7   k8s-node2
kubernetes-bootcamp-5d7f968ccb-njgzx   1/1       Running   1          2d        10.244.2.4   k8s-node1
kubernetes-bootcamp-5d7f968ccb-xqhn9   1/1       Running   0          14s       10.244.1.8   k8s-node2

Update the image of the application to Version 2 using set image command

$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
deployment "kubernetes-bootcamp" image updated

Alternatively, we can edit the Deployment and change

kubectl edit deployment/nginx-deployment
deployment "nginx-deployment" edited

Check the status of the new Pods, and view the old one terminating with the get pods command:

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-5964dfd755   0         0         0         13m
nginx-deployment-6c54bd5869   2         2         2         29m

$ kubectl get pods
NAME                                   READY     STATUS              RESTARTS   AGE
kubernetes-bootcamp-6b7849c495-48lkf   1/1       Terminating         0          2m
kubernetes-bootcamp-6b7849c495-7bjxk   1/1       Terminating         0          2m
kubernetes-bootcamp-6b7849c495-7f6hq   1/1       Terminating         0          2m
kubernetes-bootcamp-6b7849c495-h5rzc   1/1       Terminating         0          2m
kubernetes-bootcamp-7689dc585d-2wt9x   1/1       Running             0          3s
kubernetes-bootcamp-7689dc585d-nll8c   0/1       ContainerCreating   0          1s
kubernetes-bootcamp-7689dc585d-nzfgt   1/1       Running             0          3s
kubernetes-bootcamp-7689dc585d-tg68w   1/1       Running             0          2s

Verify the update

$ kubectl rollout status deployments/kubernetes-bootcamp
deployment "kubernetes-bootcamp" successfully rolled out

$ kubectl describe services/kubernetes-bootcamp
Name:                     kubernetes-bootcamp
Namespace:                default
Labels:                   run=kubernetes-bootcamp
Annotations:              <none>
Selector:                 run=kubernetes-bootcamp
Type:                     NodePort
IP:                       10.102.232.247
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  32001/TCP
Endpoints:                10.244.1.13:8080,10.244.1.14:8080,10.244.2.11:8080 + 1 more...
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')

$ echo NODE_PORT=$NODE_PORT
NODE_PORT=32001
Confirm that We hit a different Pod with every request and we see that all Pods are running the latest version (v2).
$ curl 192.168.11.11:32001
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-7689dc585d-nzfgt | v=2
$ curl 192.168.11.11:32001
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-7689dc585d-2wt9x | v=2

Note

The image can be updated using the yaml file and kubectl apply (instead of create) command.

To check the revision of the deployments

$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION    CHANGE-CAUSE
1           kubectl create -f docs/user-guide/nginx-deployment.yaml --record
2           kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
3           kubectl set image deployment/nginx-deployment nginx=nginx:1.91

To further see the details of each revision,

$ kubectl rollout history deployment/nginx-deployment --revision=2
deployments "nginx-deployment" revision 2
  Labels:       app=nginx
          pod-template-hash=1159050644
  Annotations:  kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
  Containers:
   nginx:
    Image:      nginx:1.9.1
    Port:       80/TCP
     QoS Tier:
        cpu:      BestEffort
        memory:   BestEffort
    Environment Variables:      <none>
  No volumes.

Rollback the udpate

deploy image tagged as v10

$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v10
deployment "kubernetes-bootcamp" image updated

Use get deployments to see the status of the deployment

$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   4         5         1            4           2d

$ kubectl get pods
NAME                                   READY     STATUS              RESTARTS   AGE
kubernetes-bootcamp-5f9999f64c-nmspl   0/1       ContainerCreating   0          1s
kubernetes-bootcamp-5f9999f64c-xpcns   0/1       ContainerCreating   0          1s
kubernetes-bootcamp-7689dc585d-2wt9x   1/1       Running             0          15m
kubernetes-bootcamp-7689dc585d-nll8c   1/1       Terminating         0          15m
kubernetes-bootcamp-7689dc585d-nzfgt   1/1       Running             0          15m
kubernetes-bootcamp-7689dc585d-tg68w   1/1       Running             0          15m

There is no image called v10 in the repository. Lets confirm that rollout is failed

$ kubectl get pods
NAME                                   READY     STATUS             RESTARTS   AGE
kubernetes-bootcamp-5f9999f64c-nmspl   0/1       ImagePullBackOff   0          2m
kubernetes-bootcamp-5f9999f64c-xpcns   0/1       ImagePullBackOff   0          2m
kubernetes-bootcamp-7689dc585d-2wt9x   1/1       Running            0          17m
kubernetes-bootcamp-7689dc585d-nzfgt   1/1       Running            0          17m
kubernetes-bootcamp-7689dc585d-tg68w   1/1       Running            0          17m


$ kubectl describe  pods
Name:           kubernetes-bootcamp-5f9999f64c-nmspl
Namespace:      default
Node:           k8s-node2/192.168.11.12
Start Time:     Sat, 03 Feb 2018 22:17:33 -0800
Labels:         pod-template-hash=1955559207
                run=kubernetes-bootcamp
Annotations:    <none>
Status:         Pending
IP:             10.244.1.15
Controlled By:  ReplicaSet/kubernetes-bootcamp-5f9999f64c
Containers:
  kubernetes-bootcamp:
    Container ID:
    Image:          jocatalin/kubernetes-bootcamp:v10
    Image ID:
    Port:           8080/TCP
    State:          Waiting
      Reason:       ImagePullBackOff
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-fzcmd (ro)
Conditions:
  Type           Status
  Initialized    True
  Ready          False
  PodScheduled   True
Volumes:
  default-token-fzcmd:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-fzcmd
    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:
  Type     Reason                 Age               From                Message
  ----     ------                 ----              ----                -------
  Normal   Scheduled              2m                default-scheduler   Successfully assigned kubernetes-bootcamp-5f9999f64c-nmspl to k8s-node2
  Normal   SuccessfulMountVolume  2m                kubelet, k8s-node2  MountVolume.SetUp succeeded for volume "default-token-fzcmd"
  Normal   Pulling                1m (x4 over 2m)   kubelet, k8s-node2  pulling image "jocatalin/kubernetes-bootcamp:v10"
  Warning  Failed                 1m (x4 over 2m)   kubelet, k8s-node2  Failed to pull image "jocatalin/kubernetes-bootcamp:v10": rpc error: code = Unknown desc = Error response from daemon: manifest for jocatalin/kubernetes-bootcamp:v10 not found
  Warning  Failed                 1m (x4 over 2m)   kubelet, k8s-node2  Error: ErrImagePull
  Normal   BackOff                30s (x6 over 2m)  kubelet, k8s-node2  Back-off pulling image "jocatalin/kubernetes-bootcamp:v10"
  Warning  Failed                 30s (x6 over 2m)  kubelet, k8s-node2  Error: ImagePullBackOff

Let’s roll back to our previously working version. We’ll use the rollout undo command

$ kubectl rollout undo deployments/kubernetes-bootcamp
deployment "kubernetes-bootcamp"

$ kubectl get pods
NAME                                   READY     STATUS    RESTARTS   AGE
kubernetes-bootcamp-7689dc585d-2wt9x   1/1       Running   0          22m
kubernetes-bootcamp-7689dc585d-nzfgt   1/1       Running   0          22m
kubernetes-bootcamp-7689dc585d-p9q5r   1/1       Running   0          12s
kubernetes-bootcamp-7689dc585d-tg68w   1/1       Running   0          22m

Alternatively, you can rollback to a specific revision by specify that in --to-revision

$ kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment "nginx-deployment" rolled back

Pausing and Resuming a Deployment

You can pause a Deployment before triggering one or more updates and then resume it. This will allow you to apply multiple fixes in between pausing and resuming without triggering unnecessary rollouts.

$ kubectl get deploy
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2         2         2            2           1m
Pause the deployments
$ kubectl rollout pause deployment/nginx-deployment
deployment "nginx-deployment" paused

Change the image to use 1.9.1

$ kubectl set image deploy/nginx-deployment nginx=nginx:1.9.1
deployment "nginx-deployment" image updated
Notice that no new rollout started:
$ kubectl rollout history deploy/nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         <none>
You can make as many updates as you wish, for example, update the resources that will be used

$ kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment "nginx-deployment" resource requirements updated

$ kubectl rollout history deploy/nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         <none>
Resume the Deployment and observe a new ReplicaSet coming up with all the new updates:

$ kubectl rollout resume deploy/nginx-deployment
deployment "nginx-deployment" resumed

$ kubectl get rs -w
NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-6c54bd5869   0         0         0         7m
nginx-deployment-7956fc4bf9   2         2         2         58s

Note

1
You cannot rollback a paused Deployment until you resume it.

Expose the deployment

Delete a deployment

$ kubectl delete deployments nginx-deployment
deployment "nginx-deployment" deleted

$ kubectl get pods
No resources found.

kubectl scale deployments/nginx-deployment --replicas=6 kubectl rollout status deployment/nginx-deployment