某不知名博客 某不知名博客
首页
  • 《vulcat文档》
  • Web安全

    • 《BurpSuite及官方实验室》
    • 《OSWE学习历程》
  • 云原生安全

    • 《Docker命令大全》
    • 《CKS考试学习指南》
    • 《旧-Kubernetes教程》
漏洞库
  • 《渗透工具大全》
  • 《云安全》
事件库
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carsaid

安全界的小学生
首页
  • 《vulcat文档》
  • Web安全

    • 《BurpSuite及官方实验室》
    • 《OSWE学习历程》
  • 云原生安全

    • 《Docker命令大全》
    • 《CKS考试学习指南》
    • 《旧-Kubernetes教程》
漏洞库
  • 《渗透工具大全》
  • 《云安全》
事件库
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前言

  • 学习建议

  • Docker命令大全
  • Kubernetes教程

    • Kubernetes(K8s)学习教程 - 前言
    • 第1章-Kubernetes集群部署
    • 第2章-便捷性设置以及集群插件的安装
    • 第3章-基础操作
    • 第4章-集群升级
    • 第5章-Pod
    • 第6章-Pod生命周期与资源限制
    • 第7章-Pod与节点
    • 第8章-控制器Deployment
    • 第9章-Deployment镜像变更和滚动更新
      • 1. Deployment镜像变更
        • 1.1 变更Deployment镜像的三种方式
        • 1.2 通过命令行变更镜像
        • 1.2.1 变更镜像
        • 1.2.2 查看镜像变更记录
        • 1.2.3 --record替代方案
      • 2. Deployment镜像回滚
      • 3. Deployment镜像滚动更新
        • 3.1 为什么需要滚动更新
        • 3.2 配置滚动更新
      • 4. 一个常见疑惑
      • 5. 小结
    • 第10章-其他控制器-以及标签表达式
    • 第11章-控制器与节点驱逐
    • 暂缓更新
    • 练习题

    • 常用命令及yaml配置

  • CKS教程

  • 云原生安全
  • Kubernetes教程
carsaid
2023-11-13
目录

第9章-Deployment镜像变更和滚动更新

原创

本博客原创文章,转载请注明出处

- name: 原创
  desc: 本博客原创文章,转载请注明出处
  bgColor: '#F0DFB1'
  textColor: '#1078E6'
1
2
3
4

# 第9章-Deployment镜像变更和滚动更新

本章要点
Deployment 镜像的变更和回滚
Deployment 镜像的滚动更新

# 11. Deployment镜像变更

当一个容器镜像有了新版本,我该如何将其应用到现有的 Deployment 及其 Pod 当中呢?难道要整个删了重建?

在开始实验之前,我们先下载几个不同版本的nginx镜像:

# 已经有的镜像 就不用重复下载了
ctr -n k8s.io i pull docker.io/library/nginx:latest
ctr -n k8s.io i pull docker.io/library/nginx:1.9

ctr -n k8s.io i pull docker.io/library/nginx:1.8
ctr -n k8s.io i pull docker.io/library/nginx:1.7.9
1
2
3
4
5
6

当前已经拥有了四个不同版本的nginx镜像。

ctr -n k8s.io i ls | grep nginx
1
Not Found Image

# 1.11.1 变更Deployment镜像的三种方式

和修改 Deployment 的副本数一样,修改镜像的方式也有三种:

  • 通过命令行修改
  • 通过kubectl edit编辑 Deployment 的运行信息
  • 修改原始 yaml 配置文件,然后通过kubectl apply更新配置

但在这里,将仅介绍第一种方式——通过命令行修改 Deployment 的镜像。这是因为,通过命令行修改镜像时可以产生镜像变更历史记录,这对于回滚镜像有着至关重要的作用。

在这之前,我们先创建一个 Deployment:

# deploy-update.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-update
spec:
  replicas: 2
  selector:
    matchLabels:
      app: update
  template:
    metadata:
      labels:
        app: update
    spec:
      containers:
      - image: nginx:latest
        imagePullPolicy: IfNotPresent
        name: nginx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

创建这个控制器:

kubectl apply -f deploy-update.yaml
1
Not Found Image

