你个小奴仆报上名来 發表於 2021-4-25 11:33:00

浅入Kubernetes(12):Deployment 的升级、回滚

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>更新</li><li>上线</li><li>会滚</li><li>缩放 Deployment<ul><li>直接设置</li><li>Pod 水平自动缩放</li><li>比例缩放</li></ul></li><li>暂停 Deployment 上线</li></ul></div><p></p>
<p>本篇内容讨论 Pod 的更新和回滚,内容不多。</p>
<h3 id="更新">更新</h3>
<p>打开 https://hub.docker.com/_/nginx 可以查询 nginx 的镜像版本,我们可以先选择一个旧一点的版本。</p>
<p>首先,我们创建一个 Nginx 的 Deployment,副本数量为 3。</p>
<pre><code class="language-shell">kubectl create deployment nginx --image=nginx:1.19.0 --replicas=3
</code></pre>
<p>首次部署的时候,跟之前的操作一致,不需要什么特殊的命令。</p>
<blockquote>
<p><strong>注:</strong> 我们也可以加上 <code>--record</code> 标志将所执行的命令写入资源注解 <code>kubernetes.io/change-cause</code> 中。 这对于以后的检查是有用的。例如,要查看针对每个 Deployment 修订版本所执行过的命令。</p>
</blockquote>
<p>其实更新 pod 是非常简单的,我们不需要控制每个 pod 的更新,也不需要担心会不会对业务产生影响,k8s 会自动控制这些过程。</p>
<p>我们只需要触发镜像版本更新事件,k8s 会自动为我们更新 pod 的。</p>
<pre><code class="language-shell">kubectl set image deployment.apps/nginx nginx=nginx:1.20.0
</code></pre>
<p>格式为:</p>
<pre><code class="language-shell">kubectl set image deployment.apps/{deployment名称} {镜像名称}:={镜像名称}:{版本}
</code></pre>
<p>我们可以查看 pod 的详细信息:</p>
<pre><code class="language-shell">kubectl describe pods
</code></pre>
<p>找到 Events 描述:</p>
<pre><code>... ...
Events:
Type    Reason   Age   From               Message
----    ------   --------               -------
NormalScheduled66s   default-schedulerSuccessfully assigned default/nginx-7b87485749-rlmcx to instance-2
NormalPulled   66s   kubelet            Container image "nginx:1.20.0" already present on machine
NormalCreated    66s   kubelet            Created container nginx
NormalStarted    65s   kubelet            Started container nginx
</code></pre>
<p>为了记录版本更新信息,我们需要在 <code>kubectl create deployment</code>、<code>kubectl set image</code> 命令后面加上 <code>-- --record</code>。</p>
<p>我们还可以通过 edit 方式更新 pod。</p>
<p>执行:</p>
<pre><code class="language-shell">kubectl edit deployment nginx
</code></pre>
<p>然后会弹出编辑 yaml 的界面,将 <code>.spec.template.spec.containers.image</code> 从 <code>nginx:1.19.0</code> 更改至 <code>nginx:1.20.0</code>,然后保存即可。</p>
<h3 id="上线">上线</h3>
<p>仅当 Deployment Pod 模板(即 <code>.spec.template</code>)发生改变时,例如模板的标签或容器镜像被更新, 才会触发 Deployment 上线。 其他更新(如对 Deployment 执行扩缩容的操作)不会触发上线动作。Deployment 的上线动作可以为我们更新 pod 的版本。</p>
<p>它的上线跟我们所说的更新,有些区别。因为我们所说的更新,版本是往后的,例如 1.19.0 -&gt; 1.20.0 ,用新版本替换旧版本才叫更新。但是 Deployment 的上线,则是任意版本。它会根据我们设置的镜像版本自动替换,可以用 1.19.0 替换 1.20.0。不过这里我们不需要纠结这些。</p>
<p>当我们更新 pod 版本时,k8s 会自动负载均衡,而不是把所有 pod 删除,再重新创建新版本 pod,它会以稳健的方式逐渐替换 pod。</p>
<p>我们可以通过命令,查看 pod 的上线状态:</p>
<pre><code class="language-shell">kubectl rollout status deployment nginx
</code></pre>
<p>输出类似于:</p>
<pre><code>Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
</code></pre>
<p>或者</p>
<pre><code>deployment "nginx-deployment" successfully rolled out
</code></pre>
<p>我们也可以通过获取 deployment 信息时,查看已更新的 pod 数量:</p>
<pre><code class="language-shell">kubectl get deployment
</code></pre>
<pre><code>NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3   3            3         18m
</code></pre>
<p>UP-TO-DATE 字段可以看到成功更新的 pod 数量。</p>
<p>还可以查看 ReplicaSet 和 pod:</p>
<pre><code class="language-shell">kubectl get replicaset
kubectl get pods
</code></pre>
<p>输出类型于:</p>
<pre><code>NAME               DESIRED   CURRENT   READY   AGE
nginx-7b87485749   0         0         0       20m
nginx-85b45874d9   3         3         3       21m
</code></pre>
<pre><code>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
</code></pre>
<p>可以看到有两个 ReplicaSet,nginx-7b87485749 已经被全部更新到 nginx-85b45874d9 了,所以前者的数量为 0,我们也可以看到 pod 中,所有 pod 都是以 <code>nginx-85b45874d9</code> 作为前缀的。这几个关键信息,我们可以截图,后面再次对照。</p>
<p>如果我们的项目上线了,我们更新软件版本,如果一次性更新所有容器或者 pod,那么我们的软件会有一段时间处于不可用状态,直到所有 pod 都完成更新。Deployment 可确保在更新时仅关闭一定数量的 Pod,默认情况下,它确保至少所需 Pods 75% 处于运行状态,也就是说正在被更新的 pod 比例不超过 25%。当然,只有两三个 pod 的 Deployment 不会按照这个比例限定。</p>
<p>如果我们的 pod 数量足够大,或者在更新 Deployment 时迅速输出上线状态,可以看到新旧的 pod 数量加起来不一定就是 3 个,因为它不会杀死老 Pods,直到有足够的数量新的 Pods 已经出现。 在足够数量的旧 Pods 被杀死前并没有创建新 Pods。它确保至少 2 个 Pod 可用,同时 最多总共 4 个 Pod 可用。</p>
<p>Deployment 确保仅所创建 Pod 数量只可能比期望 Pods 数高一点点。 默认情况下,它可确保启动的 Pod 个数比期望个数最多多出 25%(最大峰值 25%)所以在自动更新 Deployment 时,观察到的 pod 可能为 4个。另外,在 Deployment 更新时,除了可以更改镜像的版本,也可以更改 ReplicaSet 的数量。</p>
<p>执行 <code>kubectl describe deployment nginx</code> 查看 Deployment 详细信息,我们查看 Event 字段。</p>
<p><img src="https://img2020.cnblogs.com/blog/1315495/202104/1315495-20210425113234550-2030845471.png" alt="" loading="lazy"></p>
<p>但是这些原理等知识我们都不需要记,也不需要深入,我们记得有这回事就行,有需要的时候也可以直接查看文档的。</p>
<h3 id="会滚">会滚</h3>
<p>默认情况下, Deployment 的上线记录都会保留在系统中,以便可以随时回滚。</p>
<p>我们查看 Deployment 的上线历史记录:</p>
<pre><code class="language-shell">kubectl rollout history deployment nginx
</code></pre>
<pre><code>REVISIONCHANGE-CAUSE
2         &lt;none&gt;
3         &lt;none&gt;
</code></pre>
<p>注:我们的版本不一定一样,因为我为了这这篇文章,进行了一些测试,可能版本数量比你的多。</p>
<p>可以看到有 2,3 两个版本,我们查看 版本3 的信息:</p>
<pre><code class="language-shell">kubectl rollout history deployment nginx --revision=3
</code></pre>
<pre><code class="language-yaml">deployment.apps/nginx with revision #3
Pod Template:
Labels:        app=nginx
        pod-template-hash=85b45874d9
