K8S系列深入解析滚动升级
Posted 颜淡慕潇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K8S系列深入解析滚动升级相关的知识,希望对你有一定的参考价值。
目录
专栏介绍
因为可能还有很多同学还不清楚上下文,所以简单介绍一下这个专栏要做的事:
主要是深入解析每个知识点,帮助大家完全掌握k8s,一下是已更新的章节
序号 | 文章 |
第一讲 | 深入解析 k8s:入门指南(一) |
第二讲 | 深入解析 k8s:入门指南(二) |
第三讲 | 深入解析Pod对象(一) |
第四讲 | 深入解析Pod对象(二) |
第五讲 | 深入解析无状态服务 |
第六讲 | 深入解析有状态服务 |
第七讲 | 深入解析控制器 |
第八讲 | 深入解析 ReplicaSet |
序言
那些看似不起波澜的日复一日,一定会在某一天让你看见坚持的意义。
文章标记颜色说明:
- 黄色:重要标题
- 红色:用来标记结论
- 绿色:用来标记一级论点
- 蓝色:用来标记二级论点
Kubernetes (k8s) 是一个容器编排平台,允许在容器中运行应用程序和服务。今天学习一下滚动升级。
希望这篇文章能让你不仅有一定的收获,而且可以愉快的学习,如果有什么建议,都可以留言和我交流
1 基础介绍
Kubernetes是一个流行的容器编排平台,其中的控制器是Kubernetes的核心组件之一,它可以控制Pod的部署和管理。
滚动升级是Kubernetes中的一种重要的控制器操作,可以让用户在不中断服务的情况下对应用程序进行升级。本文将深入解析Kubernetes控制器滚动升级的原理和实现方法。
1.1 什么是滚动升级
滚动升级是指在不中断服务的情况下,对应用程序进行升级的操作。
在Kubernetes中,滚动升级是通过控制器来实现的。控制器会根据用户的要求,逐步将旧版本的Pod逐步替换为新版本的Pod,直到所有的Pod都已经被更新为止。
这样做的优点是可以减少服务中断的时间,同时也可以保证应用程序的稳定性。
1.2 控制器滚动升级的原理
控制器滚动升级的原理:是将旧版本的Pod逐步替换为新版本的Pod。这个过程可以分为以下几个步骤:
创建新版本的Pod:首先需要创建新版本的Pod,并将其添加到控制器的ReplicaSet中。这个ReplicaSet会逐步替换旧版本的Pod。
逐步替换旧版本的Pod:控制器会逐步替换旧版本的Pod,直到所有的Pod都已经被更新为止。在这个过程中,控制器会根据用户定义的策略来控制更新的速度和数量,以确保服务的稳定性。
监控更新过程:在更新过程中,控制器会不断地监控新版本的Pod是否已经成功运行,并将运行失败的Pod进行重启或者回滚操作。这样可以保证应用程序的稳定性。
清理旧版本的Pod:当所有的Pod都已经更新完成后,控制器会自动清理旧版本的Pod,以释放资源。
1.3 控制器滚动升级的实现方法
控制器滚动升级的实现方法可以分为两种:
- 基于Deployment的滚动升级
- 基于StatefulSet的滚动升级
1 基于Deployment的滚动升级
基于Deployment的滚动升级是Kubernetes中最常用的滚动升级方法。
它通过定义一个Deployment对象来管理Pod的创建和更新。Deployment对象包含了Pod的副本数、更新策略、滚动升级速度等信息,可以通过kubectl命令或者Kubernetes API来进行管理。
在进行滚动升级时:
- 创建:需要先使用kubectl命令或者Kubernetes API创建一个新的Deployment对象,并将其更新到Kubernetes集群中。
- 更新:然后,使用kubectl命令或者Kubernetes API更新Deployment对象的镜像版本或者其他配置信息。
Kubernetes会自动根据新的配置信息来创建新版本的Pod,并将更新过程控制在用户定义的范围内。
2 基于StatefulSet的滚动升级
基于StatefulSet的滚动升级是一种相对较新的滚动升级方法。
它通过定义一个StatefulSet对象来管理Pod的创建和更新。与Deployment不同,StatefulSet对象可以保证Pod的唯一性和稳定性,可以在进行滚动升级时保持Pod的稳定性。
在进行滚动升级时,
- 创建StatefulSet对象:需要先使用kubectl命令或者Kubernetes API创建一个新的StatefulSet对象,并将其更新到Kubernetes集群中。
- 更新StatefulSet对象:然后,使用kubectl命令或者Kubernetes API更新StatefulSet对象的镜像版本或者其他配置信息。
Kubernetes会自动根据新的配置信息来创建
2 拓展
2.1 Deployment 的“滚动更新”示例
在 Kubernetes 中,可以使用 Deployment 对象来进行滚动更新。以下是一个 Deployment 滚动更新的详细代码使用介绍:
1 准备镜像
在进行滚动更新之前,需要准备一个新的镜像版本。这里我们以一个简单的 "Hello World" 应用程序为例,在 Docker Hub 上准备一个新版本的镜像。这里先用nginx
2 创建 Deployment
在 Kubernetes 中,可以使用 YAML 文件或命令行工具来创建 Deployment。以下是一个示例 YAML 文件:
apiVersion: apps/v1
kind: Deployment #资源类型
metadata:
name: hello-world
spec:
replicas: 3
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: nginx:1.7.9 # <your-new-image>
ports:
- containerPort: 8080
在这个 YAML 文件中,定义了一个名为 "hello-world" 的 Deployment,它会启动 3 个 Pod,每个 Pod 都包含一个名为 "hello-world" 的容器。容器使用对应的版本镜像,并监听 8080 端口。
3 更新 Deployment
要更新 Deployment,可以使用
kubectl
命令行工具。以下是一个更新 Deployment 的示例命令:
kubectl set image deployment/hello-world hello-world=<your-new-image>
这个命令会将名为 "hello-world" 的 Deployment 的 "hello-world" 容器的镜像更新为你准备的新版本镜像。
4 监控更新状态
在更新 Deployment 后,可以使用
kubectl rollout status
命令来查看更新状态。以下是一个示例命令:
kubectl rollout status deployment/hello-world
这个命令会输出当前 Deployment 的更新状态,包括更新的版本和可用性等信息。
5 回滚更新
如果在更新过程中出现问题,可以使用
kubectl rollout undo
命令来回滚更新。以下是一个示例命令:
kubectl rollout undo deployment/hello-world
这个命令会将 Deployment 回滚到上一个版本,以恢复服务的可用性。
2.2 其他示例
除了上述提到的基本滚动更新过程,Kubernetes 还提供了一些高级功能和特性,以更好地管理应用程序和服务的更新和部署。以下是一些示例:
1 暂停和恢复更新
在滚动更新过程中,如果需要暂停更新以处理问题,可以使用
kubectl rollout pause
命令暂停更新。例如:
kubectl rollout pause deployment/hello-world
这个命令会暂停 "hello-world" Deployment 的更新。一旦问题解决,可以使用
kubectl rollout resume
命令恢复更新。例如:
kubectl rollout resume deployment/hello-world
这个命令会恢复 "hello-world" Deployment 的更新。
2 设置滚动更新策略
在创建 Deployment 时,可以设置滚动更新策略,以控制更新的速度和失败率。
例如,可以设置最大不可用 Pod 的数量和最大并行 Pod 的数量等参数。
以下是一个示例 YAML 文件:
apiVersion: apps/v1
kind: Deployment #资源类型
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deployment
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: nginx-deployment
spec:
containers:
- name: nginx-deployment
image: nginx:laste
ports:
- containerPort: 8080
在这个 YAML 文件中,设置了 RollingUpdate 策略,并指定了最大不可用 Pod 的数量和最大并行 Pod 的数量都为 1。
2.3 总结
我们来看一下在滚动升级中他们三者之间的关系是怎么样的
可以看到,
- 首先,当修改了 Deployment 里的 Pod 定义之后,Deployment Controller 会使用这个修改后的 Pod 模板,创建一个新的 ReplicaSet(v2),这个新的 ReplicaSet 的初始 Pod 副本数是:0。
- Deployment Controller 开始将这个新的 ReplicaSet-(v2)所控制的 Pod 副本数从 0 个变成 1 个,即:“水平扩展”出一个副本。
- Deployment Controller 又将旧的 ReplicaSet-(v1)所控制的旧 Pod 副本数减少一个,即:“水平收缩”成两个副本。
- 如此交替进行,新 ReplicaSet 管理的 Pod 副本数,从 0 个变成 1 个,再变成 2 个,最后变成 3 个。
- 而旧的 ReplicaSet 管理的 Pod 副本数则从 3 个变成 2 个,再变成 1 个,最后变成 0 个。
这样,就完成了这一组 Pod 的版本升级过程。
如上所示,Deployment 的控制器,实际上控制的是 ReplicaSet 的数目,以及每个 ReplicaSet 的属性。
而一个应用的版本,对应的正是一个 ReplicaSet;这个版本应用的 Pod 数量,则由 ReplicaSet 通过它自己的控制器(ReplicaSet Controller)来保证。
通过这样的多个 ReplicaSet 对象,Kubernetes 项目就实现了对多个“应用版本”的描述。
像这样,将一个集群中正在运行的多个 Pod 版本,交替地逐一升级的过程,就是“滚动更新”。
使用 Deployment 进行滚动更新是一种方便而可靠的方式,可以确保服务的连续性和可用性。在更新过程中,需要密切监控服务的性能和可用性,并及时采取措施来解决任何问题。
总的来说,Kubernetes 提供了一系列功能和特性,以帮助用户更好地管理应用程序和服务的更新和部署。这些功能可以根据用户的需求进行配置和使用。
3 投票
K8S系列深入解析Pod对象
目录
序言
任何一件事情,只要坚持六个月以上,你都可以看到质的飞跃。
在上一篇文章中,【K8S系列】深入解析Pod对象(一)
我们深入解析了 Pod 的 API 对象,讲解了 Pod 和 Container 的关系。
作为 Kubernetes 项目里最核心的编排对象,Pod 携带的信息非常丰富。
今天,从一种特殊的 Volume ——Projected Volume 开始,主要讲解:
- Secret
- Downward API
从上面这两种类型展开,希望能帮助你更加深入地理解 Pod 对象各个重要字段的含义。
文章标记颜色说明:
- 黄色:重要标题
- 红色:用来标记结论
- 绿色:用来标记一级论点
- 蓝色:用来标记二级论点
1.Volume 简单介绍
Kubernetes(k8s)中的 Volume 是一种抽象概念,用于表示容器中的存储设备。
Volume 可以包含多个容器,以便它们可以在容器之间共享数据。Volume 在容器内部进行挂载,从而使容器中的应用程序可以像使用本地存储设备一样使用它们。
Kubernetes 中的 Volume 具有以下特点:
生命周期:Volume 可以独立于容器而存在,因此可以在容器之间共享和重用数据。
类型:Kubernetes 中支持多种类型的 Volume,例如 persistentVolumeClaim(PVC)emptyDir、hostPath、configMap、secret 、downwardAPI、projected、CSI等等。每种 Volume 类型都有其特定的用途和限制。
挂载方式:Volume 可以通过不同的挂载方式挂载到容器中,例如作为容器的文件夹、作为容器的环境变量等等。每种挂载方式也都有其特定的用途和限制。
存储介质:Volume 可以与不同的存储介质一起使用,例如本地磁盘、网络存储、云存储等等。
Kubernetes 中的 Volume 提供了一种灵活、可扩展的方式来管理容器中的数据存储。通过使用 Volume,可以轻松地实现容器之间的数据共享和数据持久化,从而使 Kubernetes 应用程序更加可靠和可维护。
2 Projected Volume 介绍
在 Kubernetes 中,有几种特殊的 Volume,它们存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。
这些特殊 Volume 的作用,是为容器提供预先定义好的数据。
所以,从容器的角度来看,这些 Volume 里的信息就是仿佛是被 Kubernetes“投射”(Project)进入容器当中的。这正是 Projected Volume 的含义
详细介绍一下:
Kubernetes(k8s)中的 projected Volume 是一种特殊的 Volume 类型,可以把它翻译为“投射数据卷”。
简单说,它可以将多个 Volume 类型投影到一个 Volume 中。
它可以将多个 Volume 挂载到容器中,从而实现更加灵活和高效的容器化部署。
projected Volume 支持以下四种 Volume 类型的投影:
Secret:将 Kubernetes 中的 Secret 对象挂载到容器中,从而使容器可以访问加密的敏感信息,如密码、证书等。
ConfigMap:将 Kubernetes 中的 ConfigMap 对象挂载到容器中,从而使容器可以访问 ConfigMap 中的配置信息。
DownwardAPI:将容器的元数据(如 Pod 名称、命名空间、标签等)挂载到容器中,从而使容器可以访问自身的元数据。
ServiceAccountToken:将 ServiceAccount 的令牌挂载到容器中,从而使容器可以通过 API 服务器与 Kubernetes API 进行通信。
使用 projected Volume 可以将多个 Volume 类型投影到一个 Volume 中,从而简化 Volume 的管理和配置。
例如,可以将 ConfigMap 和 Secret 投影到一个 Volume 中,并将其挂载到容器中,以便容器可以访问配置信息和加密的敏感信息。
使用 projected Volume 可以提高容器应用程序的灵活性和可维护性,从而更加高效地进行容器化部署。
2.1 Secret
2.1.1 yaml讲解
我们先来看一下Secret,它的作用,是帮你把 Pod 想要访问的加密数据,存放到 Etcd 中。然后,就可以通过在 Pod 的容器里挂载 Volume 的方式,访问到这些 Secret 里保存的信息了。
Secret 最典型的使用场景,是存放数据库的 Credential 信息,比如下面这个例子:
文件名:test-projected-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume
spec:
containers:
- name: test-secret-volume
image: busybox
args:
- sleep
- "86400"
volumeMounts:
- name: mysql-cred
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: mysql-cred
projected:
sources:
- secret:
name: user
- secret:
name: passward
小插曲:
在这个例子中,我们用到了BusyBox镜像,简单介绍下这个镜像:
BusyBox是一个开源项目,提供了一个类似于UNIX操作系统的命令行界面,它包含了许多常用的工具程序,如文件操作、文本处理、网络配置、系统监测等。它被设计成在嵌入式系统中使用,因为它占用的空间很小,可以在资源受限的设备上运行。
在容器技术中,BusyBox通常被用作一个基础镜像,因为它非常轻量级,可以帮助构建小型容器,这也是它被称为"微型容器"的原因。
另外,很多容器镜像都会以BusyBox为基础,通过添加其他应用程序和库来构建完整的应用程序容器。
言归正传,讲下yaml示例:
在这个 Pod 中,定义了一个简单的容器。它声明挂载的 Volume,是 projected 类型。这个 Volume 的数据来源(sources),则是名为 user 和 pass 的 Secret 对象,分别对应的是数据库的用户名和密码。
这里用到的数据库的用户名、密码,就是以 Secret 对象的方式交给 Kubernetes 保存的。完成这个操作的指令,如下所示:
$ kubectl create secret generic user --from-file=./username.txt
$ kubectl create secret generic passward --from-file=./password.txt
如果要查看这些 Secret 对象的话,只要执行一条 kubectl get 命令就可以了:
kubectl get secrets
结果如下:
NAME TYPE DATA AGE
user Opaque 1 30s
passward Opaque 1 30s
又来一个小插曲:
除了使用 kubectl create secret 指令外,我们也可以直接通过编写 YAML 文件的方式来创建这个 Secret 对象,如:
apiVersion: v1
kind: Secret
metadata:
name: mytestsecret
type: Opaque
data:
user: YWRtaW4=
passward: YWRtaW4xMjM0
注意:通过编写 YAML 文件创建出来的 Secret 对象只有一个。
它的 data 字段,是以 Key-Value 的格式保存了两份 Secret 数据。其中,“user”就是第一份数据的 Key,“passward”是第二份数据的 Key。
需要注意的是,Secret 对象要求这些数据必须是经过 Base64 转码的,以免出现明文密码的安全隐患。这个转码操作也很简单,比如:
➜ ~ echo -n 'admin' | base64
YWRtaW4=
➜ ~ echo -n 'admin1234' | base64
YWRtaW4xMjM0
Tips:
需要注意的是,像这样创建的 Secret 对象,它里面的内容仅仅是经过了转码,而并没有被加密。在真正的生产环境中,需要在 Kubernetes 中开启 Secret 的加密插件,增强数据的安全性
2.1.2 创建Pod
言归正传:
我们来创建一下这个 Pod,文件名为:test-projected-volume.yaml
kubectl create -f test-projected-volume.yaml
查看结果:
$ kubectl exec -it test-projected-volume -- /bin/sh
$ ls /projected-volume/
user
passward
$ cat /projected-volume/user
admin
$ cat /projected-volume/passward
admin1234
从上面结果中,可以看到,保存在 Etcd 里的用户名和密码信息,已经以文件的形式出现在了容器的 Volume 目录里。
而这个文件的名字,就是 kubectl create secret 指定的 Key,或者说是 Secret 对象的 data 字段指定的 Key。
更重要的是,像这样通过挂载方式进入到容器里的 Secret,一旦其对应的 Etcd 里的数据被更新,这些 Volume 里的文件内容,同样也会被更新。其实,这是 kubelet 组件在定时维护这些 Volume。
2.2 Downward API
2.2.1 yaml示例
Downward API:是让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息。
举例:
apiVersion: v1
kind: Pod
metadata:
name: test-downwardapi-volume
labels:
zone: us-est-coast
cluster: test-cluster1
rack: rack-22
spec:
containers:
- name: client-container
image: k8s.gcr.io/busybox
command: ["sh", "-c"]
args:
- while true; do
if [[ -e /etc/podinfo/labels ]]; then
echo -en '\\n\\n'; cat /etc/podinfo/labels; fi;
sleep 5;
done;
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
readOnly: false
volumes:
- name: podinfo
projected:
sources:
- downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
在这个 Pod 的 YAML 文件中,定义了一个简单的容器,声明了一个 projected 类型的 Volume。
只不过这次 Volume 的数据来源,变成了 Downward API。而这个 Downward API Volume,则声明了要暴露 Pod 的 metadata.labels 信息给容器。
2.2.2 Downward API 支持字段
Kubernetes Downward API 允许容器在运行时通过环境变量或卷挂载的方式获取 Pod 和容器的元数据信息。支持的字段包括:
- metadata.name: Pod 的名称
- metadata.namespace: Pod 的命名空间
- metadata.labels: Pod 的标签
- metadata.annotations: Pod 的注释
- spec.nodeName: Pod 调度到的节点名称
- spec.serviceAccountName: Pod 使用的服务账户名称
- spec.containers[*].name: 容器名称
- spec.containers[*].image: 容器使用的镜像名称
- spec.containers[*].imagePullPolicy: 容器拉取镜像使用的策略
- spec.containers[].ports[].containerPort: 容器暴露的端口号
- spec.containers[].env[].name: 容器中定义的环境变量名称
- spec.containers[].env[].value: 容器中定义的环境变量值
- status.hostIP: Pod 调度到的节点的 IP 地址
- status.podIP: Pod 的 IP 地址
- status.podIPs[*].ip: Pod 的 IP 地址(多网卡情况下)
- status.startTime: Pod 启动时间
需要注意的是,这些字段可能会因 Kubernetes 版本而有所不同,具体的支持情况需要参考相应版本的文档
不过,需要注意的是,Downward API 能够获取到的信息,一定是 Pod 里的容器进程启动之前就能够确定下来的信息。
而你如果想要获取 Pod 容器运行后才会出现的信息,比如,容器进程的 PID,那就肯定不能使用 Downward API 了,而应该考虑在 Pod 里定义一个 sidecar 容器。
其实,Secret、ConfigMap,以及 Downward API 这三种 Projected Volume 定义的信息,大多还可以通过环境变量的方式出现在容器里。
但是,通过环境变量获取这些信息的方式,不具备自动更新的能力。所以,一般情况下,都建议你使用 Volume 文件的方式获取这些信息。
3 投票
以上是关于K8S系列深入解析滚动升级的主要内容,如果未能解决你的问题,请参考以下文章
K8s自动扩缩容工具KEDA发布2.0版本,全面升级应用扩展能力