k8s基础-资源调度

1.kubernetes调度基础

1.1replication controller和replicaset(了解即可)

Replication Controller(复制控制器,RC)和 ReplicaSet(复制集,RS)是两种简单部署 Pod的方式。因为在生产环境中,主要使用更高级的 Deployment 等方式进行 Pod 的管理和部署,所以只需要简单了解即可。

1.1.1Replication Controller

Replication Controller(简称 RC)可确保 Pod 副本数达到期望值,也就是 RC 定义的数量。换句话说,Replication Controller 可确保一个 Pod 或一组同类 Pod 总是可用。如果存在的 Pod 大于设定的值,则 Replication Controller 将终止额外的 Pod。如果太小,Replication Controller 将启动更多的 Pod 用于保证达到期望值。与手动创建 Pod 不同的是,用Replication Controller 维护的 Pod 在失败、删除或终止时会自动替换。因此即使应用程序只需要一个 Pod,也应该使用 Replication Controller 或其他方式管理。Replication Controller 类似于进程管理程序,但是 Replication Controller 不是监视单个节点上的各个进程,而是监视多个节点上的多个 Pod。

定义一个 Replication Controller 的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80

5.1.2ReplicaSet

ReplicaSet 是支持基于集合的标签选择器的下一代 Replication Controller,它主要用作Deployment 协调创建、删除和更新 Pod,和 Replication Controller 唯一的区别是,ReplicaSet 支持标签选择器。在实际应用中,虽然 ReplicaSet 可以单独使用,但是一般建议使用 Deployment 来自动管理 ReplicaSet,除非自定义的 Pod 不需要更新或有其他编排等。

定义一个 ReplicaSet 的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# 按你的实际情况修改副本数
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3

Replication Controller 和 ReplicaSet 的创建删除和 Pod 并无太大区别,Replication Controller目前几乎已经不在生产环境中使用,ReplicaSet 也很少单独被使用,都是使用更高级的资源Deployment、DaemonSet、StatefulSet 进行管理 Pod。

1.2 Deployment(无状态应用管理)

无状态的应用是指应用程序在处理每个请求时,不依赖于以前的请求或状态信息。每个请求都是独立的,服务器不会存储任何关于客户端的会话信息。

有状态的应用是指应用程序在处理请求时依赖于以前的请求或会话信息。服务器会记住客户端的状态信息,以便为后续请求提供正确的响应。

Deployment一般用于部署公司的无状态服务,这个也是最常用的控制器,因为企业内部现在都是以微服务为主,而微服务实现无状态化也是最佳实践,可以利用deployment的高级功能做到无缝迁移、自动扩容缩容、自动灾难恢复、一键回滚等功能。

常见的无状态应用:java、go、vue、php等业务容器

pAXtqJK.md.png

1.2.1创建deployment

创建一个deployment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1  #指定这个资源使用的 Kubernetes API 版本,固定写法
kind: Deployment #指定资源类型是 Deployment。
metadata: # deployment的元数据
name: nginx-deployment # 创建的deployment的名字
labels: #键值对标签,用于资源的分类和选择
app: nginx #给这个deployment资源打上'app: nginx'标签
spec: #描述 Deployment 的期望状态,定义 Deployment 的具体配置和行为。
replicas: 3 # 指定需要运行的 Pod 副本数量。
selector: #选择器,用于选择哪些pod属于这个deployment
matchLabels: #匹配标签,选择带有特定标签的pod
app: nginx #指定带有' app: nginx '标签的pod进行管理
template: # pod的模板,用于定义pod
metadata: #pod的元数据
labels: #标签,配置pod的标签
app: nginx #确保创建的 Pod 具有'app: nginx' 标签。
spec: #定义pod内部容器的配置
containers: #容器列表,复数,可配置多个容器
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #容器的镜像
ports: #端口列表,复数,可以暴露多个端口
- containerPort: 80 #指定容器暴露的端口号

使用命令创建一个deployment的模板文件:

1
2
3
4
5
6
7
8
9
10
#使用 kubectl create 命令创建 Deployment
kubectl create deployment nginx-deployment --image=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine --replicas=3 -oyaml --dry-run=client >nginx-deployment.yaml

#使用 kubectl create deployment 命令来创建一个新的 Deployment 资源。
#nginx-deployment 是 要创建的Deployment 的名称。
#--image=nginx:1.14.2:指定使用的 nginx:1.14.2 镜像来运行容器。
#--replicas=3:创建 3 个 Pod 副本。
#-oyaml 以yaml格式显示
#--dry-run=client 不需要真正创建这个deployment
#>nginx-deployment.yaml 将输出重定向到nginx-deployment.yaml文件里

创建这个deployment:

1
2
[root@k8s-master01 pra]# kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created

查看创建的deployment状态:

1
2
3
4
5
6
7
8
9
10
11
#注意,如果指定了命名空间记得要使用 -n 指定命名空间,pod、rs和deploy都有命名空间隔离性
[root@k8s-master01 pra]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 20s

#NAME列:表示deployment对象的名称,这里deployment的名字是nginx-deployment
#READY列:表示当前deploy中当前就绪状态的pod数量/总pod数量,
#UP-TO-DATE:这一列显示了当前正在运行的 Pod 中与最新版本的 Pod 一致的 Pod 的数量。在 Deployment 进行滚动更新时,这个数字会告诉你有多少 Pod 已经升级到了最新版本。
#AVAILABLE:这一列显示了可以使用的(可用的) Pod 的数量。它通常与 READY 的数字相同,除非有 Pod 因为某些原因(如资源限制、节点故障等)而无法接收流量。
#AGE:显示应用程序运行的时间。
综上所述,通过 kubectl get deploy 命令返回的结果可以快速了解到每个 Deployment 的基本状态信息,包括名称、就绪状态、更新状态以及创建时间。

查看rs和po的信息:

1
2
3
4
5
6
7
8
9
10
[root@k8s-master01 pra]# kubectl get rs
NAME DESIRED CURRENT READY AGE
cluster-test-66bb44bd88 1 1 1 18d
nginx-deployment-66bb646879 3 3 3 2m38s
[root@k8s-master01 pra]# kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cluster-test-66bb44bd88-7kct4 1/1 Running 141 (23m ago) 18d 172.16.195.3 k8s-master03 <none> <none>
nginx-deployment-66bb646879-2h2xw 1/1 Running 0 3m39s 172.16.195.5 k8s-master03 <none> <none>
nginx-deployment-66bb646879-gscpf 1/1 Running 0 3m38s 172.16.85.226 k8s-node01 <none> <none>
nginx-deployment-66bb646879-qsjf4 1/1 Running 0 3m39s 172.16.122.135 k8s-master02 <none> <none>

