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

news2025/1/21 2:49:23

滚动更新,使用 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 值作为“版本号”,虽然不太方便识别,但是很实用。
pod-version

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

ngx-dep

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

rollout pod

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

v2

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

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

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


kubectl describe deploy ngx-dep

describe

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

rollout deploy

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

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


kubectl rollout history deploy --revision=2

revision2

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


kubectl rollout undo deploy ngx-dep

undo rollout

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 来看一下更新历史:

rollout pod

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 来看下具体内容:

get rs

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

在实验环境中,我的每个版本并不是都有 YAML 文件,有时只是做一个很小的调整接着发布,这时 undo 比较好用,真正实现版本回滚/退 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/414418.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能作业之遗传算法

遗传算法1.遗传算法定义2.相关术语3.遗传算法的主要步骤4.遗传算法的参数设计原则5.代码实现1.遗传算法定义 遗传算法(Genetic Algorithm, GA)起源于对生物系统所进行的计算机模拟研究。它是模仿自然界生物进化机制发展起来的随机全局搜索和优化方法&am…

java 婚恋交友网站Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 婚恋交友网站是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0&…

IMX6ULL学习笔记(22)——eLCDIF接口使用(TFT-LCD屏显示)

一、TFT-LCD简介 TFT-LCD(Thin Film Transistor-Liquid Crystal Display) 即薄膜晶体管液晶显示器。TFT-LCD 与无源 TN-LCD、 STN-LCD 的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT)&#…

智慧网点解决方案 | 助推银行“营销-销售-服务”一体化建设

传统网点的智慧化变革已成为新形势下银行创新业务服务模式与产品、优化客户体验、提质增效的一大阵地。如何在网点转型过程中充分发挥边缘计算等新技术的价值,引领行业数字化转型新趋势,成为银行业面临的共同课题。 在传统银行网点向智慧网点的转型过程…

基于Java+SpringBoot+vue的家具销售电商平台设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍:专注于Java技术领域和毕业项目实战 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟 Java项目精品实战案例(300套) 目录 一、效果演示 二、…

真00后整顿职场?公司新来了个00后卷王,3个月薪资干到20K.....

最近聊到软件测试的行业内卷,越来越多的转行和大学生进入测试行业。想要获得更好的待遇和机会,不断提升自己的技能栈成了测试老人迫在眉睫的问题。 不论是面试哪个级别的测试工程师,面试官都会问一句“会编程吗?有没有自动化测试…

Redis基础总结-redis简介

Redis基础Redis基础目标:1. Redis 简介1.1 NoSQL概念1.1.1 问题现象1.1.2 NoSQL的概念1.2 Redis概念1.2.1 redis概念1.2.2 redis的应用场景1.3 Redis 的下载与安装1.3.1 Redis 的下载与安装1.4 Redis服务器启动1.4.1 Redis服务器启动1.4.2 Redis客户端启动1.4.3 Red…

数字化转型迫在眉睫!药企如何应用AI技术加速创新?

导语 | 近年来,随着 AI 等技术的发展应用,数字化、智能化日渐成为各行各业转型升级的新兴力量,其与医药产业的融合创新也逐渐成为当前的新趋势,众多医药制造企业蓄势待发,搭乘数字化的快车,驶入高速发展的快…

论文笔记:Fully Convolutional Networks for Semantic Segmentation

摘要 卷积网络是产生特征层次结构的强大视觉模型。我们展示了卷积网络本身,经过端到端、像素到像素的训练,超过了语义分割的最新技术水平。我们的主要见解是构建“全卷积”网络,该网络接受任意大小的输入并通过有效的推理和学习产生相应大小…

css的font-size属性、line-height属性、height属性

目录 一,字体框 二、font-size属性 三、line-height属性 四、line-height和font-size的联系 简介:font-size是css中关于字体的样式属性,注意与文本属性text-xxx进行区别。因为文本由一个个字符组成,所以字体属性也会对文本属性…

海伦司的酒何时“醒”

被年轻人喝出来的“酒馆第一股”海伦司,目前正经历疯狂开店之后的阵痛。 3月24日,海伦司国际控股有限公司(下称“海伦司”,09869.HK)发布了2022年的业绩报告。 海伦司是一家连锁酒馆品牌,其年报公布后的首个交易日,其股价跌幅达…

Qt5.12實戰之Qt調用Linux靜態庫(.a)與動態庫(.so)

1.準備編譯好的靜態庫,複製到lib目錄 ,動態庫複製到bin目錄 2.創建Qt控制臺應用,並添加靜態庫引用 右擊工程名call_liba,選擇添加擴展庫 選擇要添加的libtest.a 然後 點擊 OPEN 點擊Next後會自動添加靜態庫相關引用 到工程 的.pro文件 中 生…

OpenCV实例(五)指纹识别

OpenCV实例(五)指纹识别1.指纹识别概述1.1概述1.2原理2.指纹识别算法2.1特征提取2.2MCC匹配方法2.3尺度不变特征变换(SIFT)3.显示指纹的关键点4.基于SIFT的指纹识别作者:Xiou 1.指纹识别概述 1.1概述 指纹识别&…

程序设计方法学

体育竞技分析 问题分析 体育竞技分析 需求:毫厘是多少? 如何科学分析体育竞技比赛? 输入:球员的水平 输出:可预测的比赛成绩 体育竞技分析:模拟N场比赛 计算思维:抽象 自动化 模拟&am…

QML控件--Menu

文章目录一、控件基本信息二、控件使用三、属性成员四、成员函数一、控件基本信息 二、控件使用 import QtQuick 2.10 import QtQuick.Window 2.10 import QtQuick.Controls 2.3ApplicationWindow{visible: true;width: 1280;height: 720;Button {id: fileButtontext: "Fi…

2023最全的自动化测试入门基础知识(建议收藏)

1)首先,什么是自动化测试? 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常,在设计了测试用例并通过评审之后,由测试人员根据测试用例中描述的过程一步步执行测试,得到实际结果与期望结果的比较。…

数据结构入门(C语言版)二叉树的顺序结构及堆的概念及结构实现应用

二叉树的顺序结构及堆的概念及结构实现二叉树的顺序结构堆的概念及结构堆的实现1、堆向下调整算法2、堆的创建3、堆的插入4、堆的实现向上调整(AdjustUp)向下调整(AdjustDown)堆的初始化(HeapInit)堆的销毁(HeapDestroy)堆的插入(HeapPush)堆的删除(HeapPop)取堆顶的数据(HeapT…

【微服务笔记14】微服务组件之Config配置中心高可用环境搭建

这篇文章,主要介绍微服务组件之Config配置中心高可用环境搭建。 目录 一、高可用Config配置中心 1.1、高可用配置中心介绍 1.2、搭建Eureka注册中心 1.3、搭建ConfigServer服务端 (1)引入依赖 (2)添加配置文件 …

北上广测试工程师月薪20K往上,该如何做,需要会什么技能?

有人回答说这只能是大企业或者互联网企业工程师才能拿到。也许是的,小公司或者非互联网企业拿两万的不太可能是码农了,应该已经转管理。还有区域问题,这个不在我的考虑范围内,因为除了北上广深杭,其他地方也很难达到。…

代码审计之PHP核心配置详解

代码审计之PHP核心配置详解1.register_globals(全局变量注册开关)2.allow_url_include(是否允许包含远程文件)3.magic_quotes_gpc(魔术引号自动过滤)4.magic_quotes_runtime(魔术引号自动过滤&a…