# 1.21.2 通过命令行变更镜像

# 1.2.11.2.1 变更镜像

基本语法:

  • --record:记录镜像变更信息
kubectl set image deployment <控制器名称> <容器名称>=<新镜像> --record
1

如果不添加--record选项,则当前变更会在历史记录中显示为<none>(空),所以推荐每次都加上该选项。

1、我们可以通过-o wide选项来列出 deployment 的详细信息:

kubectl get deployments -o wide
1

多出了三列信息:

  • “CONTAINERS”:容器名称
  • “IMAGES”:当前使用的镜像
  • “SELECTOR”:通过哪些标签来追踪 Pod
Not Found Image

2、然后通过命令kubectl set image将这个 deployment 的镜像变更为nginx:1.8,同时使用--record选项来记录本次变更:

kubectl set image deployment deploy-update nginx=nginx:1.8 --record
1

命令执行成功,该 deployment 的镜像变更为了nginx:1.8,随后它会删除之前的 Pod,并使用新镜像创建两个新的 Pod。

在不删除控制器的情况下,我们成功更换了 Pod 所使用的镜像版本。

Not Found Image

同时,在执行命令之后,你可能会看到一条突兀的提示信息:

Flag --record has been deprecated, --record will be removed in the future

选项 --record 已被弃用,--record 将在未来被删除
1
2
3

这其实是高版本 k8s 的一个改动,选项--record即将被移除。你不必担心,因为我将在后面介绍一个替代方案。

# 1.2.21.2.2 查看镜像变更记录

基本语法:

kubectl rollout history deployment <控制器名称>
1

1、例如,查看deploy-update的镜像变更记录:

kubectl rollout history deployment deploy-update
1

我们可以看到两条历史记录:

  • 记录 1(初始记录):这条记录是 deployment 被创建出来的那一刻自动产生的,并没有记录变更信息
  • 记录 2:这是我们在 “1.2.1” 小节中所做的变更,将原本的镜像变更为了nginx:1.8
Not Found Image

2、我们再次将 deployment 的镜像变更为nginx:1.9,但这次不添加--record选项:

kubectl set image deployment deploy-update nginx=nginx:1.9
1

变更成功。

Not Found Image

3、再次查看镜像变更历史记录:

kubectl rollout history deployment deploy-update
1

这时有人会说了:诶?这个 “记录 3” 里面不是有变更记录吗?

你再仔细看看,这条变更记录和上一次的相同,都是 nginx:1.8。我们刚刚变更的目标镜像明明是 nginx:1.9,但是这两条记录都是1.8?

Not Found Image

4、我们验证一下,将镜像变更为 nginx:1.7.9,且不记录变更:

kubectl set image deployment deploy-update nginx=nginx:1.7.9

# 再次查看记录
kubectl rollout history deployment deploy-update
1
2
3
4

可以看到,虽然变更的镜像为 nginx:1.7.9,但由于没有添加--record选项,本次历史记录会沿用上一次的变更信息。

Not Found Image

# 1.2.31.2.3 --record替代方案

在 “1.2.1” 小节中得知--record选项即将被移除,那么它的替代方案是什么呢?

1、我们来查看一下 deployment 的详细信息:

kubectl describe deployment deploy-update | head -10
1

这个 deployment 有两条注释信息:

  • deployment.kubernetes.io/revision: 4(镜像变更记录数为 4)
  • kubernetes.io/change-cause: ...(镜像变更信息)

没错,在高版本的 k8s 中,选项--record的替代方案就是注释。

Not Found Image

2、修改注释信息kubernetes.io/change-cause,看看能否产生新的历史记录:

kubectl annotate deployment deploy-update kubernetes.io/change-cause="Update image to nginx:1.7.9"

kubectl rollout history deployment deploy-update
1
2
3

在改变了注释信息kubernetes.io/change-cause的内容之后,记录 4 的历史变更信息也发生了改变。

Not Found Image

那么,如果我想修改记录 3 的变更信息该怎么办呢?诶嘿,改不了!改不了!

在官方文档中,我暂未找到修改前置记录的方法。而在 k8s 的官方论坛中,我遇到了一个具有相同问题的帖子:

