Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

这篇具有很好参考价值的文章主要介绍了Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

滚动更新,使用 kubectl rollout 实现用户无感知的应用升级和降级。

1. 定义应用版本

Kubernetes 里,版本更新使用的不是 API 对象,而是两个命令:kubectl applykubectl rollout,当然它们也要搭配部署应用所需要的 DeploymentDaemonSetYAML 文件。

我们常常会简单地认为“版本”就是应用程序的“版本号”,或者是容器镜像的“标签”,但不要忘了,在 Kubernetes 里应用都是以 Pod 的形式运行的,而 Pod 通常又会被 Deployment 等对象来管理,所以应用的“版本更新”实际上更新的是整个 Pod

Pod 又是由什么来决定的呢?

Pod 是由 YAML 描述文件来确定的,更准确地说,是 Deployment 等对象里的字段 template

所以,在 Kubernetes 里应用的版本变化就是 templatePod 的变化,哪怕 template 里只变动了一个字段,那也会形成一个新的版本,也算是版本变化。

template 里的内容太多了,拿这么长的字符串来当做“版本号”不太现实,所以 Kubernetes 就使用了“摘要”功能,用摘要算法计算 templateHash 值作为“版本号”,虽然不太方便识别,但是很实用。
Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

Pod 名字里的那串随机数“6796……”就是 Pod 模板的 Hash 值,也就是 Pod 的“版本号”。如果你变动了 Pod YAML 描述,比如把镜像改成 nginx:stable-alpine,或者把容器名字改成 nginx-test,都会生成一个新的应用版本,kubectl apply 后就会重新创建 Pod

image.png

你可以看到,Pod 名字里的 Hash 值变成了“7c6c……”,这就表示 Pod 的版本更新了。

2. 实现应用更新

为了更仔细地研究 Kubernetes 的应用更新过程,让我们来略微改造一下 Nginx Deployment 对象,看看 Kubernetes 到底是怎么实现版本更新的。

首先修改 ConfigMap,让它输出 Nginx 的版本号,方便我们用 curl 查看版本:

# ngx-conf.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: ngx-conf

data:
  default.conf: |
    server {
      listen 80;
      location / {
        default_type text/plain;
        return 200
          'ver : $nginx_version\nsrv : $server_addr:$server_port\nhost: $hostname\n';
      }
    }

然后我们修改 Pod 镜像,明确地指定版本号是 1.21-alpine,实例数设置为 4 个:

# ngx-v1.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ngx-dep

spec:
  replicas: 4
  selector:
    matchLabels:
      app: ngx-dep

  template:
    metadata:
      labels:
        app: ngx-dep
    spec:
      volumes:
      - name: ngx-conf-vol
        configMap:
          name: ngx-conf

      containers:
      - image: nginx:1.21-alpine
        name: nginx
        ports:
        - containerPort: 80

        volumeMounts:
        - mountPath: /etc/nginx/conf.d
          name: ngx-conf-vol


把它命名为 ngx-v1.yml,然后执行命令 kubectl apply 部署这个应用:

kubectl apply -f ngx-conf.yml
kubectl apply -f ngx-v1.yml
# ngx-svc.yml
apiVersion: v1
kind: Service
metadata:
  name: ngx-svc
  
spec:
  selector:
    app: ngx-dep
    
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP

我们还可以为它创建 Service 对象,再用 kubectl port-forward 转发请求来查看状态:

kubectl apply -f ngx-svc.yml

kubectl port-forward svc/ngx-svc 8080:80 &
curl 127.1:8080

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

curl 命令的输出中可以看到,现在应用的版本是 1.21.6。现在,让我们编写一个新版本对象 ngx-v2.yml,把镜像升级到 nginx:1.22-alpine,其他的都不变。

因为 Kubernetes 的动作太快了,为了能够观察到应用更新的过程,我们还需要添加一个字段 minReadySeconds,让 Kubernetes 在更新过程中等待一点时间,确认 Pod 没问题才继续其余 Pod 的创建工作。