查看此deployment创建的pod的标签:

1
2
3
4
5
6
#查看此 Deployment 创建的Pod,可以看到Pod的hash值 66bb646879 和上述 Deployment对应的ReplicaSet的hash值一致:
[root@k8s-master01 pra]# kubectl get po --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-66bb646879-2h2xw 1/1 Running 0 31m app=nginx,pod-template-hash=66bb646879
nginx-deployment-66bb646879-gscpf 1/1 Running 0 31m app=nginx,pod-template-hash=66bb646879
nginx-deployment-66bb646879-qsjf4 1/1 Running 0 31m app=nginx,pod-template-hash=66bb646879

1.2.2更新deployment

注意:当且仅当deployment的pod模板(即.spec.)更改时,才会触发deployment的更新,例如更改内存、cpu或者容器的image,但是不要更改template.metadata.lables中的标签。

可以使用以下方法更新deploy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#方法一:使用set命令
#假如更新上述创建的deploy中 Nginx Pod 的 image 使用 nginx:latest,并使用--record 记录当前更改的参数,后期回滚时可以查看到对应的信息:
#kubectl 是 Kubernetes 的命令行工具,set image 用于更新 Deployment、DaemonSet 或 StatefulSet 中的容器镜像。
#Deployment 指定要更新的资源类型
#nginx-deployment 指定更新的deployment的名称
#nginx 表示更新 Deployment 中名为 nginx 的容器
#registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest 指定镜像
#--record 用于记录更新,方便查看历史操作 ,也方便后期回滚
[root@k8s-master01 pra]# kubectl set image deployment nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest --record


#查看deployment的更新状态
[root@k8s-master01 pra]# kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out


#查看 Deployment 详细信息:
[root@k8s-master01 pra]# kubectl describe deployment nginx-deployment
返回信息中
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 4m5s deployment-controller Scaled up replica set nginx-deployment-85c7b546bd to 1
Normal ScalingReplicaSet 3m52s deployment-controller Scaled down replica set nginx-deployment-66bb646879 to 2 from 3
Normal ScalingReplicaSet 3m52s deployment-controller Scaled up replica set nginx-deployment-85c7b546bd to 2 from 1
Normal ScalingReplicaSet 3m39s deployment-controller Scaled down replica set nginx-deployment-66bb646879 to 1 from 2
Normal ScalingReplicaSet 3m39s deployment-controller Scaled up replica set nginx-deployment-85c7b546bd to 3 from 2
Normal ScalingReplicaSet 3m25s deployment-controller Scaled down replica set nginx-deployment-66bb646879 to 0 from 1

#翻译:
正常 ScalingReplicaSet 4m5s 部署控制器 将副本集 nginx-deployment-85c7b546bd 扩大到 1
正常 ScalingReplicaSet 3m52s 部署控制器 将副本集 nginx-deployment-66bb646879 从 3 缩小到 2
正常 ScalingReplicaSet 3m52s 部署控制器 将副本集 nginx-deployment-85c7b546bd 从 1 扩大到 2
正常 ScalingReplicaSet 3m39s 部署控制器 将副本集 nginx-deployment-66bb646879 从 2 缩小到 1
正常 ScalingReplicaSet 3m39s 部署控制器 将副本集 nginx-deployment-85c7b546bd 从 2 扩大到 3
正常 ScalingReplicaSet 3m25s部署控制器将副本集 nginx-deployment-66bb646879 从 1 缩减为 0

pod的更新过程:会创建一个新的rs,将新的rs副本数扩大为1,将旧的rs副本数从3缩小到2
再将新的rs副本数从1扩大到2,将旧的rs副本数从2缩小到1
再将新的rs副本数从2扩大到3,将旧的rs副本数从1缩小到0
---------------------------------------------------------------------------------------


#方法二:使用edit命令
#edit用于编辑资源的命令
#deploy指定资源的类型
#nginx-deployment 指定要编辑的deployment的名字,这里名字是nginx-deployment的deployment
#该命令跟vim操作一样,编辑完可以使用:wq保存退出,也可以使用shift+zz保存退出
[root@k8s-master01 pra]# kubectl edit deploy nginx-deployment



#方法三:编辑deploy的yaml文件,重新apply,但是需要注意的是正在运行的deploy和yaml文件一致




可以看出更新过程为新旧交替更新,首先新建一个 Pod,当 Pod 状态为 Running 时,删除一个旧的 Pod,同时再创建一个新的 Pod。当触发一个更新后,会有新的 ReplicaSet 产生,旧的ReplicaSet 会被保存,查看此时ReplicaSet,可以从 AGE 或 READY 看出来新旧 ReplicaSet:

1
2
3
4
5
[root@k8s-master01 pra]# kubectl get rs
NAME DESIRED CURRENT READY AGE
cluster-test-66bb44bd88 1 1 1 18d
nginx-deployment-66bb646879 0 0 0 139m
nginx-deployment-85c7b546bd 3 3 3 23m

在describe中可以看出,第一次创建时,它创建了一个名为nginx-deployment-66bb646879 的ReplicaSet,并将其扩展为3个副本。更新部署时,它创建了一个新的ReplicaSet(nginx-deployment-85c7b546bd ),并将其副本数扩展为 1,然后将旧的 ReplicaSet(nginx-deployment-66bb646879)副本从3 缩小为 2,以此类推完成更新。

正常 ScalingReplicaSet 4m5s 部署控制器 将副本集 nginx-deployment-85c7b546bd 扩大到 1
正常 ScalingReplicaSet 3m52s 部署控制器 将副本集 nginx-deployment-66bb646879 从 3 缩小到 2
正常 ScalingReplicaSet 3m52s 部署控制器 将副本集 nginx-deployment-85c7b546bd 从 1 扩大到 2
正常 ScalingReplicaSet 3m39s 部署控制器 将副本集 nginx-deployment-66bb646879 从 2 缩小到 1
正常 ScalingReplicaSet 3m39s 部署控制器 将副本集 nginx-deployment-85c7b546bd 从 2 扩大到 3
正常 ScalingReplicaSet 3m25s部署控制器将副本集 nginx-deployment-66bb646879 从 1 缩减为 0

1.2.3回滚deployment

当更新了版本不稳定或配置不合理时,可以对其进行回滚操作,假设我们又进行了几次更新(此处以更新镜像版本触发更新,更改配置效果类似):

假设我们进行了更新操作:

1
2
3
4
5
6
7
8
9
#假设更新了镜像,第一次将镜像版本更新为nginx:1.10.0
[root@k8s-master01 ~]# kubectl set image deployment nginx-deployment nginx=nginx:1.10.0 --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deployment image updated

