Exercise 4: Deployments

In this Exercise, you will create a Deployment and rollout an application update. Deployments provide a consistent mechanism to upgrade an application to a new version, while keeping the downtime to a minimum. Note that internally, Deployments use ReplicaSets for managing pods. However, you never work directly with ReplicaSets since Deployments abstract out that interaction.

Task 1 - Create A New Deployment

  1. Create a Deployment manifest where the pod template contains an nginx container with a tag 1.0. The 1.0 represents the version of this container and hence of the application running inside it.

    $ngDepYaml = @"
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ng-dep
    spec:
      replicas: 2
      selector:
        matchLabels:
          target: dev
      template:
        metadata:
          name: ng-pod
          labels:
            target: dev
        spec:
          nodeSelector:
            kubernetes.io/os: linux
          containers:
          - name: nginx
            image: k8sonazureworkshoppublic.azurecr.io/k8slab/nginx:1.0
            ports:
            - containerPort: 80
              protocol: TCP
    "@
    
    # Create the Deployment
    $ngDepYaml | kubectl apply -f -
    cat << EOF | kubectl apply -f -
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ng-dep
    spec:
      replicas: 2
      selector:
        matchLabels:
          target: dev
      template:
        metadata:
          name: ng-pod
          labels:
            target: dev
        spec:
          nodeSelector:
            kubernetes.io/os: linux
          containers:
          - name: nginx
            image: k8sonazureworkshoppublic.azurecr.io/k8slab/nginx:1.0
            ports:
            - containerPort: 80
              protocol: TCP
    EOF
  2. Create a Service to access the pods of the deployment:

    $ngSvcYaml = @"
    apiVersion: v1
    kind: Service
    metadata:
      name: ng-svc
    spec:
      ports:
        - port: 80
      selector:
        target: dev
      type: LoadBalancer
    "@
    
    # Create the Service
    $ngSvcYaml | kubectl apply -f -
    cat << EOF | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: ng-svc
    spec:
      ports:
        - port: 80
      selector:
        target: dev
      type: LoadBalancer
    EOF
  3. Run the following command to see the Pods, ReplicaSets, Deployments and Services that were created.

    kubectl get all --show-labels
    kubectl get all --show-labels

    Get All Get All

    Tip

    You can also chain resource types together with a comma to create a customised list of resources to view, e.g. kubectl get pods,replicasets,deployments,services --show-labels or kubectl get po,rs,deploy,svc --show-labels

Task 2 - Access Version 1.0 Of Application

  1. Wait about 3-4 minutes to allow Azure to create a Public IP address for the service. Check to see if an address has been assigned by getting the list of services.

    kubectl get svc
    kubectl get svc

    Services Services

    Tip

    If the EXTERNAL-IP shows as <pending>, it means the underlying Azure load balancer resource is still being provisioned. Give it a couple more minutes and try again.

  2. When you see an EXTERNAL-IP assigned, open a browser with that address, e.g.: http://20.81.24.216

    IP IP

Task 3 - Update The Deployment To Version 2.0

You are now going to update the Deployment to use version 2.0 of the container instead of 1.0. This can be done in one of two ways. One approach is to use imperative syntax, which is faster and is often used during the development/testing stage of an application. The alternate method is to update the YAML file and then to reapply it to the cluster - this is known as the declarative approach.

We will demonstrate the imperative method over the next few steps.

  1. To start rolling out the new update, change the container image tag from 1.0 to 2.0 by running this command:

    kubectl set image deployment ng-dep nginx=k8sonazureworkshoppublic.azurecr.io/k8slab/nginx:2.0
    kubectl set image deployment ng-dep nginx=k8sonazureworkshoppublic.azurecr.io/k8slab/nginx:2.0
  2. In the command above, ng-dep is the name of Deployment and nginx is the name of the container within the pod template. The change will force the Deployment to create a new ReplicaSet with an image tagged 2.0.

  3. List all the pods and notice that old pods are terminating and that new pods have been created.

    kubectl get pods
    kubectl get pods

    Run kubectl get pods a few more times to watch new pods get created and old pods deleted. Notice the values in the AGE column change each time you run the command.

  4. Run the follwing command to review the Deployment definition with the updated value of container image:

    kubectl describe deployment ng-dep
    kubectl describe deployment ng-dep

    Describe Describe

    Note

    Notice the Image: section (under Containers:) shows the value of container image as 2.0.

  5. Run the command to view the Pods, ReplicaSets and Deployments again.

    kubectl get all
    kubectl get all

    Get All Get All

    Note

    Notice that the old replica set still exists, even though it has 0 DESIRED pods.

  6. Run the describe command on the old ReplicaSet.

    kubectl describe rs <oldReplicaSetName>
    kubectl describe rs <oldReplicaSetName>

    Describe RS Describe RS

    Note

    Notice that the old definition still has the previous version number. This is maintained so you can roll back the change to that version if you wish.

  7. Access the 2.0 version of application by refreshing the browser at the same address as above.

    Browser Browser

Task 4 - Rollback The Deployment

The purpose of maintaining the previous ReplicaSet is to be able to rollback changes to any previous version.

  1. Review the deployment history.

    kubectl rollout history deploy/ng-dep
    kubectl rollout history deploy/ng-dep
  2. Rollback the Deployment to the previous version.

    kubectl rollout undo deploy/ng-dep
    kubectl rollout undo deploy/ng-dep
  3. Wait a few seconds and refresh the browser again.

    Browser Browser

    Note

    Notice the site is back to the previous version.

Knowledge Check

Can you update the Deployment using the declarative approach, where you update the YAML file and update the deployment?

Hint

Go back to Task 3 and check what we changed to update the app from v1.0 to v2.0. How would you make that change in the YAML file?

Solution
$ngDepYaml = @"
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ng-dep
spec:
  replicas: 2
  selector:
    matchLabels:
      target: dev
  template:
    metadata:
      name: ng-pod
      labels:
        target: dev
    spec:
      nodeSelector:
        kubernetes.io/os: linux
      containers:
      - name: nginx
        image: k8sonazureworkshoppublic.azurecr.io/k8slab/nginx:2.0
        ports:
        - containerPort: 80
          protocol: TCP
"@

# Create the Deployment
$ngDepYaml | kubectl apply -f -
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ng-dep
spec:
  replicas: 2
  selector:
    matchLabels:
      target: dev
  template:
    metadata:
      name: ng-pod
      labels:
        target: dev
    spec:
      nodeSelector:
        kubernetes.io/os: linux
      containers:
      - name: nginx
        image: k8sonazureworkshoppublic.azurecr.io/k8slab/nginx:2.0
        ports:
        - containerPort: 80
          protocol: TCP
EOF

Once you’re happy that you understand what’s going on here, you can move onto the next task.

Task 5 - Delete The Deployment And Service

  1. Delete the Deployment and Service.

    kubectl delete deployment ng-dep
    kubectl delete service ng-svc
    kubectl delete deployment ng-dep
    kubectl delete service ng-svc
    Note

    It may take a few minutes to delete the service because has to delete the Public IP resource in Azure.