要提醒你注意的是,minReadySeconds 这个字段不属于 Pod 模板,所以它不会影响 Pod 版本:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: ngx-dep

spec:
  minReadySeconds: 15      # 确认Pod就绪的等待时间 
  replicas: 4
  ... ...
      containers:
      - image: nginx:1.22-alpine
  ... ...

现在我们执行命令 kubectl apply 来更新应用,因为改动了镜像名,Pod 模板变了,就会触发“版本更新”,然后用一个新命令:kubectl rollout status,来查看应用更新的状态:


kubectl apply -f ngx-v2.yml
kubectl rollout status deployment ngx-dep

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

更新完成后,你再执行 kubectl get pod,就会看到 Pod 已经全部替换成了新版本“d575……”,用 curl 访问 Nginx,输出信息也变成了“1.22.0”:

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

仔细查看 kubectl rollout status 的输出信息,你可以发现,Kubernetes 不是把旧 Pod 全部销毁再一次性创建出新 Pod,而是在逐个地创建新 Pod,同时也在销毁旧 Pod,保证系统里始终有足够数量的 Pod 在运行,不会有“空窗期”中断服务。

Pod 数量增加的过程有点像是“滚雪球”,从零开始,越滚越大,所以这就是所谓的“滚动更新”(rolling update)。

使用命令 kubectl describe 可以更清楚地看到 Pod 的变化情况:


kubectl describe deploy ngx-dep

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

1、一开始的时候 V1 Pod(即 ngx-dep-54b865d75)的数量是 4;
2、当“滚动更新”开始的时候,Kubernetes 创建 1 个 V2 Pod(即 ngx-dep-d575d5776),并且把 V1 Pod 数量减少到 3;
3、接着再增加 V2 Pod 的数量到 2,同时 V1 Pod 的数量变成了 1;
4、最后 V2 Pod 的数量达到预期值 4,V1 Pod 的数量变成了 0,整个更新过程就结束了。

看到这里你是不是有点明白了呢,其实“滚动更新”就是由 Deployment 控制的两个同步进行的“应用伸缩”操作,老版本缩容到 0,同时新版本扩容到指定值,是一个“此消彼长”的过程。

这个滚动更新的过程我画了一张图,你可以参考它来进一步体会:
image.png

3. 管理应用更新

Kubernetes 的“滚动更新”功能确实非常方便,不需要任何人工干预就能简单地把应用升级到新版本,也不会中断服务,不过如果更新过程中发生了错误或者更新后发现有 Bug 该怎么办呢?

要解决这两个问题,我们还是要用 kubectl rollout 命令。

在应用更新的过程中,你可以随时使用 kubectl rollout pause 来暂停更新,检查、修改 Pod,或者测试验证,如果确认没问题,再用 kubectl rollout resume 来继续更新。

这两个命令比较简单,我就不多做介绍了,要注意的是它们只支持 Deployment,不能用在 DaemonSetStatefulSet 上(最新的 1.24 支持了 StatefulSet 的滚动更新)。

对于更新后出现的问题,Kubernetes 为我们提供了“后悔药”,也就是更新历史,你可以查看之前的每次更新记录,并且回退到任何位置,和我们开发常用的 Git 等版本控制软件非常类似。

查看更新历史使用的命令是 kubectl rollout history


kubectl rollout history deploy ngx-dep

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

它会输出一个版本列表,因为我们创建 Nginx Deployment 是一个版本,更新又是一个版本,所以这里就会有两条历史记录。

kubectl rollout history 的列表输出的有用信息太少,你可以在命令后加上参数 --revision 来查看每个版本的详细信息,包括标签、镜像名、环境变量、存储卷等等,通过这些就可以大致了解每次都变动了哪些关键字段:


kubectl rollout history deploy --revision=2

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