#第二次将镜像版本更新为nginx:1.10.1
[root@k8s-master01 ~]# kubectl set image deployment nginx-deployment nginx=nginx:1.10.1 --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deployment image updated

kubectl rollout history 命令用于查看 Kubernetes 中资源的历史版本记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#案例:查看deployment资源中nginx-deployment的更新历史
[root@k8s-master01 ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 1 3 14h


#查看更新记录
#rollout 指令提供查看、暂停、继续、撤销(回滚)和回滚资源更新的功能。
[root@k8s-master01 ~]# kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 kubectl set image deploy nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest --record=true
3 kubectl set image deploy nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest --record=true
4 kubectl set image deployment nginx-deployment nginx=nginx:1.10.0 --record=true
5 kubectl set image deployment nginx-deployment nginx=nginx:1.10.1 --record=true

查看 Deployment 某次更新的详细信息,使用–revision 指定某次更新版本号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#例如查看第4次更新的详细信息
[root@k8s-master01 ~]# kubectl rollout history deployment nginx-deployment --revision=4
deployment.apps/nginx-deployment with revision #4
Pod Template:
Labels: app=nginx
pod-template-hash=d4c4895f8
Annotations: kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.10.0 --record=true
Containers:
nginx:
Image: nginx:1.10.0-
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>

回滚到上一个版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#使用下面命令看到当前nginx-deployment使用的镜像是官方的nginx:1.10.1
[root@k8s-master01 ~]# kubectl get deployment nginx-deployment -oyaml|grep image
kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.10.1
- image: nginx:1.10.1
imagePullPolicy: IfNotPresent

#kubectl rollout history查看版本更新记录
[root@k8s-master01 ~]# kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 kubectl set image deploy nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest --record=true
3 kubectl set image deploy nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest --record=true
4 kubectl set image deployment nginx-deployment nginx=nginx:1.10.0 --record=true
5 kubectl set image deployment nginx-deployment nginx=nginx:1.10.1 --record=true


#使用kubectl rollout undo指定来回滚到上一个版本,上一个版本用的镜像是nginx:1.10.0
#undo表示撤销、回滚
#deployment表示资源的类型
#nginx-deployment表示资源的名称
[root@k8s-master01 ~]# kubectl rollout undo deployment nginx-deployment
deployment.apps/nginx-deployment rolled back

回滚到指定版本:(使用参数: –to-revision)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#回滚到指定版本使用 --to-revision=2,例如先查看更新历史,在通过回滚操作,回滚到2版本
[root@k8s-master01 ~]# kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 kubectl set image deploy nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest --record=true
3 kubectl set image deploy nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest --record=true
4 kubectl set image deployment nginx-deployment nginx=nginx:1.10.0 --record=true
5 kubectl set image deployment nginx-deployment nginx=nginx:1.10.1 --record=true

#回滚到3,通过上述更新历史可以看出2版本使用的镜像是nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
[root@k8s-master01 ~]# kubectl rollout undo deployment nginx-deployment --to-revision=3
deployment.apps/nginx-deployment rolled back

#查看运行的资源使用的镜像是否是nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
[root@k8s-master01 ~]# kubectl get deploy nginx-deployment -oyaml|grep image
kubernetes.io/change-cause: kubectl set image deploy nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
imagePullPolicy: IfNotPresent

1.2.4扩容deployment

当公司访问量变大,或者有预期内的活动时,三个 Pod 可能已无法支撑业务时,可以提前对其进行扩展。

扩缩容有两种方式:方式一使用edit直接编辑副本数;方式二使用scal命令

方式一:edit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#这里使用edit演示缩容
#此时nginx-deployment管理了三个pod
[root@k8s-master01 ~]# kubectl get po --show-labels|grep app=nginx
nginx-deployment-85c7b546bd-4zk96 1/1 Running 0 18m app=nginx,pod-template-hash=85c7b546bd
nginx-deployment-85c7b546bd-7xxls 1/1 Running 0 18m app=nginx,pod-template-hash=85c7b546bd
nginx-deployment-85c7b546bd-m78f4 1/1 Running 0 18m app=nginx,pod-template-hash=85c7b546bd


#先缩容,缩减到1个pod
[root@k8s-master01 ~]# kubectl edit deploy nginx-deployment
#找到replicas参数将值设为1
replicas: 1

#在查看pod的数量,此时就剩下1个pod
[root@k8s-master01 ~]# kubectl get po --show-labels|grep app=nginx
nginx-deployment-85c7b546bd-4zk96 1/1 Running 0 21m app=nginx,pod-template-hash=85c7b546bd

#注意扩容和缩容不会记录到版本更新记录中,因为replicas的修改不会触发更新,哪些会触发更新见5.2.2

方式二:使用 kubectl scale 动态调整 Pod 的副本数,比如增加 Pod 为 5 个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#使用命令对资源惊醒扩容
#scale是扩容缩容的指令
#deployment 要操作的资源类型,这里是deployment
#nginx-deployment是deployment的名字
# --replicas=5指定副本的数量
#意思是将名字是nginx-deployment的deployment的副本数量设置为5个
[root@k8s-master01 ~]# kubectl scale deployment nginx-deployment --replicas=5
deployment.apps/nginx-deployment scaled


#此时查看pod的数量已经扩增到5个
[root@k8s-master01 ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
cluster-test-66bb44bd88-7kct4 1/1 Running 148 (26m ago) 18d
nginx-deployment-85c7b546bd-2m2pz 1/1 Running 0 3s
nginx-deployment-85c7b546bd-4zk96 1/1 Running 0 43m
nginx-deployment-85c7b546bd-8bmf6 1/1 Running 0 3s
nginx-deployment-85c7b546bd-952gd 1/1 Running 0 3s
nginx-deployment-85c7b546bd-gqvfq 0/1 ContainerCreating 0 3s

注意:无状态的资源可以缩容,但是有状态的服务不要随便缩容,会出现问题(例如statefulset)

1.2.5暂停和恢复deployment更新

上述演示的均为更改某一处的配置,更改后立即触发更新,大多数情况下可能需要针对一个资源文件更改多处地方,而并不需要多次触发更新,此时可以使用 Deployment 暂停功能,临时禁用更新操作,对 Deployment 进行多次修改后在进行更新。

流程就是先对资源进行暂停,在对资源进行编辑,编辑完成在执行恢复指令

①使用 kubectl rollout pause 命令即可暂停 Deployment 更新:

1
2
3
#暂停名为 nginx-deployment 的 Deployment 资源的更新
[root@k8s-master01 ~]# kubectl rollout pause deployment nginx-deployment
deployment.apps/nginx-deployment paused

②然后对 Deployment 进行相关更新操作,比如先更新镜像版本为nginx:1.19.0,然后对其资源进行限制(如果使用的是 kubectl edit 命令,可以直接进行多次修改,无需暂停更新,kubectlset 命令一般会集成在CICD 流水线中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#修改镜像的版本
[root@k8s-master01 ~]# kubectl set image deploy nginx-deployment nginx=nginx:1.19.0
deployment.apps/nginx-deployment image updated

#再次修改,增加内存和cpu的配置
#kubectl set resources 命令用于设置 Kubernetes 中资源的请求和限制。
#deploy:资源类型的缩写,指 Deployment
# nginx-deployment指定要设置资源的具体 Deployment 资源名称是nginx-deployment
#-c nginx指定在 nginx-deployment 中的容器名字是nginx,要为那个容器配置。
#--limits=cpu=200m,memory=512Mi:为容器设置 CPU 和内存的限制。
#cpu=200m:设置 CPU 限制为 200 毫核(0.2 个 CPU 核心)。memory=512Mi:设置内存限制为 512 MiB(兆字节)。
kubectl set resources deploy nginx-deployment -c nginx --limits=cpu=200m,memory=512Mi


#可以用kubectl describe deploy指令查看deploy的状态Progressing
#注意 Progressing 条目,它应该显示 DeploymentPaused 状态。
[root@k8s-master01 ~]# kubectl describe deploy nginx-deployment |grep Progressing
Progressing Unknown DeploymentPaused


#kubectl get deployments也可以看到nginx-deployment的UP-TO-DATE为0,也就是说没有达到期望的pod,恢复后这里会变成5
[root@k8s-master01 ~]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
cluster-test 1/1 1 1 19d
nginx-deployment 5/5 0 5 18h

③恢复更新:进行完最后一处配置更改后,使用 kubectl rollout resume 恢复 Deployment 更新:

1
2
3
#使用kubectl rollout resume指令恢复更新
[root@k8s-master01 ~]# kubectl rollout resume deployment nginx-deployment
deployment.apps/nginx-deployment resumed

可以查看到恢复更新的 Deployment 创建了一个新的 RS(ReplicaSet 缩写):nginx-deployment-55dfd6f8b7

1
2
3
4
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
cluster-test-66bb44bd88 1 1 1 19d
nginx-deployment-55dfd6f8b7 3 3 0 2m53s

可以查看 Deployment 的 image(镜像)已经变为 nginx:1.19.0,资源限制也有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
[root@k8s-master01 ~]# kubectl get deploy nginx-deployment -oyaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "9"
kubernetes.io/change-cause: kubectl set image deploy nginx-deployment nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest
--record=true
generation: 14
labels:
app: nginx
name: nginx-deployment
spec:
progressDeadlineSeconds: 600
replicas: 5
revisionHistoryLimit: 10
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.19.0
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
protocol: TCP
resources:
limits:
cpu: 200m
memory: 512Mi
requests:
cpu: 100m
memory: 100Mi

1.2.6更新deployment的注意事项

历史版本清理策略:

在默认情况下,revision 保留 10 个旧的 ReplicaSet,其余的将在后台进行垃圾回收,可以在.spec.revisionHistoryLimit 设置保留 ReplicaSet 的个数。当设置为 0 时,不保留历史记录。

1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s-master01 ~]# kubectl get  deployments.apps nginx-deployment -oyaml|grep revisionHistoryLimit
revisionHistoryLimit: 10

#最多保留10个rs
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
cluster-test-66bb44bd88 1 1 1 19d
nginx-deployment-55dfd6f8b7 3 3 0 38m
nginx-deployment-66bb646879 0 0 0 19h
nginx-deployment-85c7b546bd 4 4 4 17h
nginx-deployment-9ffdcf9 0 0 0 5h25m
nginx-deployment-d4c4895f8 0 0 0 5h26m

更新策略:

.spec.strategy.type==Recreate,表示重建,先删掉旧的Pod再创建新的Pod(一次性对所有pod进行删除和创建);

.spec.strategy.type==RollingUpdate,表示滚动更新,可以指定maxUnavailable和maxSurge:

配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 #在更新过程中允许的最大不可用 Pod 数量
maxSurge: 2 # 在更新过程中允许的最大超出期望数量的 Pod 数量。这里副本设置5,所以允许最多创建7个pod
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: my-image:latest
  • .spec.strategy.rollingUpdate.maxUnavailable,指定在回滚更新时最大不可用的Pod数量,可选字段,默认为25%,可以设置为数字或百分比,如果maxSurge为0,则该值不能为0;
  • .spec.strategy.rollingUpdate.maxSurge可以超过期望值的最大Pod数,可选字段,默认为25%,可以设置成数字或百分比,如果maxUnavailable为0,则该值不能为0。来控制滚动更新过程;

注意:maxUnavailable=0意思是不能有任何 Pod 被标记为不可用,maxSurge: 0表示没有任何额外的 Pod 被允许创建。会导致更新死锁以及服务中断的风险

Ready 策略:(保持默认值即可)

.spec.minReadySeconds 是可选参数,指定新创建的 Pod 应该在没有任何容器崩溃的情况下视为 Ready(就绪)状态的最小秒数,默认为 0,即一旦被创建就视为可用,通常和容器探针连用。

1.3StatefulSet(有状态应用管理)

1.3.1什么是StatefulSet

无状态的应用是指应用程序在处理每个请求时,不依赖于以前的请求或状态信息。每个请求都是独立的,服务器不会存储任何关于客户端的会话信息。

有状态的应用是指应用程序在处理请求时依赖于以前的请求或会话信息。服务器会记住客户端的状态信息,以便为后续请求提供正确的响应。

pAXtjQe.md.png

1.3.2StatefulSet部署过程

pAXtLRO.md.png

1.3.3headless service和普通service

pAXtOzD.md.png

在 Kubernetes 的环境中,”headless service” 和普通的 “service” 都是用来管理对一组 pod 的访问的,但它们在功能上有一些区别。

  1. Service
    • Kubernetes 中的 Service 是用来提供一个抽象层,允许外部访问 Pod 集群。Service 通过一个固定的 IP 地址和 DNS 名称对外提供服务,并且通过轮询等方式分配外部请求到后端的多个 Pod。
    • Service 通常有一个虚拟的 IP 地址(ClusterIP),请求首先到达这个 IP 地址,然后再由 Service 转发到后端的 Pod。
  2. Headless Service
    • Headless Service 在 Kubernetes 中用于当你不需要 Service 提供负载均衡时。设置 headless service 时,你可以在 Service 的定义中指定 clusterIP: None,这样 Service 就不会有虚拟 IP。
    • Headless Service 的主要用途是允许直接访问 Pod,通常用于需要 Pod 稳定网络标识的应用,比如分布式数据库。DNS 查询会直接返回后端 Pod 的 IP 地址列表,而不是单个 Service IP。

如何定义这两种service:

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
name: my-headless-service
spec:
clusterIP: None # 指定为 None 使得这个 Service 成为 Headless;不配置clusterIP选项默认是普通service
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 9376

1.3.4定义一个 StatefulSet 资源文件

定义一个简单的 StatefulSet 的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
apiVersion: v1
kind: Service #定义资源的类型
metadata:
name: nginx #这里定义的是service的名字
labels:
app: nginx #给service定义的标签
spec:
ports:
- port: 80 #定义service的端口,客户端访问service时使用的端口
name: web #端口的名称,方便管理和引用端口
clusterIP: None #None表示这是一个headless service
selector: #选择器,选择带有app=nginx标签的pod进行管理
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet #定义资源的类型
metadata: #定义资源的元数据
name: web #StatefulSet 的名称
spec:
selector: #标签选择器
matchLabels: #匹配标签
app: nginx # 必须匹配 .spec.template.metadata.labels,选择带有 app: nginx标签的pod
serviceName: "nginx" #关联的 Headless Service 名称,也就是定义service中metadata.name的值
replicas: 3 # 默认值是 1,期望pod的副本数量
minReadySeconds: 10 # 默认值是 0
template:
metadata:
labels: #标签
app: nginx # 必须匹配 .spec.selector.matchLabels,给pod定义打上app:nginx的标签
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
ports:
- containerPort: 80 #容器内部监听的端口
name: web #端口的名称,方便引用和管理端口

kind: Service定义了一个名字为Nginx的Headless Service,创建的Service格式为nginx-0.nginx.default.svc.cluster.local,其他的类似,因为没有指定Namespace(命名空间),所以默认部署在default;

kind: StatefulSet定义了一个名字为web的StatefulSet,replicas表示部署Pod的副本数,本实例为2。

 在 StatefulSet 中 必 须 设 置 Pod 选择器( .spec.selector ) 用 来 匹 配 其 标 签(.spec.template.metadata.labels)。在 1.8 版本之前,如果未配置该字段(.spec.selector),将被设置为默认值,在 1.8 版本之后,如果未指定匹配 Pod Selector,则会导致StatefulSet 创建错误。

​ 当 StatefulSet 控制器创建 Pod 时,它会添加一个标签 statefulset.kubernetes.io/pod-name,该标签的值为 Pod 的名称,用于匹配 Service。

内部pod访问方式:pod名字.svc名字.命名空间

1.3.5创建StatefulSet

利用5.3.2的yaml文件内容创建StatefulSet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@k8s-master01 pra]# kubectl create -f statefulset.yaml
service/nginx created
statefulset.apps/web created

#查看创建的service
[root@k8s-master01 pra]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 22d
nginx ClusterIP None <none> 80/TCP 35s

#查看创建的statefulset,可以缩写为sts
[root@k8s-master01 pra]# kubectl get sts
NAME READY AGE
web 3/3 6m57s

#查看创建的pod
[root@k8s-master01 pra]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 51s
web-1 1/1 Running 0 31s
web-2 1/1 Running 0 11s

1.3.6StatefulSet 创建 Pod 流程

StatefulSet 管理的 Pod 部署和扩展规则如下:

  1. 对于具有N个副本的StatefulSet,将按顺序从0到N-1开始创建Pod;
  2. 当删除Pod时,将按照N-1到0的反顺序终止;
  3. 在缩放Pod之前,必须保证当前的Pod是Running(运行中)或者Ready(就绪);
  4. 在终止Pod之前,它所有的继任者必须是完全关闭状态。

​ StatefulSet 的 pod.Spec.TerminationGracePeriodSeconds(终止 Pod 的等待时间)不应该指定0,设置为 0 对 StatefulSet 的 Pod 是极其不安全的做法,优雅地删除 StatefulSet 的 Pod 是非常有必要的,而且是安全的,因为它可以确保在 Kubelet 从 APIServer 删除之前,让 Pod 正常关闭。

​ 当创建上面的 Nginx 实例时,Pod 将按 web-0、web-1、web-2 的顺序部署 3 个 Pod。在 web-0 处于 Running 或者 Ready 之前,web-1 不会被部署,相同的,web-2 在 web-1 未处于 Running和 Ready 之前也不会被部署。如果在 web-1 处于 Running 和 Ready 状态时,web-0 变成 Failed(失败)状态,那么 web-2 将不会被启动,直到 web-0 恢复为 Running 和 Ready 状态。

​ 如果用户将 StatefulSet 的 replicas 设置为 1,那么 web-2 将首先被终止,在完全关闭并删除web-2 之前,不会删除 web-1。如果 web-2 终止并且完全关闭后,web-0 突然失败,那么在 web-0 未恢复成 Running 或者 Ready 时,web-1 不会被删除。

1.3.7StatefulSet 扩容和缩容

和 Deployment 类似,可以通过更新 replicas 字段扩容/缩容 StatefulSet,也可以使用 kubectl scale、kubectl edit 和 kubectl patch 来扩容/缩容一个 StatefulSet。

  1. 扩容
    将上述创建的 sts 副本增加到 5 个:使用scale命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #当前的pod副本数量是3个
    [root@k8s-master01 pra]# kubectl get po
    NAME READY STATUS RESTARTS AGE
    web-0 1/1 Running 0 10m
    web-1 1/1 Running 0 10m
    web-2 1/1 Running 0 9m48s


    #将sts管理的pod副本数扩容为5
    #scale是扩容缩容指令
    #statefulset是你要操作的资源类型
    #web资源的名字,这里是名字叫web的statefulset
    #--replicas=5 是将pod的副本扩容成5个
    [root@k8s-master01 pra]# kubectl scale statefulset web --replicas=5


    #可以使用-w参数实时查看创建pod的过程
    [root@k8s-master01 pra]# kubectl get po -w
    NAME READY STATUS RESTARTS AGE
    web-0 1/1 Running 0 31m
    web-1 1/1 Running 0 30m
    web-2 1/1 Running 0 30m
    web-3 1/1 Running 0 5s
    web-4 0/1 Pending 0 0s
    web-4 0/1 Pending 0 0s
    web-4 0/1 ContainerCreating 0 0s
    web-4 0/1 ContainerCreating 0 1s
    web-4 1/1 Running 0 3s


    #此时在检查pod数量,已经是5个了
    [root@k8s-master01 pra]# kubectl get po
    NAME READY STATUS RESTARTS AGE
    web-0 1/1 Running 0 43m
    web-1 1/1 Running 0 43m
    web-2 1/1 Running 0 42m
    web-3 1/1 Running 0 12m
    web-4 1/1 Running 0 12m
  2. 缩容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #缩容这里使用编辑文件,然后apply形式
    [root@k8s-master01 pra]# vim statefulset.yaml
    # 将replicas的值改为1
    replicas: 1 #

    #使用replace重新应用一下文件,使其生效
    [root@k8s-master01 pra]# kubectl replace -f statefulset.yaml

    #执行-w实时查看删除动态,可以看出是pod正在有序的被删除
    [root@k8s-master01 pra]# kubectl get po -w
    NAME READY STATUS RESTARTS AGE
    web-4 1/1 Terminating 0 49s
    web-4 0/1 Terminating 0 50s
    web-3 1/1 Terminating 0 70s
    web-3 0/1 Terminating 0 72s
    web-2 1/1 Terminating 0 92s
    web-2 0/1 Terminating 0 93s
    web-1 1/1 Terminating 0 113s
    web-1 0/1 Terminating 0 115s

1.3.8StatefulSet更新策略

  1. On Delete 策略

    OnDelete 更新策略实现了传统(1.7 版本之前)的行为,它也是默认的更新策略。当我们选择这个更新策略并修改 StatefulSet 的.spec.template 字段时,StatefulSet 控制器不会自动更新 Pod,必须手动删除 Pod 才能使控制器创建新的 Pod。

    1
    2
    3
    4
    #配置案例
    spec:
    updateStrategy: #更新策略
    type: OnDelete #表示只在手动删除 Pod 时才更新
  2. RollingUpdate 策略

    RollingUpdate(滚动更新)更新策略会自动更新一个 StatefulSet 中所有的 Pod,采用与序号索引相反的顺序进行滚动更新。

    1
    2
    3
    4
    5
    6
    7
    8
    #配置案例
    spec:
    updateStrategy: #更新策略
    rollingUpdate: #滚动更新
    partition: 0 #分区更新,控制从第几个pod开始更新,如果是1,那表示第0个pod不更新
    type: RollingUpdate #类型:滚动更新

    #partition用来定义滚动更新的分区。它表示 StatefulSet 中从下标 partition 开始的 Pod 将被更新,而小于 partition 的 Pod 将保持不变。

    updateStrategy参数应该配置在spec.updateStrategy区域,而不是spec.template.updateStrategy。这是因为它控制的是StatefulSet整体的Pod更新策略,而不是Pod模板中的单独配置项。

1.3.9StatefulSet分段更新(灰度发布)

比如我们定义一个分区”partition”:3,可以使用 patch 或 edit 直接对 StatefulSet 进行设置:partition参数只能用在RollingUpdate

当partition: 3时,只有下标>=3的pod会被更新,而小于 partition 的 Pod 将保持不变如下图:

pAXtxLd.md.png

案例演示:statefulset.yaml的文件内容如下,RollingUpdate中配置partition: 3,pod副本为5;然后更改镜像版本为nginx:1.27,执行更新操作后观察结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[root@k8s-master01 pra]# cat statefulset.yaml
apiVersion: v1
kind: Service #定义资源的类型
metadata:
name: nginx #这里定义的是service的名字
labels:
app: nginx #给service定义的标签
spec:
ports:
- port: 80 #定义service的端口,客户端访问service时使用的端口
name: web #端口的名称,方便管理和引用端口
clusterIP: None #None表示这是一个headless service
selector: #选择器,选择带有app=nginx标签的pod进行管理
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet #定义资源的类型
metadata: #这个资源的元数据
name: web #StatefulSet 的名称
spec:
updateStrategy: #更新策略
rollingUpdate: #滚动更新
partition: 3 #分区更新,控制从第几个pod开始更新,如果是3,那表示第0,1,2个pod不更新
type: RollingUpdate #类型:滚动更新
selector: #标签选择器
matchLabels: #匹配标签
app: nginx # 必须匹配 .spec.template.metadata.labels,选择带有 app: nginx标签的pod
serviceName: "nginx" #关联的 Headless Service 名称,也就是定义service中metadata.name的值
replicas: 5 # 默认值是 1,期望pod的副本数量
minReadySeconds: 10 # 默认值是 0
template:
metadata:
labels: #标签
app: nginx # 必须匹配 .spec.selector.matchLabels,给pod定义打上app:nginx的标签
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
ports:
- containerPort: 80 #容器内部监听的端口
name: web #端口的名称,方便引用和管理端口

当前5个pod,镜像都是registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@k8s-master01 pra]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 20h
web-1 1/1 Running 0 16m
web-2 1/1 Running 0 15m
web-3 1/1 Running 0 15m
web-4 1/1 Running 0 15m