Containers:
   nginx:
    Image:        nginx:1.20.0
    Port:        &lt;none&gt;
    Host Port:        &lt;none&gt;
    Environment:        &lt;none&gt;
    Mounts:        &lt;none&gt;
Volumes:        &lt;none&gt;
</code></pre>
<p>目前介绍了几个查看 Deployment 上线的历史记录,下面我真正来回滚 Deployment。</p>
<p>回滚是一个版本:</p>
<pre><code class="language-shell">kubectl rollout undo deployment nginx
</code></pre>
<p>再执行 <code>kubectl rollout history deployment nginx</code> 会看到不一样的信息。</p>
<p>此时版本数量多了,我们还可以指定回滚到特点的版本。</p>
<pre><code class="language-shell">kubectl rollout undo deployment nginx --to-revision=2
</code></pre>
<p>这里提一下 <code>--record</code>,在前面,我们创建和更新 Deployment 时,都没有使用到这个参数。我们可以试试这个参数的作用。</p>
<pre><code class="language-shell">kubectl set image deployment.apps/nginx nginx=nginx:1.19.0
</code></pre>
<pre><code class="language-shell">kubectl rollout history deployment nginx
</code></pre>
<p>输出:</p>
<pre><code>REVISIONCHANGE-CAUSE
5         &lt;none&gt;
6         kubectl set image deployment.apps/nginx nginx=nginx:1.19.0 --record=true
</code></pre>
<p>说明加上了 <code>--record</code>,会把我们操作时的命令记录下来。</p>
<p>但是我们这里目前来说,只有两个记录,我们明明提交了多次,但是这里查询的只有两条记录,这时因为我们操作的时候,只用到了 1.19.0、1.20.0 两个版本,所以也就只有这两个版本的提交记录。多用几个版本,输出结果:</p>
<pre><code>REVISIONCHANGE-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