(但该帖子已发布接近两年,至今零回复。难道官方还没开发出这种功能?)

Not Found Image

3、所以,在没有--record选项的情况下,每当你变更一次镜像之后,就必须手动修改一次注释......就像这样:

kubectl set image deployment deploy-update nginx=nginx:latest

kubectl annotate deployment deploy-update kubernetes.io/change-cause="Update image to nginx:latest"
1
2
3
Not Found Image

笔记

未来--record注定会被抛弃,所以从现在开始要养成良好习惯。

每当执行变更命令之后,都手动记录一下注释信息kubernetes.io/change-cause="<变更原因>"

如果你没有添加--record选项,又没有手动修改注释信息。那不好意思,本次变更将不会记录新信息。

# 22. Deployment镜像回滚

当你变更了一个 deployment 的镜像之后,发现这个镜像有 BUG,或者遇到了不兼容当前业务之类的情况,该如何将镜像还原到之前的版本呢?

在列出镜像变更历史记录的时候,你可以通过--revision选项查看某次变更的详细信息。

1、例如,查看记录 3 的变更详情:

kubectl rollout history deployment deploy-update --revision=3
1

成功列出了记录 3 的变更详情,虽然注释信息里写的是... nginx=nginx:1.8,但是实际变更的还是 nginx:1.9版本。这印证了之前说过的一句话 “注释只是对集群资源的解释和说明,旨在提高阅读性,不会被作用于任何方面”。

所以,就算你忘记为某一条记录设置注释了,也不会对那一次的实际变更产生影响。

Not Found Image

history命令和--revision选项可以列出某条记录的详情。如果想要回滚镜像,则需要使用undo命令和--to-revision选项。

2、例如,将这个控制器的镜像回滚至记录 3 的状态:

kubectl rollout undo deployment deploy-update --to-revision=3
1

成功将其镜像回滚到了记录 3 所设置的镜像nginx:1.9。

Not Found Image

3、再次查看镜像变更记录:

kubectl rollout history deployment deploy-update

kubectl rollout history deployment deploy-update --revision=6
1
2
3

我们刚刚执行的明明是 “回滚” 操作,但却离奇多出了一条 “变更” 记录 6。

查看记录 6 的详情之后你会发现,所谓的 “回滚”,原来就是 k8s 自动帮你执行了一条变更命令,将状态改回去。

Not Found Image

好嘛,原来回滚(rollout undo)里面包装了一个变更(set image),那我自己变回去不也是一样的?为啥还要回滚?

其实,在查看 变更详情 的时候你应该注意到了,能够 “变更” 的参数不止镜像一个。当变更的参数多起来时,你也需要添加更多的参数选项。

一条命令的参数选项越多,出错的几率也越大。而 “回滚” 可以识别历史变更记录,然后自动为你执行 “变更” 命令,这有助于节省工作量。

笔记

“回滚” 是简洁化的 “变更”。

# 33. Deployment镜像滚动更新

# 3.13.1 为什么需要滚动更新

在 “1.2.1” 小节中我们得知,当 deployment 的镜像被变更之后,它会删除旧的 Pod,然后使用新镜像来创建新的 Pod。

假设有一个 deployment 控制了五个 Pod,默认情况下,当它的镜像被变更之后,它会立马删除五个 Pod,然后再创建另外五个新的 Pod。

这种默认的变更方式有点粗暴,这五个 Pod 在同一时间被删除,而重新创建和运行肯定需要一些时间,在此期间业务都会处于中断状态。

这时候就需要用到滚动更新。

# 3.23.2 配置滚动更新

在创建 deployment 时可以通过spec.strategy字段来为其配置滚动更新:

  • maxSurge:当镜像被变更时,依次创建25%个新的 Pod,直到新的 Pod 数量达到控制器上限
  • maxUnavailable:当镜像被变更时,依次删除25%个旧的 Pod,直到旧的 Pod 全部被删光
...
spec:
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
...
1
2
3
4
5
6
7
8

1、为了更好地看出效果,先将deploy-update的副本数修改为4:

kubectl scale deployment deploy-update --replicas=4
1
Not Found Image