假设我们认为刚刚更新的 nginx:1.22-alpine 不好,想要回退到上一个版本,就可以使用命令 kubectl rollout undo,也可以加上参数 --to-revision 回退到任意一个历史版本:


kubectl rollout undo deploy ngx-dep

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

kubectl rollout undo 的操作过程其实和 kubectl apply 是一样的,执行的仍然是“滚动更新”,只不过使用的是旧版本 Pod 模板,把新版本 Pod 数量收缩到 0,同时把老版本 Pod 扩展到指定值。

这个 V2 到 V1 的“版本降级”的过程我同样画了一张图,它和从 V1 到 V2 的“版本升级”过程是完全一样的,不同的只是版本号的变化方向:
image.png

4. 添加更新描述

有没有觉得 kubectl rollout history 的版本列表好像有点太简单了呢?只有一个版本更新序号,而另一列 CHANGE-CAUSE 为什么总是显示成 呢?能不能像 Git 一样,每次更新也加上说明信息呢?

这当然是可以的,做法也很简单,我们只需要在 Deploymentmetadata 里加上一个新的字段 annotations

annotations 字段的含义是“注解”“注释”,形式上和 labels 一样,都是 Key-Value,也都是给 API 对象附加一些额外的信息,但是用途上区别很大。

  • annotations 添加的信息一般是给 Kubernetes 内部的各种对象使用的,有点像是“扩展属性”;
  • labels 主要面对的是 Kubernetes 外部的用户,用来筛选、过滤对象的。

如果用一个简单的比喻来说呢,annotations 就是包装盒里的产品说明书,而 labels 是包装盒外的标签贴纸。

借助 annotationsKubernetes 既不破坏对象的结构,也不用新增字段,就能够给 API 对象添加任意的附加信息,这就是面向对象设计中典型的 OCP“开闭原则”,让对象更具扩展性和灵活性。

annotations 里的值可以任意写,Kubernetes 会自动忽略不理解的 Key-Value,但要编写更新说明就需要使用特定的字段 kubernetes.io/change-cause

下面来操作一下,我们创建 3 个版本的 Nginx 应用,同时添加更新说明:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: ngx-dep
  annotations:
    kubernetes.io/change-cause: v1, ngx=1.21
... ...

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ngx-dep
  annotations:
    kubernetes.io/change-cause: update to v2, ngx=1.22
... ...

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ngx-dep
  annotations:
    kubernetes.io/change-cause: update to v3, change name
... ...

需要注意 YAML 里的 metadata 部分,使用 annotations.kubernetes.io/change-cause 描述了版本更新的情况,相比 kubectl rollout history --revision 的罗列大量信息更容易理解。

依次使用 kubectl apply 创建并更新对象之后,中间稍微间隔点时间,确保 Pod 都已建立,我们再用 kubectl rollout history 来看一下更新历史:

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

5. 总结

滚动更新,它会自动缩放新旧版本的 Pod 数量,能够在用户无感知的情况下实现服务升级或降级,让原本复杂棘手的运维工作变得简单又轻松。

  1. Kubernetes 里应用的版本不仅仅是容器镜像,而是整个 Pod 模板,为了便于处理使用了摘要算法,计算模板的 Hash 值作为版本号。
  2. Kubernetes 更新应用采用的是滚动更新策略,减少旧版本 Pod的同时增加新版本 Pod,保证在更新过程中服务始终可用。
  3. 管理应用更新使用的命令是 kubectl rollout,子命令有 statushistoryundo 等。
  4. Kubernetes 会记录应用的更新历史,可以使用 history --revision 查看每个版本的详细信息,也可以在每次更新时添加注解 kubernetes.io/change-cause

另外,在 Deployment 里还有其他一些字段可以对滚动更新的过程做更细致的控制,它们都在 spec.strategy.rollingUpdate 里,比如 maxSurgemaxUnavailable 等字段,分别控制最多新增 Pod 数和最多不可用 Pod 数,一般用默认值就足够了。