</code></pre>
<h3 id="缩放-deployment">缩放 Deployment</h3>
<h4 id="直接设置">直接设置</h4>
<p>很简单,使用 <code>kubectl scale</code> 命令直接设置:</p>
<pre><code class="language-shell">kubectl scale deployment.v1.apps/nginx --replicas=10
</code></pre>
<p>修改 yaml 的方式也行,一是修改 yaml文件,使用 <code>kubectl apply -f</code> 的方式更新,或者使用 <code>kube edit</code> 的方式。</p>
<h4 id="pod-水平自动缩放">Pod 水平自动缩放</h4>
<p>K8S有个 Pod 水平自动扩缩(Horizontal Pod Autoscaler) 可以基于 CPU 利用率自动扩缩 ReplicationController、Deployment、ReplicaSet 和 StatefulSet 中的 Pod 数量。</p>
<p>除了 CPU 利用率,也可以基于其他应程序提供的自定义度量指标 来执行自动扩缩。 Pod 自动扩缩不适用于无法扩缩的对象,比如 DaemonSet。</p>
<p>参考资料:https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/</p>
<p>命令:</p>
<pre><code class="language-shell">kubectl autoscale deployment nginx --min=10 --max=15 --cpu-percent=80
</code></pre>
<p>表示目标 CPU 使用率为 <code>80%</code>(期望指标),副本数量配置应该为 10 到 15 之间,CPU 是动态缩放 pod 的指标,会根据具体的 CPU 使用率计算副本数量,其计算公式如下。</p>
<pre><code>期望副本数 = ceil[当前副本数 * (当前指标 / 期望指标)]
</code></pre>
<p>算法细节请查看:https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details</p>
<h4 id="比例缩放">比例缩放</h4>
<p>另外还有个比例缩放,允许 Deployment 支持同时运行应用程序的多个版本。</p>
<p>当我们设置<code>.spec.strategy.type==RollingUpdate</code>时,采取 滚动更新的方式更新 Pods,就可以指定 <code>maxUnavailable</code> 和 <code>maxSurge</code> 来控制滚动更新 过程。这个我们之前提到过,就是 Deployment 默认会保证一直有 75% 的 pod处于可用状态,在完成更新前可能有多个版本的 pod 共存。</p>
<p>这里不细说,请参考:https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/#max-unavailable</p>
<p>默认的话,deployment 的 yaml 是这样的:</p>
<pre><code class="language-yaml">strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
</code></pre>
<p>我们可以改成:</p>
<pre><code class="language-yaml">strategy:
    rollingUpdate:
      maxSurge: 3
      maxUnavailable: 2
    type: RollingUpdate
