Introduction to Kubernetes (12): Deployment Upgrades and Rollbacks

2021年4月25日 18点热度 0人点赞 0条评论
内容目录

Table of Contents

  • Update
  • Rollout
  • Rollback
  • Scale Deployment
  • Direct Set
  • Pod Horizontal Autoscaling
  • Proportional Scaling
  • Pause Deployment Rollout

This article discusses the updating and rolling back of Pods, and is relatively short.

Update

You can check the version of the Nginx image at https://hub.docker.com/_/nginx. We can first select an older version.

First, we create a Deployment for Nginx with a replica count of 3.

kubectl create deployment nginx --image=nginx:1.19.0 --replicas=3

The first deployment is performed just as before, with no special commands required.

Note: We can also add the --record flag to write the executed command into the resource annotation kubernetes.io/change-cause. This is useful for future inspections, such as checking the commands executed for each Deployment revision.

Updating a Pod is actually very simple; we don't need to control the update of each Pod, nor do we need to worry about whether it will affect the business. Kubernetes will automatically manage these processes.

We just need to trigger the image version update event, and Kubernetes will automatically update the Pods for us.

kubectl set image deployment.apps/nginx nginx=nginx:1.20.0

The format is:

kubectl set image deployment.apps/{deployment_name} {image_name}:={image_name}:{version}

We can view detailed information of the Pods:

kubectl describe pods

Find the Events description:

... ...
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  66s   default-scheduler  Successfully assigned default/nginx-7b87485749-rlmcx to instance-2
  Normal  Pulled     66s   kubelet            Container image "nginx:1.20.0" already present on machine
  Normal  Created    66s   kubelet            Created container nginx
  Normal  Started    65s   kubelet            Started container nginx

To record version update information, we need to append -- --record after the kubectl create deployment and kubectl set image commands.

We can also update the Pod using the edit method.

Execute:

kubectl edit deployment nginx

An editing YAML interface will appear; change .spec.template.spec.containers[0].image from nginx:1.19.0 to nginx:1.20.0, and then save.

Rollout

Deployment rollout will only be triggered when the Deployment Pod template (i.e., .spec.template) changes, such as when the template's labels or container images are updated. Other updates (such as scaling the Deployment) will not trigger a rollout. The rollout of the Deployment can update the version of the Pods.

Its rollout differs from what we refer to as updating, because the update we refer to is a forward version, such as from 1.19.0 to 1.20.0, replacing the old version with the new version is termed updating. However, a Deployment rollout can be any version. It will automatically replace the version as per the image version we set, meaning it can replace 1.19.0 with 1.20.0. But we need not dwell on this.

When we update the Pod version, Kubernetes will automatically load balance; it will not delete all Pods and recreate new version Pods. Instead, it will gradually replace Pods in a robust manner.

We can check the rollout status of the Pod with the command:

kubectl rollout status deployment nginx

Output would be similar to:

Waiting for rollout to finish: 2 out of 3 new replicas have been updated...

Or

deployment "nginx-deployment" successfully rolled out

We can also check the number of updated Pods by getting the Deployment information:

kubectl get deployment
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           18m

In the UP-TO-DATE column, you can see the number of successfully updated Pods.

We can also check ReplicaSets and Pods:

kubectl get replicaset
kubectl get pods

Outputs similarly to:

NAME               DESIRED   CURRENT   READY   AGE
nginx-7b87485749   0         0         0       20m
nginx-85b45874d9   3         3         3       21m
NAME                     READY   STATUS    RESTARTS   AGE
nginx-85b45874d9-nrbg8   1/1     Running   0          12m
nginx-85b45874d9-qc7f2   1/1     Running   0          12m
nginx-85b45874d9-t48vw   1/1     Running   0          12m

We can see there are two ReplicaSets; all of nginx-7b87485749 have been updated to nginx-85b45874d9, so the count for the former is 0. We can also see in the Pods that all Pods are prefixed with nginx-85b45874d9. We can take screenshots of these key pieces of information for later reference.

If our project is live, and we update the software version, if we update all containers or Pods at once, our software may be unavailable for a while until all Pods finish updating. The Deployment ensures that during updates, only a certain number of Pods are closed; by default, it ensures that at least 75% of the required Pods are running, which means that the proportion of Pods being updated does not exceed 25%. However, a Deployment with only two or three Pods won't adhere to this percentage limitation.

If our Pod count is large enough, or if we quickly output the rollout status while updating the Deployment, we might find that the total number of new and old Pods does not necessarily add up to 3 because it will not kill old Pods until there are enough new Pods available. New Pods are not created until a sufficient number of old Pods are terminated. The Deployment ensures that at least two Pods are available while allowing a total of up to four Pods to be available.

The Deployment ensures that the created Pods will only exceed the expected number by a small margin. By default, it ensures that the number of Pods started can exceed the expected number by a maximum of 25% (maximum peak 25%). Therefore, during an automatic update of the Deployment, the observed number of Pods may be 4. Also, during a Deployment update, aside from changing the image version, we can also change the number of ReplicaSets.

Execute kubectl describe deployment nginx to view detailed information about the Deployment, and we can check the Event field.

file

However, we don't need to remember these principles or delve deeply into them; it suffices to know they exist and we can refer to the documentation when needed.

Rollback

By default, the rollout history of Deployments is retained in the system, allowing for easy rollback at any time.

We can check the rollout history of a Deployment:

kubectl rollout history deployment nginx
REVISION  CHANGE-CAUSE
2         <none>
3         <none>

Note: Our versions may not exactly match, as I conducted some tests for this article, which may result in more version counts than yours.

We can see revisions 2 and 3; now let’s check the information for revision 3:

kubectl rollout history deployment nginx --revision=3
deployment.apps/nginx with revision #3
Pod Template:
  Labels:	app=nginx
	pod-template-hash=85b45874d9
  Containers:
   nginx:
    Image:	nginx:1.20.0
    Port:	<none>
    Host Port:	<none>
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

Now that we have introduced several ways to view the rollout history of Deployments, let’s actually rollback the Deployment.

Rollback is done one version back:

kubectl rollout undo deployment nginx

Then executing kubectl rollout history deployment nginx will display different information.

At this point, the version count has increased, and we can also specify a rollback to a specific version.

kubectl rollout undo deployment nginx --to-revision=2

Here, it's worth mentioning --record. Earlier, we did not utilize this parameter while creating and updating the Deployment. Let's explore what this parameter does.

kubectl set image deployment.apps/nginx nginx=nginx:1.19.0
kubectl rollout history deployment nginx

Output:

REVISION  CHANGE-CAUSE
5         <none>
6         kubectl set image deployment.apps/nginx nginx=nginx:1.19.0 --record=true

This indicates that adding --record will log the command we used during our operations.

However, we currently have only two records. Despite having made multiple submissions, we observe only two records because we only used two versions, namely 1.19.0 and 1.20.0, hence there are only these two submission records. If we use more versions, we might see output like:

REVISION  CHANGE-CAUSE
7         kubectl set image deployment.apps/nginx nginx=nginx:1.19.0 --record=true
8         kubectl set image deployment.apps/nginx nginx=nginx:1.20.0 --record=true
9         kubectl set image deployment.apps/nginx nginx=nginx:latest --record=true

Scale Deployment

Direct Set

This can be easily done using the kubectl scale command:

kubectl scale deployment.v1.apps/nginx --replicas=10

You can also modify the YAML manually, using either kubectl apply -f to update or kubectl edit to do so.

Pod Horizontal Autoscaling

Kubernetes has a Pod horizontal autoscaler that can automatically scale the number of Pods in ReplicationController, Deployment, ReplicaSet, and StatefulSet based on CPU utilization.

In addition to CPU utilization, it can also scale based on other custom metrics provided by the application. Pod autoscaling does not apply to non-scalable objects such as DaemonSets.

Reference: https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/

Command:

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

This means the target CPU utilization is 80% (expected metric), and the replica count should be between 10 and 15. CPU is used as a dynamic metric for scaling Pods, calculated by the following formula:

Desired Number of Replicas = ceil[Current Number of Replicas * (Current Metric / Expected Metric)]

For algorithm details, visit: https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details

Proportional Scaling

Additionally, there is proportional scaling, allowing the Deployment to support running multiple versions of an application simultaneously.

When we set .spec.strategy.type==RollingUpdate, by adopting a rolling update method to update Pods, we can specify maxUnavailable and maxSurge to control the rolling update process. This was mentioned earlier; the Deployment defaults to ensuring at least 75% of Pods remain available throughout the update process, which can allow multiple versions of Pods to coexist before completion.

We won't go into detail here; please refer to: https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/#max-unavailable

By default, the YAML for the deployment is as follows:

  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate

We can change it to:

  strategy:
    rollingUpdate:
      maxSurge: 3
      maxUnavailable: 2
    type: RollingUpdate

Note: Execute kubectl edit deployment nginx to make changes directly.

We can observe this process:

root@instance-1:~# kubectl set image deployment nginx nginx=nginx:1.20.0
deployment.apps/nginx image updated
root@instance-1:~# kubectl get replicaset
NAME               DESIRED   CURRENT   READY   AGE
nginx-7b87485749   5         5         0       93m
nginx-85b45874d9   0         0         0       93m
nginx-bb957bbb5    8         8         8       35m

Previously, we set a maximum of two unavailable Pods (maxUnavailable=2), so initially, updating two Pods would lead to nginx-bb957bbb5 having 8 available statuses. Regarding maxSurge, it indicates the allowed overflow beyond the expected number of Pods, meaning the count of nginx-7b87485749 is not limited to 2 but may be 5, as up to 3 extra are permitted. Essentially, it allows for multiple new Pods to be created without waiting for the deletion of an old Pod for each new one, thereby allowing a smoother transition during updates.

Final status:

NAME               DESIRED   CURRENT   READY   AGE
nginx-7b87485749   10        10        10      99m
nginx-85b45874d9   0         0         0       99m
nginx-bb957bbb5    0         0         0       41m

Pause Deployment Rollout

Command:

kubectl rollout pause deployment nginx

The purpose is to pause when updating the Pod version of the Deployment.

Earlier, we set the maxSurge and maxUnavailable, which can slow down Pod creation.

Executing the following command can quickly halt the rollout process.

kubectl set image deployment nginx nginx=nginx:latest
kubectl rollout pause deployment nginx

Subsequently, if we execute kubectl get replicaset multiple times, we will find that the replica count remains unchanged.

NAME               DESIRED   CURRENT   READY   AGE
nginx-7b87485749   8         8         8       109m
nginx-85b45874d9   0         0         0       109m
nginx-bb957bbb5    5         5         5       52m

If we try again:

kubectl set image deployment nginx nginx=nginx:1.19.0

We will notice that while an update prompt appears, no actual changes occur. During the pause, executing new update operations is ineffective.

Executing kubectl rollout history deployment nginx will also not show our request for 1.19.0.

While paused, we can update some resource limits such as CPU:

kubectl set resources deployment nginx -c=nginx --limits=cpu=200m,memory=512Mi

To resume the Deployment:

kubectl rollout resume deployment nginx

痴者工良

高级程序员劝退师

文章评论