#查看pod的镜像
[root@k8s-master01 pra]# kubectl get pod -oyaml|grep image
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imageID: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx@sha256:a97dd748c61782687030e80daa151d829843b57d3d2afe72ad6b63d7c3e37402
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imageID: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx@sha256:a97dd748c61782687030e80daa151d829843b57d3d2afe72ad6b63d7c3e37402
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imageID: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx@sha256:a97dd748c61782687030e80daa151d829843b57d3d2afe72ad6b63d7c3e37402
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imageID: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx@sha256:a97dd748c61782687030e80daa151d829843b57d3d2afe72ad6b63d7c3e37402
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
imageID: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx@sha256:a97dd748c61782687030e80daa151d829843b57d3d2afe72ad6b63d7c3e37402

更改sts的镜像为registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:lastest,这里使用edit直接编辑

1
2
3
4
5
6
7
#使用edit编辑名字是web的statefulset
[root@k8s-master01 pra]# kubectl edit sts web
spec:
containers:
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx #修改这里的版本
imagePullPolicy: IfNotPresent
name: nginx

查看更新结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
#可以看出,1、2、3号pod的镜像还是nginx:1.27-alpine,4、5号pod的镜像已经被更新为最新版本nginx:latest  
[root@k8s-master01 ~]# kubectl get po -oyaml|grep image:
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest #这里镜像已更改
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:latest #这里镜像已更改

