Kubernetes之资源控制器
1、控制器分类
- Kubernetes中内建了很多controller(控制器),这些相当于一个状态机,用来控制Pod的具体状态和行为。 控制器大致分为如下介绍六种:
- ReplicationController和ReplicaSet
- Deployment
- DaemonSet
- Job/CronJob
- StateFulSet
- Horizontal Pod Autoscaling
1.1 ReplicationController和ReplicaSet
ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收。
在新版本的Kubernetes中建议使用ReplicaSet来取代RC。ReplicaSet跟RC没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector。
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
64
65
66
67
68
69[root@master ~]# vim rs.yaml
[root@master ~]# cat rs.yaml
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: mynginx
image: nginx:latest
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 80
[root@master ~]# kubectl create -f rs.yaml
replicaset.extensions/frontend created
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-2gcxt 1/1 Running 0 61s
frontend-f6mft 1/1 Running 0 61s
frontend-rvdwb 1/1 Running 0 61s
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 70s
# 手动删除其中一个pod,验证副本功能
[root@master ~]# kubectl delete pod frontend-2gcxt
pod "frontend-2gcxt" deleted
#根据副本数会自动创建新的pod
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-f6mft 1/1 Running 0 95s
frontend-hnsn8 1/1 Running 0 9s
frontend-rvdwb 1/1 Running 0 95s
[root@master ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-f6mft 1/1 Running 0 4m11s tier=frontend
frontend-hnsn8 1/1 Running 0 2m45s tier=frontend
frontend-rvdwb 1/1 Running 0 4m11s tier=frontend
# 修改标签名后发现多了一个副本,因为上方配置了标签名为frontend的pod才属于该rs,而修改成frontend1后不满足副本数为3,于是多创建了一个pod
[root@master ~]# kubectl label pod frontend-f6mft --overwrite=true tier=frontend1
pod/frontend-f6mft labeled
[root@master ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-dwfqg 1/1 Running 0 14s tier=frontend
frontend-f6mft 1/1 Running 0 5m40s tier=frontend1
frontend-hnsn8 1/1 Running 0 4m14s tier=frontend
frontend-rvdwb 1/1 Running 0 5m40s tier=frontend
[root@master ~]# kubectl delete rs --all
replicaset.extensions "frontend" deleted
# 删除掉所有rs后,发现只有label被更改后的pod在运行,因为其已经不被识别属于该rs
[root@master ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-dwfqg 0/1 Terminating 0 3m21s tier=frontend
frontend-f6mft 1/1 Running 0 8m47s tier=frontend1
frontend-hnsn8 0/1 Terminating 0 7m21s tier=frontend
frontend-rvdwb 0/1 Terminating 0 8m47s tier=frontend
[root@master ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-f6mft 1/1 Running 0 10m tier=frontend1
1.2 Deployment
Deployment为Pod和ReplicaSet提供了一个声明式定义 (declarative) 方法,用来替代以前的RC来方便的管理应用。
典型的应用场景包括:
定义Deployment来创建Pod和ReplicaSet。
滚动升级和回滚应用。
扩容和缩容。
暂停和继续Deployment。
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82[root@master ~]# vim deployment.yaml
[root@master ~]# cat deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: mynginx
image: nginx:latest
ports:
- containerPort: 80
# --record参数可以记录命令,我们可以很方便的查看每次revision的变化
[root@master ~]# kubectl apply -f deployment.yaml --record
deployment.extensions/nginx-deployment created
[root@master ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 15s
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-7f57b5c565 3 3 3 36s
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-7f57b5c565-pshpl 1/1 Running 0 42s
nginx-deployment-7f57b5c565-wxlbn 1/1 Running 0 42s
nginx-deployment-7f57b5c565-zcckg 1/1 Running 0 42s
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-7f57b5c565-pshpl 1/1 Running 0 2m48s 10.244.1.13 node1 <none> <none>
nginx-deployment-7f57b5c565-wxlbn 1/1 Running 0 2m48s 10.244.2.18 node2 <none> <none>
nginx-deployment-7f57b5c565-zcckg 1/1 Running 0 2m48s 10.244.1.14 node1 <none> <none>
# 动态扩容副本为5
[root@master ~]# kubectl scale deployment nginx-deployment --replicas=5
deployment.extensions/nginx-deployment scaled
[root@master ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 5/5 5 5 5m20s
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-7f57b5c565 5 5 5 5m27s
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-7f57b5c565-9x2fc 1/1 Running 0 68s
nginx-deployment-7f57b5c565-d9t68 1/1 Running 0 68s
nginx-deployment-7f57b5c565-pshpl 1/1 Running 0 5m34s
nginx-deployment-7f57b5c565-wxlbn 1/1 Running 0 5m34s
nginx-deployment-7f57b5c565-zcckg 1/1 Running 0 5m34
# 更改创建容器使用的镜像
[root@master ~]# kubectl set image deployment/nginx-deployment mynginx=nginx:1.21.3
deployment.extensions/nginx-deployment image updated
# 会创建新的rs
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-59fbddf78c 5 5 5 43s
nginx-deployment-7f57b5c565 0 0 0 93s
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-59fbddf78c-9vwv9 1/1 Running 0 112s
nginx-deployment-59fbddf78c-bmjfp 1/1 Running 0 109s
nginx-deployment-59fbddf78c-pkrcp 1/1 Running 0 116s
nginx-deployment-59fbddf78c-prlsw 1/1 Running 0 107s
nginx-deployment-59fbddf78c-zjq4w 1/1 Running 0 116s
# 进行回滚操作
[root@master ~]# kubectl rollout undo deployment/nginx-deployment
deployment.extensions/nginx-deployment rolled back
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-59fbddf78c 0 0 0 4m46s
nginx-deployment-7f57b5c565 5 5 5 5m36s
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-7f57b5c565-7nn4z 1/1 Running 0 18s
nginx-deployment-7f57b5c565-dhv46 1/1 Running 0 30s
nginx-deployment-7f57b5c565-gq6mj 1/1 Running 0 29s
nginx-deployment-7f57b5c565-m26lf 1/1 Running 0 24s
nginx-deployment-7f57b5c565-qmd7x 1/1 Running 0 24s
Deployment更新策略:
- Deployment可以保证在升级时只有一定数量的Pod是down的。默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)。
- Deployment同时也可以确保只创建出超过期望数量的一定数量的Pod。默认的,它会确保最多比期望的Pod数量多一个的Pod是up的(最多1个surge)。
- 未来的Kuberentes版本中,将从1-1变成25%-25% 。
Deployment回滚策略(多个rollout并行):
假如创建了一个有5个niginx:1.7.9 replica的Deployment,但是当还只有3个nginx:1.7.9的replica创建出来的时候您就开始更新含有5个nginx:1.9.1 replica的 Deployment。在这种情况下,Deployment会立即杀掉已创建的3个nginx:1.7.9的Pod,并开始创建nginx:1.9.1的Pod。它不会等到所有的5个nginx:1.7.9的Pod都创建完成后才开始改变航道。
1
2
3
4
5
6
7
8# 查看版本历史
$ kubectl rollout history deployment/nginx-deployment
# 可以使用--revision参数指定某个历史版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=2
# 暂停 deployment 的更新
$ kubectl rollout pause deployment/nginx-deployment
清理Policy:
- 可以通过设置spec.revisonHistoryLimit项来指定Deployment最多保留多少revision历史记录。默认的会保留所有的revision;如果将该项设置为0,Deployment就不允许回退了。
1.3 DaemonSet
DaemonSet确保全部(或者一些)Node上运行一个Pod的副本。当有Node加入集群时,也会为他们新增一个Pod。当有Node从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod。
使用DaemonSet的一些典型用法:
- 运行集群存储daemon,例如在每个Node上运行glusterd、ceph。
- 在每个Node上运行日志收集daemon,例如fluentd、logstash。
- 在每个Node上运行监控daemon,例如Prometheus Node Exporter、collectd、Datadog代理、New Relic代理,或Ganglia gmond。
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[root@master ~]# vim daemonset.yaml
[root@master ~]# cat daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: deamonset-example
labels:
app: daemonset
spec:
selector:
matchLabels:
name: deamonset-example
template:
metadata:
labels:
name: deamonset-example
spec:
containers:
- name: daemonset-example
image: nginx:latest
[root@master ~]# kubectl create -f daemonset.yaml
daemonset.apps/deamonset-example created
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deamonset-example-9vr5w 1/1 Running 0 10s
deamonset-example-ldw29 1/1 Running 0 10s
# 每个node都将创建一个DaemonSet副本
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deamonset-example-9vr5w 1/1 Running 0 2m16s 10.244.1.31 node1 <none> <none>
deamonset-example-ldw29 1/1 Running 0 2m16s 10.244.2.35 node2 <none> <none>
1.4 Job
Job负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
特殊说明:
- RestartPolicy仅支持Never或OnFailure。
- 单个Pod时,默认Pod成功运行后Job即结束。
- .spec.completions标志Job结束需要成功运行的Pod个数,默认为1。
- .spec.parallelism标志并行运行的Pod的个数,默认为1。
- spec.activeDeadlineSeconds标志失败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[root@master ~]# vim job.yaml
[root@master ~]# cat job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
metadata:
name: pi
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
[root@master ~]# kubectl create -f job.yaml
job.batch/pi create
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pi-8hl8j 0/1 Completed 0 10m 10.244.2.36 node2 <none> <none>
[root@master ~]# kubectl get job
NAME COMPLETIONS DURATION AGE
pi 1/1 9m47s 11m
[root@master ~]# kubectl log pi-8hl8j
log is DEPRECATED and will be removed in a future version. Use logs instead.
3.1415926535897932384626433832795028841971693993751058209749445923078164062862
…………
1.5 CronJob
Cron Job管理基于时间的Job,即:
- 在给定时间点只运行一次。
- 周期性地在给定时间点运行。
使用前提条件:当前使用的Kubernetes集群,版本 >= 1.8(对CronJob);对于先前版本的集群,版本 <1.8,启动API Server时,通过传递选项–runtime-config=batch/v2alpha1=true可以开启batch/v2alpha1API。
典型的用法如下所示:
- 在给定的时间点调度Job运行。
- 创建周期性运行的Job,例如:数据库备份、发送邮件。
CronJob spec用法:
- .spec.schedule:调度,必需字段,指定任务运行周期,格式同Cron。
- .spec.jobTemplate:Job模板,必需字段,指定需要运行的任务,格式同Job。
- .spec.startingDeadlineSeconds:启动Job的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的Job将被认为是失败的。如果没有指定,则没有期限。
- .spec.concurrencyPolicy:并发策略,该字段也是可选的。它指定了如何处理被Cron Job创建的Job的并发执行。只允许指定下面策略中的一种:
- Allow(默认):允许并发运行Job。
- Forbid:禁止并发运行,如果前一个还没有完成,则直接跳过下一个。
- Replace:取消当前正在运行的Job,用一个新的来替换注意,当前策略只能应用于同一个Cron Job创建的Job。如果存在多个Cron Job,它们创建的Job之间总是允许并发运行。
- .spec.suspend:挂起,该字段也是可选的。如果设置为true,后续所有执行都会被挂起。它对已经开始执行的Job不起作用。默认值为false。
- .spec.successfulJobsHistoryLimit和.spec.failedJobsHistoryLimit:历史限制,是可选的字段。它们指定了可以保留多少完成和失败的Job。默认情况下,它们分别设置为3和1。设置限制的值为0,相关类型的Job完成后将不会被保留。
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@master ~]# vim cronjob.yaml
[root@master ~]# cat cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
[root@master ~]# kubectl create -f cronjob.yaml
cronjob.batch/hello created
[root@master ~]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 <none> 7s
[root@master ~]# kubectl get job
NAME COMPLETIONS DURATION AGE
hello-1633877460 1/1 9s 24s
# 1分钟后再创建一个job
[root@master ~]# kubectl get job
NAME COMPLETIONS DURATION AGE
hello-1633877460 1/1 9s 89s
hello-1633877520 1/1 9s 29s
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-1633877460-d78qt 0/1 Completed 0 2m12s
hello-1633877520-mnbq9 0/1 Completed 0 72s
hello-1633877580-rz7np 0/1 Completed 0 12s
[root@master ~]# kubectl log hello-1633877460-d78qt
log is DEPRECATED and will be removed in a future version. Use logs instead.
Sun Oct 10 14:51:13 UTC 2021
Hello from the Kubernetes cluster
1.6 StateFulSet
- StatefulSet作为Controller为Pod提供唯一的标识。它可以保证部署和scale的顺序。
- StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现。
- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现。
- 有序部署,有序扩展,即
Pod
是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现。 - 有序收缩,有序删除(即从N-1到0)。
1.7 Horizontal Pod Autoscaling
即HPA,本身不是控制器,而是上方列举的控制器的附属品,用来管理控制器。
应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?这就有赖于Horizontal Pod Autoscaling了,顾名思义,使Pod水平自动缩放。