Deployment 在版本更新的时候实际控制的是 ReplicaSet 对象,创建不同版本的 ReplicaSet,再由 ReplicaSet 来伸缩 Pod 数量。

除了使用 kubectl apply 来触发应用更新,你也可以使用其它任何能够修改 API 对象的方式,比如 kubectl editkubectl patchkubectl set image 等命令 。

kubenetes 不会记录所有的更新历史,那样太浪费资源,默认它只会保留最近的 10 次操作,但是这个值可以使用字段 revisionHistoryLimit 调整。

6. 问答

  1. 今天学的 Kubernetes 的“滚动更新”,与我们常说的“灰度发布”有什么相同点和不同点?

“滚动发布”是能力,“灰度发布”是功能,k8s 基于“滚动发布”的能力,可以实现 pod 的‘水平扩展/收缩’,从而能够提供类似于“灰度发布”、“金丝雀发布”这种功能。

灰度发布应该是多个应用版本共存,按一定比例分配;

滚动更新是一个逐步使用“新”版本替换“旧”版本的发布方式;灰度发布又称金丝雀发布,在灰度期间,“新”、“旧”两个版本会同时存在,这种发布方式可以用于实现A/B测试

  1. 直接部署旧版本的 YAML 也可以实现版本回退,kubectl rollout undo 命令的好处是什么?

其实讨论这个问题前,我们要先了解下 k8s 的控制器模型,另外还要引入一个概念就是 ReplicaSet ,什么意思呢,其实Deployment 并不是直接控制 PodPod 的归属对象是 ReplicaSet ,也就是说 Deployment 控制的是 ReplicaSet (版本这个概念其实我们可以等同于是 ReplicaSet ),然后 ReplicaSet 控制 Pod 的数量。我们可以通过 kubectl get rs 来看下具体内容:

Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述

所以这个时候,我们再来理解“版本回退”和“直接部署旧版本的 YAML”的区别就容易了,这里的版本就像是我们平时开发代码库打的 tag 一样,是类似于我们的快照文件一样,这个快照信息可以正确的帮我们记录当时场景的最原始信息,所以我们通过版本回退的方式能够最大限度的保证正确性(这点是k8s已经为我们保证了这一点),反之如果我们通过旧的 yaml 部署,就不一定能保证当前这个 yaml 文件有没有被改动过,这里的变数还是挺大的,所以直接通过 yaml 部署,极大的增加了我们部署的风险性。

在实验环境中,我的每个版本并不是都有 YAML 文件,有时只是做一个很小的调整接着发布,这时 undo 比较好用,真正实现版本回滚/退 。文章来源地址https://www.toymoban.com/news/detail-418369.html