总结:按照上述方式,可以实现分阶段更新,类似于灰度/金丝雀发布,先更新部分的pod看下效果,没有问题在更新所有的pod,更新其他pod的方式是执行下edit命令将partition的值改为0就会更新之前没有更新的pod(想更新哪些只需要根据partition值修改即可)

1.3.10删除StatefulSet

删除StatefulSet有两种方式:即级联删除和非级联删除。

使用非级联方式删除 StatefulSet时,StatefulSet 管理的 Pod 不会被删除;

使用级联删除时,StatefulSet 和它管理的 Pod 都会被删除;

非级联删除

使用 kubectl delete sts xxx 删除 StatefulSet 时,只需提供–cascade=false 参数,就会采用非级联删除,此时删除 StatefulSet 不会删除它管理的 Pod:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#查看sts
[root@k8s-master01 pra]# kubectl get sts
NAME READY AGE
web 5/5 60m

#查看pod
[root@k8s-master01 pra]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 40m
web-1 1/1 Running 0 41m
web-2 1/1 Running 0 41m
web-3 1/1 Running 0 58m
web-4 1/1 Running 0 58m

#通过上述命令可以看到名字是web的sts管理了5个pod
#使用非级联删除sts
[root@k8s-master01 pra]# kubectl delete sts web --cascade=false
#warning提示 --cascade=false已经被弃用,改用 --cascade=orphan
warning: --cascade=false is deprecated (boolean value) and can be replaced with --cascade=orphan.
statefulset.apps "web" deleted