2、由于我们的 deployment 已经处于运行状态,所以通过edit命令来编辑它,然后为其添加滚动更新:

kubectl edit deployment deploy-update
1

刚想编辑,发现这个 deployment 已经配置了滚动更新。可是我们之前创建这个 deployment 的时候明明没有为其配置?

k8s 想的很周到,如果你没有为 deployment 配置滚动更新,那么它就会提供一个默认值:依次删除25%个旧的 Pod、并依次创建25%个新的 Pod。这个百分比是根据 副本数 来计算具体数量的。

Not Found Image

我们刚刚将 deployment 的副本数调整为了4个,也就是说,当这个 deployment 的镜像被变更时,它会依次删除1个旧的 Pod、并依次创建1个新的 Pod,直到所有的 Pod 都完成镜像变更。

3、此外,如果你不想使用百分比,你也可以提供一个绝对数值:

...
spec:
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
...
1
2
3
4
5
6
7
8

如图所示,不用改变字段名称,直接将 值 修改为数字即可。

然后保存退出。

Not Found Image

4、然后变更其镜像,并不断查看 Pod 情况:

kubectl set image deployment deploy-update nginx=nginx:1.7.9

kubectl get pods
1
2
3

删除和创建 Pod 的速度很快,但看得还是很清楚。

  • 第一次查看时
    • 已经有三个新的 Pod 被创建出来,其中一个刚刚进入 “Running” 状态
    • 已经有一个旧的 Pod 被删除;一个旧的 Pod 正处于删除状态(Terminating);还有两个旧的 Pod 处于运行状态,等着被删除
  • 第二次查看时
    • 新的 Pod 已经全部创建完成,并进入运行状态,它们接手了之前的工作任务
    • 旧的 Pod 即将被完全删除,还剩下一个
  • 第三次查看时,滚动更新已经完成
Not Found Image

笔记

在执行滚动更新时,创建新 Pod 和删除旧 Pod 这两个操作是同时进行的,并不存在先后顺序。

# 44. 一个常见疑惑

我们前面变更镜像,都只是单纯地更改了 nginx 镜像的版本号,能否将 nginx 镜像修改为其它镜像?

1、当然可以,还是以之前的 deployment 为例,将其镜像变更为alpine:

kubectl set image deployment deploy-update nginx=alpine
1

成功将镜像nginx:1.7.9变更为了alpine。

Not Found Image

在查看 Pod 信息时,你会发现两个新创建出来的 Pod 貌似遇到了错误,状态一直停留在 “CrashLoopBackOff”。

别担心,这其实是 Pod 生命周期的缘故,由于镜像alpine默认不会在容器中执行任何启动命令,所以 Pod 的生命周期会很快结束,然后状态会被标记为 “Completed”(运行完毕)。

而由于 滚动更新 的存在,如果 deployment 在创建新的 Pod 时遇到了错误,便会停止变更。可想而知,如果此时没有滚动更新,那么所有的 Pod 都将处于不可用状态,这会对业务造成多大的影响?

Not Found Image

2、如果你想解决这个问题,可以编辑 deployment 中的 Pod 模板,为其添加spec.containers.command(启动时命令):

kubectl edit deployment deploy-update
1
# 这将使容器休眠 9999999 秒
command: ['sh', '-c', 'sleep 9999999']
1
2
Not Found Image

保存退出之后,由于sleep命令使 Pod 生命周期得到了延长,错误得以解决,所以滚动更新会继续进行。

Not Found Image

# 55. 小结

本章内容较为简单,但你仍需掌握:

  • 通过命令行变更 deployment 的镜像
  • 通过注释来记录变更信息
  • 查看历史变更记录(列表)
  • 查看历史变更记录(详情)
  • 回滚镜像
  • 配置滚动更新

去做一些练习吧(练习题-7),这肯定难不到你。

编辑 (opens new window)
第8章-控制器Deployment
第10章-其他控制器-以及标签表达式

← 第8章-控制器Deployment 第10章-其他控制器-以及标签表达式→

最近更新
01
API测试笔记
04-30
02
msfvenom
03-29
03
Metasploit
03-29
更多文章>
Theme by Vdoing | Copyright © 2023-2024 Carsaid | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式