</code></pre>
<p>注:执行 <code>kubectl edit deployment nginx</code> 直接改。</p>
<p>我们可以观察到这个过程:</p>
<pre><code class="language-shell">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
</code></pre>
<p>前面我们设置了最大存在两个不可用 pod(maxUnavailable=2),所以一开始会更新两个 pod,所以 <code>nginx-bb957bbb5</code>8个处于可用状态。而 maxSurge 表示允许超出的期望 pod 数量,所以<code>nginx-7b87485749</code> 的数量不是 2 个,而是 5个,因为允许超出 3 个。其实意思就是不需要等旧的 pod 删除 一个,新的 pod 创建一个。可以多创建几个 pod,再按照慢一些的速度删除旧的 pod,最终完成版本更新。</p>
<p>最终:</p>
<pre><code>NAME               DESIRED   CURRENT   READY   AGE
nginx-7b87485749   10      10      10      99m
nginx-85b45874d9   0         0         0       99m
nginx-bb957bbb5    0         0         0       41m

</code></pre>
<h3 id="暂停-deployment-上线">暂停 Deployment 上线</h3>
<p>命令:</p>
<pre><code class="language-shell">kubectl rollout pause deployment nginx
</code></pre>
<p>用途就是我们更新 Deployment 的 pod 版本时,可以暂停。</p>
<p>前面我们已经设置了这个 maxSurge 和 maxUnavailable,可以让 pod 的创建慢一些。</p>
<p>执行下面的命令可以快速卡住上线过程。</p>
<pre><code class="language-shell">kubectl set image deployment nginx nginx=nginx:latest
kubectl rollout pause deployment nginx
</code></pre>
<p>之后,多次执行 <code>kubectl get replicaset</code> ,会发现副本数量不会变化。</p>
<pre><code>NAME               DESIRED   CURRENT   READY   AGE
nginx-7b87485749   8         8         8       109m
nginx-85b45874d9   0         0         0       109m
nginx-bb957bbb5    5         5         5       52m
</code></pre>
<p>如果我们再次执行:</p>
<pre><code class="language-shell">kubectl set image deployment nginx nginx=nginx:1.19.0
</code></pre>
<p>会发现虽然提示更新了,但是实际上没有变化。在暂停中,执行新的更新操作是无效的。</p>
<p>执行 <code>kubectl rollout history deployment nginx</code> 也查不到我们提交的 <code>1.19.0</code> 的请求。</p>
<p>暂停的时候,我们可以更新一些限制的 CPU 和 资源:</p>
<pre><code class="language-shell">kubectl set resources deployment nginx -c=nginx --limits=cpu=200m,memory=512Mi
</code></pre>
<p>恢复 Deployment:</p>
<pre><code>kubectl rollout resume deployment nginx
</code></pre>
<p>本文已入驻腾讯云社区,我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=o61z17zlxbqx</p>


</div>
<div id="MySignature" role="contentinfo">
    痴者工良(https://whuanle.cn)<br><br>
来源:https://www.cnblogs.com/whuanle/p/14699661.html
頁: [1]
查看完整版本: 浅入Kubernetes(12):Deployment 的升级、回滚