#此时在查看sts和pod,发现sts已经被删除,但是StatefulSet管理的pod还在
[root@k8s-master01 pra]# kubectl get sts
No resources found in default namespace.
[root@k8s-master01 pra]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 44m
web-1 1/1 Running 0 45m
web-2 1/1 Running 0 45m
web-3 1/1 Running 0 62m
web-4 1/1 Running 0 62m

总结:由于此时删除了 StatefulSet,它管理的 Pod 变成了“孤儿”Pod,pod已经不受调度资源管理,因此单独删除 Pod 时,该Pod 不会被重建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@k8s-master01 pra]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 44m
web-1 1/1 Running 0 45m
web-2 1/1 Running 0 45m
web-3 1/1 Running 0 62m
web-4 1/1 Running 0 62m
[root@k8s-master01 pra]# kubectl delete po web-4
pod "web-4" deleted
[root@k8s-master01 pra]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 48m
web-1 1/1 Running 0 48m
web-2 1/1 Running 0 48m
web-3 1/1 Running 0 65m
级联删除

不使用–cascade=false 参数就是级联删除

也可以使用-f 指定创建 StatefulSet 和 Service 的 yaml 文件,直接删除 StatefulSet 和 Service(此文件将 StatefulSet 和 Service 写在了一起):

1
2
3
4
[root@k8s-master01 pra]# kubectl delete  -f statefulset.yaml
service "nginx" deleted
#这里的报错是由于上面演示非级联删除操作时已经删除了sts,所以这里报错找不到名字是web的statefulsets
Error from server (NotFound): error when deleting "statefulset.yaml": statefulsets.apps "web" not found

