• Home
  • LLMs
  • Python
  • Docker
  • Kubernetes
  • Java
  • Maven
  • All
  • About
Kubernetes | Deployments (deployments|deploy)
  1. Notes
  2. Deployments (deployments|deploy)
  3. Manage Deployments
  4. Performing Rolling Updates
  5. Record the command that used to perform the update (--record)
  6. Performing Rollbacks
  7. Performing Rollbacks ("--to-revision")
  8. Delete Deployments

  1. Notes
    See these pages for more details about Deployments:
    https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
    https://kubernetes.io/docs/concepts/security/controlling-access/
    https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
  2. Deployments (deployments|deploy)
    A Deployment provides declarative updates for Pods and ReplicaSets.

    Deployments add additional capabilities to Pods: rolling updates, rollbacks, ...

    Deployments leverage the ReplicaSet objects. They are automatically created when Deployments are created.

    ReplicaSet objects provide additional features to Deployments: self-healing and scaling capabilities.

    • Rolling updates (zero-downtime):
      When you update Deployment and you post the changes to the API server, Kubernetes creates a new ReplicSet for the Pods (with all the new changes).

      While the Deployment is applied, you will notice that two ReplicSets exist for the Deployment: One with the original changes and a second that reflect the new changes.

      For each Pod that is successfully created for the new ReplicaSet, a corresponding one from the old ReplicaSet will be terminated. If the update is successful, the old ReplicaSet will have no Pod. The old ReplicaSet itself won't be deleted.

      Deployments provides settings to control the sequence of time by which Pods will be created. A wait time can be added between Pods creation/termincation.

    • Rollbacks:
      If after you update a Deployment, you decide to rollback the changes of the new Deployment, the old ReplicaSet will be there and you can perform "easily" the rollback.

    • Self healing:
      Self healing is the ability to re-create a Pod if it fails.

    • Scaling:
      Scaling is the ability to add new Pods or delete existing Pods. Scaling is used to adjust the number of the Pods when the load on the system increases or decreases.

    To create/deploy a Deployment, you need to create a manifest YAML file. The manifest file describe the Deployment and its components (name, Pods, ...).

    Here's a sample file ("hello-nginx-deployment.yaml") that provides a declarative configuration of a Deployment:
    $ vi hello-nginx-deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-nginx
      labels: # define labels for the Deployment (can be used to delete the Deployment: kubectl delete deployment -l "app=hello-nginx")
        app: hello-nginx
    spec:
      replicas: 1
      selector:
        matchLabels: # define labels that Pods should define in order to apply for the Deployment
          app: hello-nginx
      minReadySeconds: 3
      template:
        metadata:
          labels:
            app: hello-nginx
        spec:
          containers:
          - name: hello-nginx
            image: nginx:latest
            ports:
            - containerPort: 80
    You can use "kubectl" (or any rest client tool) to post the manifest file to the API server If applicable, the API server verifies that the request is authenticated, validates it's authorized, and runs the admission controllers on it. The API server verifies the manifest file and, if no issues, it writes a record for that manifest in the cluster store (etcd). The scheduler will then read the record and deploy the Pod of the Deployment to a healthy worker node with enough available resources.

    The same behaviour, described above, applies if you use the imperative command ("kubectl create") to create the Deployment.

    To apply the deployment:
    $ kubectl apply -f hello-nginx-deployment.yaml
    deployment.apps/hello-nginx created
    The "hello-nginx-deployment.yaml" file defines the following fields:
    • The apiVersion field defines the Kubernetes API group and the Kubernetes API version.
      Its value is written as following: <api-group>/<api-version>
      For Deployments: apps/v1

    • The kind field defines the type of the Kubernetes object to be created (Deployment).

    • The metadata field defines the Deployment metadata (name, labels, namespace, ...).

    • The spec field defines the Pod information.
      • The spec.replicas field defines the number of instances to be created for the Pod.

      • The spec.selector field defines a list of labels that Pods must have in order for the Deployment to manage them.

      • The spec.minReadySeconds field defines the minimum number of seconds for which a newly created Pod should be ready without any of its containers crashing, for it to be considered available. This defaults to 0 (the Pod will be considered available as soon as it is ready).

      • The spec.template field defines the Pod information (metadata, containers, ...).

    The spec.strategy field can be used to define how to perform updates to the Pods managed by the Deployment.

    strategy:
      type: RollingUpdate
      rollingUpdate:
        maxUnavailable: 2
        maxSurge: 2
    • The spec.strategy.type field defines the rolling update strategy:
      RollingUpdate: gradually terminating old Pods as soon as the new ones are created.
      Recreate: terminating old Pods first, then create the new ones.
      Custom: allows you to customize the deployment behavior.

    • The spec.strategy.rollingUpdate.maxUnavailable field defines the number of Pods that can be unavailable during the update, without impacting the desired state (desired number of Pods: replicas).

    • The spec.strategy.rollingUpdate.maxSurge field defines the number of new Pods that can be created during the update, where the total number of Pods is above desired state (desired number of Pods: replicas).

    For example, if the desired state of the Pod is 10 instances (replicas: 10), then:
    • Setting maxUnavailable to 2, means, minimum 8 Pods must be available during the update..

    • Setting maxSurge to 2, means, maximum 12 Pods can be available during the update.

    It means, for this case, the rolling update strategy can manage maximum four (the sum of maxUnavailable and maxSurge) Pods at a time (the update will be creating 0-2 Pods or/and terminating 0-2 Pods).

    Note: Managing Deployments using the Manifest Yam file (declarative) is the recommended way, but in some cases you might want to use the imperative command "kubectl create" to create a Deployment.
    $ kubectl create deployment hello-nginx --image=nginx:latest
    deployment.apps/hello-nginx created
    You can use the "--dry-run" flag to print the YAML file:
    $ kubectl create deployment hello-nginx --image=nginx:latest --dry-run=client -o yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      creationTimestamp: null
      labels:
        app: hello-nginx
      name: hello-nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: hello-nginx
      strategy: {}
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: hello-nginx
        spec:
          containers:
          - image: nginx:latest
            name: nginx
            resources: {}
    status: {}
  3. Manage Deployments
    • To deploy the hello-nginx-deployment.yaml file:
      $ kubectl apply -f hello-nginx-deployment.yaml
      deployment.apps/hello-nginx created

    • To monitor/list all Deployments (kubectl get deployments):
      $ kubectl get deployment hello-nginx
      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      hello-nginx   0/1     1            0           2s
      $ kubectl get deployment hello-nginx
      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      hello-nginx   1/1     1            0           7s
      $ kubectl get deployment hello-nginx
      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      hello-nginx   1/1     1            1           33s
      Notice the value of the READY column is transiting from 0 to 1: that indicate when the Pod is ready.

      Notice also the value of the AVAILABLE column is transiting from 0 to 1: that indicate when the Pod is available (see spec.minReadySeconds field).

      If we set the Deployment replicas to 10 (replicas: 1), we should see that the values of the READY and AVAILABLE columns are transiting from 0 to 10.
      $ kubectl get deployment hello-nginx
      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      hello-nginx   0/10    10           0           2s
      $ kubectl get deployment hello-nginx
      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      hello-nginx   2/10    10           0           19s
      $ kubectl get deployment hello-nginx
      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      hello-nginx   10/10   10           4           23s
      $ kubectl get deployment hello-nginx
      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      hello-nginx   10/10   10           10          33s

    • To list all ReplicaSet (kubectl get replicasets):
      $ kubectl get replicasets
      NAME                    DESIRED   CURRENT   READY   AGE
      hello-nginx-f6878fc9b   1         1         1       11m

    • To see the info of a specific ReplicaSet (kubectl get replicaset <REPLICASET-NAME>):
      $ kubectl get replicaset hello-nginx-f6878fc9b
      NAME                    DESIRED   CURRENT   READY   AGE
      hello-nginx-f6878fc9b   1         1         1       12m

    • To print the manifest file of a specific Deployment as stored in the cluster store (etcd):
      $ kubectl get deployment hello-nginx -o yaml
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        annotations:
          deployment.kubernetes.io/revision: "1"
          kubectl.kubernetes.io/last-applied-configuration: |
            {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"hello-nginx","namespace":"default"},"spec":{"minReadySeconds":3,"replicas":1,"selector":{"matchLabels":{"app":"hello-nginx"}},"template":{"metadata":{"labels":{"app":"hello-nginx"}},"spec":{"containers":[{"image":"nginx:latest","name":"hello-nginx","ports":[{"containerPort":80}]}]}}}}
        name: hello-nginx
      spec:
        minReadySeconds: 3
        progressDeadlineSeconds: 600
        replicas: 1
        revisionHistoryLimit: 10
        selector:
          matchLabels:
            app: hello-nginx
        strategy:
          rollingUpdate:
            maxSurge: 25%
            maxUnavailable: 25%
          type: RollingUpdate
        template:
          metadata:
            creationTimestamp: null
            labels:
              app: hello-nginx
          spec:
            containers:
            - image: nginx:latest
              imagePullPolicy: Always
              name: hello-nginx
              ports:
              - containerPort: 80
                protocol: TCP
              resources: {}
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
            dnsPolicy: ClusterFirst
            restartPolicy: Always
            schedulerName: default-scheduler
            securityContext: {}
            terminationGracePeriodSeconds: 30
      status:
        availableReplicas: 1
        conditions:
        - message: Deployment has minimum availability.
          reason: MinimumReplicasAvailable
          status: "True"
          type: Available
        - message: ReplicaSet "hello-nginx-f6878fc9b" has successfully progressed.
          reason: NewReplicaSetAvailable
          status: "True"
          type: Progressing
        observedGeneration: 1
        readyReplicas: 1
        replicas: 1
        updatedReplicas: 1
      The printed yaml object contains more settings than what it was defined in the original manifest file.
      Some of the settings are the default values that Kubernets gives to the missing field in the manifest file.
      Some of the settings are runtime information set by Kubernets (node IP address, Pod IP address, container info, status, ...).

      The status field provides detailed information about the different transitional states of the Deployment.

    • To describe a Deployment (kubectl describe deployment).

      The command provides information about the Deployment (Replicas, Pods, ...) and its current state.
      It also provide the list of the events occurred while applying the Deployment.

      $ kubectl describe deployment hello-nginx
      Name:                   hello-nginx
      Namespace:              default
      Labels:                 <none>
      Annotations:            deployment.kubernetes.io/revision: 1
      Selector:               app=hello-nginx
      Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
      StrategyType:           RollingUpdate
      MinReadySeconds:        3
      RollingUpdateStrategy:  25% max unavailable, 25% max surge
      Pod Template:
        Labels:  app=hello-nginx
        Containers:
         hello-nginx:
          Image:        nginx:latest
          Port:         80/TCP
          Host Port:    0/TCP
          Environment:  <none>
          Mounts:       <none>
        Volumes:        <none>
      Conditions:
        Type           Status  Reason
        ----           ------  ------
        Available      True    MinimumReplicasAvailable
        Progressing    True    NewReplicaSetAvailable
      OldReplicaSets:  <none>
      NewReplicaSet:   hello-nginx-f6878fc9b (1/1 replicas created)
      Events:
        Type    Reason             Age    From                   Message
        ----    ------             ----   ----                   -------
        Normal  ScalingReplicaSet  3m36s  deployment-controller  Scaled up replica set hello-nginx-f6878fc9b to 1
  4. Performing Rolling Updates
    • Let's update the hello-nginx-deployment.yaml file and set the container port to 8080.
      Apply the changes:
      $ kubectl apply -f hello-nginx-deployment.yaml
      deployment.apps/hello-nginx configured

    • Monitor the changes:
      $ kubectl get pods --watch
      NAME                          READY   STATUS              RESTARTS   AGE
      hello-nginx-f6878fc9b-k8vbt   1/1     Running             0          3m43s
      hello-nginx-5c799dfb8-drwh2   0/1     ContainerCreating   0          3s
      hello-nginx-5c799dfb8-drwh2   1/1     Running             0          17s
      hello-nginx-f6878fc9b-k8vbt   1/1     Terminating         0          4m
      hello-nginx-f6878fc9b-k8vbt   0/1     Completed           0          4m7s

    • To monitor the rolling update progress:
      $ kubectl rollout status deployment hello-nginx
      aiting for deployment "hello-nginx" rollout to finish: 3 out of 5 new replicas have been updated...
      Waiting for deployment "hello-nginx" rollout to finish: 1 old replicas are pending termination...
      deployment "hello-nginx" successfully rolled out

    • To check the rollout history.
      $ kubectl rollout history deployment hello-nginx
      deployment.apps/hello-nginx
      REVISION CHANGE-CAUSE
      1        <none>
      2        <none>
      Revision 1 is referring to the initial deployment and the revision 2 is the current rolling update.

    • List Deployments:
      $ kubectl get deployments
      NAME          READY   UP-TO-DATE   AVAILABLE   AGE
      hello-nginx   1/1     1            1           5m
      As mentioned before, if we set replicas to 10, we should see that the value of the READY column is transiting between 8/10 to 12/10, and the value of the AVAILABLE column is transiting between 8 to 10 (see the fields spec.strategy.rollingUpdate.maxUnavailable and spec.strategy.rollingUpdate.maxSurge).

    • List Pods:
      $ kubectl get pods
      NAME                          READY   STATUS    RESTARTS   AGE
      hello-nginx-5c799dfb8-drwh2   1/1     Running   0          71s

    • List ReplicaSets:
      $ kubectl get replicasets
      NAME                    DESIRED   CURRENT   READY   AGE
      hello-nginx-5c799dfb8   1         1         1       88s
      hello-nginx-f6878fc9b   0         0         0       5m8s
      After applying the changes, there are now two ReplicaSets.

      As mentioned, when performing a rolling update, a new ReplicaSet is created and the old one is kept (but all its Pods are terminated).

      Note that the name of the ReplicaSet is composed of the deployment name plus a hash calculated from the spec.template field in the manifest YAML file.

    • Validate that the container port was changed (should be 8080):
      $ kubectl get pods -o jsonpath="{.items[*].spec.containers[*].ports[*].containerPort}"
      8080
      Note: to get the correct json path you can print the pod information in json format kubectl get pods -o json.
  5. Record the command that used to perform the update (--record)
    Previously when checked the rollout history, the CHANGE-CAUSE was showing <none>.

    You can use the --record flag to save the current kubectl command in the resource annotation. This can be useful to keep track of the commands that triggered to changes.

    Let's repeat the initial deployment and to apply the changes using the --record flag.

    First, let's delete the Deployment:
    $ kubectl delete -f hello-nginx-deployment.yaml
    deployment.apps "hello-nginx" deleted
    Apply the hello-nginx-deployment.yaml file:
    $ kubectl apply -f hello-nginx-deployment.yaml --record=true
    deployment.apps/hello-nginx created
    Change the container port to 8080 and apply the hello-nginx-deployment.yaml file:
    $ kubectl apply -f hello-nginx-deployment.yaml --record=true
    deployment.apps/hello-nginx configured
    If we check the rollout history, we should see now the command that was used to apply the Deployment:
    $ kubectl rollout history deployment hello-nginx
    deployment.apps/hello-nginx
    REVISION  CHANGE-CAUSE
    1         kubectl apply --filename=hello-nginx-deployment.yaml --record=true
    2         kubectl apply --filename=hello-nginx-deployment.yaml --record=true
  6. Performing Rollbacks
    Note that the rollback follow the same rolling update strategy behavior defined in the manifest YAML file see (spec.strategy.rollingUpdate.maxUnavailable spec.strategy.rollingUpdate.maxSurge).

    • Let's rollback the latest changes:
      $ kubectl rollout undo deployment hello-nginx
      deployment.apps/hello-nginx rolled back

    • Validate that the container port was changed (should be 8080):
      $ kubectl get pods -o jsonpath="{.items[*].spec.containers[*].ports[*].containerPort}"
      80

    • List ReplicaSets:
      $ kubectl get replicasets
      NAME                    DESIRED   CURRENT   READY   AGE
      hello-nginx-5c799dfb8   0         0         0       21m
      hello-nginx-f6878fc9b   1         1         1       25m
      Notice that the "old" ReplicaSet was not deleted. Which mean that you can do another rollback to get the container port set again to 8080!

      As mentioned before, if we set the replicas to 10, then when we run the command kubectl get deployment hello-nginx we should see that the value of the READY column is transiting between 8/10 to 12/10, and the value of the AVAILABLE column is transiting between 8 to 10 (see the fields spec.strategy.rollingUpdate.maxUnavailable and spec.strategy.rollingUpdate.maxSurge).
  7. Performing Rollbacks ("--to-revision")
    • To rollback to a specific revision your can use the --to-revision flag:
      $ kubectl rollout undo deployment hello-nginx --to-revision=1
      deployment.apps "hello-nginx" rolled back

    • Check the rolling update history:
      $ kubectl rollout history deployment hello-nginx
      deployment.apps/hello-nginx
      REVISION  CHANGE-CAUSE
      2         kubectl apply --filename=hello-nginx-deployment.yaml --record=true
      3         kubectl apply --filename=hello-nginx-deployment.yaml --record=true
  8. Delete Deployments
    To delete a Deployment using its manifest file:
    $ kubectl delete -f hello-nginx-deployment.yaml
    deployment.apps "hello-nginx" deleted
    To delete a Deployment using its name:
    $ kubectl delete deployment hello-nginx
    deployment.apps "hello-nginx" deleted
© 2025  mtitek