到了这里,关于Kubernetes 笔记(14)— 滚动更新、定义应用版本、实现应用更新、管理应用更新、添加更新描述的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 云原生Kubernetes:K8S集群实现容器运行时迁移(docker → containerd) 与 版本升级(v1.23.14 → v1.24.1)

    目录 一、理论 1.K8S集群升级 2.环境 3.升级策略 4.master1节点迁移容器运行时(docker → containerd)  5.master2节点迁移容器运行时(docker → containerd)  6.node1节点容器运行时迁移(docker → containerd)  7.升级集群计划(v1.23.14 → v1.24.1) 8.升级master1节点版本(v1.24.1) 9.升级master2节点版本

    2024年02月03日
    浏览(69)
  • Android 系统版本与Sdk版本对应一览(更新时间:2023.02.14)

    Android 14 SDK API level 34 Android 13 SDK API level 33 Android 12L SDK API level 32 Android 12 SDK API level 31 Android 11 SDK API level 30 Android 10 SDK API level 29 Android 9 SDK API level 28 Android 8.1 SDK API level 27 Android 8.0 SDK API level 26 Android 7.1.1 SDK API level 25 Android 7.0 SDK API level 24 Android 6.0 SDK API level 23 Android 5.1 SDK A

    2023年04月09日
    浏览(94)
  • 云原生Kubernetes:K8S集群版本升级(v1.20.15 - v1.22.14)

    目录 一、理论 1.K8S集群升级 2.集群概况 3.升级集群(v1.21.14) 4.验证集群(v1.21.14) 5.升级集群(v1.22.14) 6.验证集群  (v1.22.14) 二、实验  1.升级集群(v1.21.14) 2.验证集群(v1.21.14)  3.升级集群(v1.22.14) 4.验证集群(v1.22.14) (1)概念 搭建K8S集群的方式有很多种,比如二

    2024年02月07日
    浏览(48)
  • 使用element 2.14 实现表格虚拟滚动组件

    下述代码为组件实现代码复制即可食用,默认只展示 一屏数据加两条 全选存在些许问题, 使用row-key时,如果行过多滚动时会不会很流畅 特别需要注意的是 行高必须要保持一致 下面为调用示例  

    2024年02月05日
    浏览(36)
  • iOS问题记录 - Xcode 14安装低版本iOS模拟器(持续更新)

    最近客服跟我反馈说,有一个用户打开老项目的iOS App闪退,我回顾了下这项目上次发布改了啥,发现就改了一些文本和链接,这就很奇怪。到后台查了下这个用户的设备信息和应用版本,用的是手机型号是iPhone X,系统版本是iOS 11.2,以及最新版的应用。 很长时间都忙着Flu

    2024年02月15日
    浏览(54)
  • 【微信小程序】列表滚动触底更新实现

    微信小程序开发系列 在微信小程序开发中经常遇到分页列表需要滚动到底部之后进行请求数据更新,下面介绍如何进行触底更新分页展示。使用到页面上拉触底事件的处理函数 onReachBottom 。 监听用户上拉触底事件,可以在app.json的window选项中或页面配置中设置触发距离onRea

    2024年02月05日
    浏览(37)
  • Flutter 自定义AppBar实现滚动渐变

    1、使用ListView实现上下滚动。 2、使用Stack:允许将其子部件放在彼此的顶部,第一个子部件将放置在底部。所以AppBar,写在ListView下面。 3、MediaQuery.removePadding:当使用ListView的时候发现,顶部有块默认的Padding,MediaQuery.removePadding来删除默认的Padding。 4、NotificationListener:监听

    2024年01月23日
    浏览(39)
  • 前端实现浏览器自定义滚动条

    最近有个项目,产品觉得浏览器默认滚动条太丑了。想美化一下,比如自定义颜色,加上圆角,宽高都要更改一下。我查了资料和文档总结了一下 写法,特此记录以便之后使用。 scrollbar-width scrollbar-width 属性允许开发者在元素显示滚动条时设置滚动条的最大宽度。 语法: 取值

    2024年04月10日
    浏览(44)
  • Kubeadm 部署k8s实现并且演示滚动不停服务更新

    在开始之前,部署Kubernetes集群机器需要满足以下几个条件: 一台或多台机器,操作系统 CentOS7.x-86_x64; 硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30GB或更多; 集群中所有机器之间网络互通; 可以访问外网,需要拉取镜像; 禁止swap分区。 主机详情 IP Hostname 备注 192.168

    2024年02月11日
    浏览(37)
  • UniApp苹果真机运行调试(自定义基座,版本更新后/没有基座打开失败)

    在HBuilderX更新后,Windows系统UniAPP在线调试iOS已经不能像之前那样自己安装基座到手机,通过在【设备管理】信任基座app后直接运行调试,现在采用打包自定义基座。 生成打iOS自定义基座所需的描述文件 1.1:登录苹果开发者账户,添加 Profiles 1.2:选择【Ad Hoc】,右上角下一步

    2023年04月16日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包