由于已经删除了sts,在执行kubectl delete -f statefulset.yaml时pod不会被删除

1
2
3
4
5
6
#删除本命名空间下的所有pod,使用--all参数
[root@k8s-master01 pra]# kubectl delete pod --all
pod "web-0" deleted
pod "web-1" deleted
pod "web-2" deleted
pod "web-3" deleted

1.4DaemonSet守护进程集

pAXwauD.md.png
pAXwJ9x.md.png

1.4.1定义一个DaemonSet

创建一个 DaemonSet 和 Deployment 类似,比如创建一个 nginx 的 DaemonSet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@k8s-master01 pra]# vim daemonset.yaml 
apiVersion: apps/v1
kind: DaemonSet #定义资源的类型
metadata: #元数据
labels: #定义标签
app: nginx #这里是具体的标签,这是为DaemonSet资源打标签
name: nginx-daemonset #定义DaemonSet这个资源的名字
spec: #定义DaemonSet的规格和行为
selector: #选择器,选择什么样的pod进行管理
matchLabels: #标签匹配,用于匹配pod的标签,对pod进行管理
app: nginx #选择具有 app=nginx 标签的pod管理
template: #定义pod的模板,意思是DaemonSet使用这个模板创建pod
metadata: #pod的元数据
labels: #pod的标签,必须与 selector 中的标签匹配
app: nginx #为DaemonSet管理的每个pod添加app=nginx的标签。
spec: #定义pod的规格和行为
containers: #容器列表
- name: nginx #容器的名字是nginx
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #容器使用的镜像

DaemonSet.yaml文件中定义的所要管理的pod的标签在该命名空间中不能有其他pod也有,否则DaemonSet无法管理,会报错。

(1)必需字段

和其他所有 Kubernetes 配置一样,DaemonSet 需要 apiVersion、kind 和 metadata 字段,同时也需要一个.spec 配置段。

(2)Pod 模板

.spec 唯一需要的字段是.spec.template。.spec.template 是一个 Pod 模板,它与 Pod 具有相同的配置方式,但它不具有 apiVersion 和 kind 字段。

除了 Pod 必需的字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签。

(3)Pod Selector

.spec.selector 字段表示 Pod Selector,它与其他资源的.spec.selector 的作用相同。

.spec.selector 表示一个对象,它由如下两个字段组成:

1.4.2创建DaemonSet

利用上述的yaml文件创建daemonset

1
2
3
4
5
6
7
8
9
10
11
12
#使用create命令创建daemonset
[root@k8s-master01 pra]# kubectl create -f ds-nginx.yaml
daemonset.apps/nginx-daemonset created

#查看pod是否被创建,可以看出每个节点中都运行了一个pod
[root@k8s-master01 pra]# kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-daemonset-92vqb 1/1 Running 0 26s 172.16.32.151 k8s-master01 <none> <none>
nginx-daemonset-ltl2x 1/1 Running 0 26s 172.16.58.210 k8s-node02 <none> <none>
nginx-daemonset-mq5g7 1/1 Running 0 26s 172.16.195.15 k8s-master03 <none> <none>
nginx-daemonset-pc5v7 1/1 Running 0 26s 172.16.85.242 k8s-node01 <none> <none>
nginx-daemonset-rkjt7 1/1 Running 0 26s 172.16.122.151 k8s-master02 <none> <none>

1.4.3指定节点部署pod

默认情况下daemonset会在每个节点上部署一个pod,可以利用标签的方式,让daemonset在指定的节点上创建,而不是在所有的节点上创建。

具体流程:先给要部署的节点打上相应的标签,然后配置yaml参数,指定选择具有什么样标签的节点部署pod。创建后的pod就会根据标签选择相应的noe节点上运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#查看所有节点的标签
[root@k8s-master01 pra]# kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master01 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master01,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-master02 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master02,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-master03 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master03,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-node01 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-node02 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node02,kubernetes.io/os=linux,node.kubernetes.io/node=

#给node01和node02节点打上disktype=ssd标签
#可以一次指定多个节点名称
[root@k8s-master01 pra]# kubectl label nodes k8s-node01 k8s-node02 disktype=ssd
node/k8s-node01 labeled
node/k8s-node02 labeled


#验证k8s-node01和k8s-node02节点是否有disktype=ssd标签
[root@k8s-master01 pra]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master01 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master01,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-master02 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master02,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-master03 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master03,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-node01 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux,node.kubernetes.io/node=
k8s-node02 Ready <none> 24d v1.28.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node02,kubernetes.io/os=linux,node.kubernetes.io/node=



#指定了.spec.template.spec.nodeSelector,DaemonSet Controller 将在与 Node Selector(节点选择器)匹配的节点上创建 Pod,比如部署在磁盘类型为 ssd 的节点上(需要提前给节点定义标签 Label):
[root@k8s-master01 pra]# cat ds-nginx.yaml
apiVersion: apps/v1
kind: DaemonSet #定义资源的类型
metadata: #元数据
labels: #定义标签
app: nginx #这里是具体的标签,这是为DaemonSet资源打标签
name: nginx-daemonset #定义DaemonSet这个资源的名字
spec: #定义DaemonSet的规格和行为

selector: #选择器,选择什么样的pod进行管理
matchLabels: #标签匹配,用于匹配pod的标签,对pod进行管理
app: nginx #选择具有 app=nginx 标签的pod管理
template: #定义pod的模板,意思是DaemonSet使用这个模板创建pod
metadata: #pod的元数据
labels: #pod的标签,必须与 selector 中的标签匹配
app: nginx #为DaemonSet管理的每个pod添加app=nginx的标签。
spec: #定义pod的规格和行为
containers: #容器列表
- name: nginx #容器的名字是nginx
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #容器使用的镜像
nodeSelector: #节点选择器,由于该配置项是定义pod的调度策略的,所以应该在spec.template.spec中配置
disktype: ssd #选择带有disktype=ssd标签的节点进行部署pod

#注意:由于 `nodeSelector` 是 Pod 的调度策略,因此它必须放在描述 Pod 规格的 `spec.template.spec` 中,而不是更高层级的DaemonSet `spec` 中。


#创建pod
[root@k8s-master01 pra]# kubectl replace -f ds-nginx.yaml
daemonset.apps/nginx-daemonset replaced

#验证pod是否只在k8s-node01和k8s-node02节点上创建
[root@k8s-master01 pra]# kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-daemonset-xq5xt 1/1 Running 0 34s 172.16.85.243 k8s-node01 <none> <none>
nginx-daemonset-zlmhr 1/1 Running 0 31s 172.16.58.211 k8s-node02 <none> <none>

补充:当你想在其他节点上也创建pod,只需给其他节点上加上disktype=ssd标签即可,pod会自动进行创建

1
2
3
4
5
6
7
[root@k8s-master01 pra]# kubectl label nodes k8s-master03 disktype=ssd
node/k8s-master03 labeled
[root@k8s-master01 pra]# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-daemonset-8dlt6 1/1 Running 0 6s 172.16.195.16 k8s-master03 <none> <none>
nginx-daemonset-xq5xt 1/1 Running 0 5m41s 172.16.85.243 k8s-node01 <none> <none>
nginx-daemonset-zlmhr 1/1 Running 0 5m38s 172.16.58.211 k8s-node02 <none> <none>

1.4.4DaemonSet更新和回滚

如果添加了新节点或修改了节点标签(Label),DaemonSet 将立刻向新匹配上的节点添加Pod,同时删除不能匹配的节点上的 Pod。

在 Kubernetes 1.6 以后的版本中,可以在 DaemonSet 上执行滚动更新,未来的 Kubernetes 版本将支持节点的可控更新。

DaemonSet 滚动更新可参考:https://kubernetes.io/zh-cn/docs/tasks/manage-daemon/update-daemon-set/

查看上一节创建的 DaemonSet 更新方式:RollingUpdate

1
2
[root@k8s-master01 pra]# kubectl get ds/nginx-daemonset -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}'
RollingUpdate

命令式更新,和之前 Deployment、StatefulSet 方式一致:

1
2
#命令格式:kubectl edit ds /<daemonset-name>
[root@k8s-master01 pra]# kubectl edit ds nginx-daemonset

更新镜像:

1
2
3
4
5
6
7
8
9
10
11
12
#命令格式 kubectl set image ds <daemonset-name> -c <container-name>= <container-newimage> --record=true
#kubectl set image更新镜像的命令
#ds表示更新的资源类型是daemonset
#--record=true 表示记录此次更新
[root@k8s-master01 pra]# kubectl set image ds nginx-daemonset nginx=registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine --record=true
Flag --record has been deprecated, --record will be removed in the future
daemonset.apps/nginx-daemonset image updated

#验证镜像是否更新为registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
[root@k8s-master01 pra]# kubectl get ds nginx-daemonset -oyaml|grep image:
- image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine

daemonset不像deployment,每次更新会记录在rs中,daemonset的更新是记录在controllerrevision

1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master01 pra]# kubectl get controllerrevision
NAME CONTROLLER REVISION AGE
nginx-daemonset-6f5d44b8cb daemonset.apps/nginx-daemonset 5 13m
nginx-daemonset-776cfb4bf6 daemonset.apps/nginx-daemonset 3 94m
nginx-daemonset-7966c9fb86 daemonset.apps/nginx-daemonset 6 37m
web-7c8457974 daemonset.apps/nginx-daemonset 1 4h50m
web-8f8db7cb daemonset.apps/nginx-daemonset 2 4h47m


具体更新内容通过controllerrevision查看,例如:
[root@k8s-master01 pra]# kubectl get controllerrevision nginx-daemonset-7966c9fb86 -oyaml

1.5HPA(Horizontal Pod Autoscaler)

HPA(Horizontal Pod Autoscaler)是 Kubernetes 中用于根据工作负载的实时情况自动调整 Pod 副本数量的控制器。HPA 可以根据 CPU 使用率、内存使用率、或者其他自定义的指标(如应用程序特定的指标)来动态地扩展或缩减 Pod 的数量,从而提高应用程序的弹性和资源利用效率。

HPA 的主要功能:

  • 自动扩展:根据实时指标自动增加 Pod 副本数量,以应对高负载情况,从而确保应用程序的性能和可用性。
  • 自动缩减:当负载减少时,自动减少 Pod 副本数量,以节省资源和成本。

1.5.1HPA自动扩缩容实践

待补充