工作负载控制器(Workload Controllers)是k8s的一个抽象概念,用于更高级层次对象,负责部署和管理Pod。
常用工作负载控制器:
控制器的作用:
Deployment的功能:
第一步:部署镜像
web.yaml清单内容如下
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
#Pod副本的预期数量
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
#Pod副本的标签
app: web
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
运行此清单创建deployment
[root@k8s-master ~]# kubectl apply -f web.yaml
[root@k8s-master ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
web 3/3 3 3 5s
[root@k8s-master ~]# kubectl get pod -l app=web
NAME READY STATUS RESTARTS AGE
web-794776687-ms58g 1/1 Running 0 76s
web-794776687-xtc9d 1/1 Running 0 77s
web-794776687-zdtkp 1/1 Running 0 76s
创建service将此deployment暴露出去供浏览器访问
[root@k8s-master ~]# kubectl expose deployment web --port=80 --target-port=80 --type=NodePort --dry-run=client -o yaml > service.yaml
[root@k8s-master ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
type: NodePort
[root@k8s-master ~]# kubectl apply -f service.yaml
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 132d
web NodePort 10.102.94.33 <none> 80:32012/TCP 13s
浏览器访问k8s任意节点IP:32012即可访问到nginx首页
更新镜像有三种方式,默认自动触发滚动升级
滚动升级:滚动发布是指每次只升级一个或多个服务,升级完成后加入生产环境,不断执行这个过程,直至集群中的全部的旧版本升级为新版本;
例如上一步我们部署了镜像版本为1.14的nginx,现在我们将镜像升级为1.17
第一种方式:
其实就是手动编辑yaml清单将镜像修改为1.17
[root@k8s-master ~]# vim web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
#Pod副本的预期数量
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
#Pod副本的标签
app: web
spec:
containers:
- name: web
image: nginx:1.17
ports:
- containerPort: 80
[root@k8s-master ~]# kubectl apply -f web.yaml
第二种方式:
直接通过命令行修改deployment资源使用的镜像,jenkins常用这种方式
kubectl set image deployment/
[root@k8s-master ~]# kubectl set image deployment/web nginx=nginx:1.17
第三种方式:
使用当前系统默认的编辑器临时打开deployment控制器,保存后可以立即生效(wq保存之后相当于自动kubectl apply 了一下),可以作用于找不到deployment的yaml清单时使用
[root@k8s-master ~]# kubectl edit deployment/web
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: apps/v1
kind: Deployment
...
spec:
containers:
- image: nginx:1.17
imagePullPolicy: IfNotPresent
name: nginx
...
使用上面三种方式升级镜像后,pod变化如下
[root@k8s-master ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
web-777dc5c56f-96dcr 1/1 Running 0 3m59s
web-777dc5c56f-c4h2v 1/1 Running 0 3m56s
web-777dc5c56f-r2zds 1/1 Running 0 3m54s
web-5499465464-rz2hm 0/1 Pending 0 0s
web-5499465464-rz2hm 0/1 ContainerCreating 0 1s
web-5499465464-rz2hm 1/1 Running 0 3s
web-777dc5c56f-r2zds 1/1 Terminating 0 4m3s
可以看出就是使用的滚动升级
,先创建一个新的pod,等running后在干掉一个老的pod,往复循环,直至pod全部变为新的;
去浏览器查看下现在nginx的版本
在了解滚动升级的原理之前,需清楚replicaSet控制器:
replicaSet控制器
kubectl get rs #查看rs历史的记录,rs会对之前的部署过的记录进行保留,当前在用的RS ready为3,历史不在用的为0
[root@k8s-master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
web-5499465464 3 3 3 24h
web-777dc5c56f 0 0 0 24h
kubectl rollout history deployment web #每个版本对应的RS记录
[root@k8s-master ~]# kubectl rollout history deployment web
deployment.apps/web
REVISION CHANGE-CAUSE
1 <none>
2 <none>
在k8s中更新镜像就会触发滚动升级,滚动升级是利用了1个deployment和2个replicaSet来实现的
如上图:
在1个deployment控制器中包含2个replicaset控制器,replicaset主要管理pod的副本数,继而通过replicaset管理副本数的能力来实现滚动升级;例如将replicaset2的副本数调整为3时,那么replicaset1的副本数就回被调整为1,
如上图,我们可以看到deployment在升级的时候是对两个RS(web-777dc5c56f、web-5499465464) 进行操作的,对两个RS来回的进行一个扩容一个缩容从而就实现了副本数的滚动升级;
注:如果升级失败(pod没有运行成功),将不再继续进行升级,等待升级正确的镜像或者回滚;
示例一:此选项为 30% 时,replicas副本数设置的为10,那么在滚动升级时,会立即对新的replicaset进行扩容,同时会保证新旧Pod的总数不超过所需Pod的总数(replicas)的130%,一旦旧Pod被杀死,新的Replicaset就可以进一步扩容,同时确保更新期间的任何时候运行中的Pod总数最多为所需Pod总数的130%;
apiVersion: apps/v1
kind: Deployment
...
spec:
#Pod副本的预期数量
replicas: 10
strategy:
rollingUpdate:
#滚动更新时,maxSurge=新Pod的数量=(replicas*30%),此时Pod的总数量=replicas + maxSurge
maxSurge: 30%
selector:
matchLabels:
app: web
...
示例二:此选项为 5 时,replicas副本数设置的为10,那么在滚动升级时,会立即对新的replicaset进行扩容,同时会保证新旧Pod的总数不超过所需Pod的总数15(replicas + maxSurge),一旦旧Pod被杀死,新的Replicaset就可以进一步扩容,同时确保更新期间的任何时候运行中的Pod总数最多为所需Pod的总数15;
apiVersion: apps/v1
kind: Deployment
...
spec:
#Pod副本的预期数量
replicas: 10
strategy:
rollingUpdate:
#滚动更新时,一次性更新的Pod数量,此时Pod的总数量=replicas + maxSurge
maxSurge: 5
selector:
matchLabels:
app: web
...
示例一:此选项为 30% 时,replicas副本数设置的为10,那么在滚动升级时,会立即对旧的repliaset进行缩容至70%,也就是7个旧的pod,当新pod就绪后,会继续缩容旧的replicaset,然后对新的replicaset进行扩容,确保在更新期间可用的pod总数在任何时候都至少为所需pod个数的70%;
apiVersion: apps/v1
kind: Deployment
...
spec:
#Pod副本的预期数量
replicas: 10
strategy:
rollingUpdate:
#滚动更新时,不可用pod的数量;也就是会会将旧的replicaset缩容30%
maxUnavailable: 30%
selector:
matchLabels:
app: web
template:
metadata:
labels:
#Pod副本的标签
app: web
...
示例二:此选项为 3 时,replicas副本数设置的为10,那么在滚动升级时,会立即对旧的repliaset进行缩容至7个副本,当新pod就绪后,会继续缩容旧的replicaset,然后对新的replicaset进行扩容,确保在更新期间可用的pod总数在任何时候都不少于7个;
apiVersion: apps/v1
kind: Deployment
...
spec:
#Pod副本的预期数量
replicas: 10
strategy:
rollingUpdate:
#滚动更新时,不可用pod的数量为3个;也就是会会将旧的replicaset缩容至7个
maxUnavailable: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
#Pod副本的标签
app: web
...
通过上面的列子可以总结出:
建议配置为:
apiVersion: apps/v1
kind: Deployment
...
spec:
#Pod副本的预期数量
replicas: 10
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: web
template:
metadata:
labels:
#Pod副本的标签
app: web
...
这也算是在生产环境中最稳定的配置,即“一上一下,先上后下”最平滑原则,一个新的pod状态为reday后,再将旧版本的pod进行销毁;这个配置的使用场景是平滑更新、保证服务稳定,但也有缺点,就是更新太慢了;
自定义策略:
切记:当服务的副本数为1时,推荐使用上面的"建议配置"或使用k8s默认的配置即可,千万不要自定义将"maxUnavailable"这个值设为1或100%,否则将造成更新期间服务直接挂掉!!
Deployment controller调整replicaset数量时,严格通过以下公式来控制发布节奏。所以,如需快速发布,可根据实际情况去调整这两个值:
(目标副本数-maxUnavailable) <= 线上实际Ready副本数 <= (目标副本数+maxSurge)
举例:如果期望副本数是10,期望能有至少80%数量的副本能稳定工作,所以:maxUnavailable = 2,maxSurge = 2 (可自定义,建议与maxUnavailable保持一致)
8 <= 线上实际Ready副本数 <= 12
这样,更新过程中,线上能够正常提供服务的pod数总会保持在这个区间内。
现象(maxUnavailable = 1,maxSurge = 1)
扩容:当用户的请求数增高时,例如双十一、618这种活动,这时就需要增加我们服务的副本数(replicas)来支撑高并发;
水平扩缩容解决方案:
注:
web为要扩缩容的deployment名称
replicas参数用来控制Pod副本数量
当我们的应用发布后因某种问题导致了线上事故,业务不能正常访问;此时就需要对应用进行回滚;
注:回滚是重新部署某一次部署时的状态,即当时版本所有配置
#查看历史发布版本
kubectl rollout history deployment/web
#回滚至上个版本
kubectl rollout undo deployment/web
#回滚至指定历史版本
kubectl rollout undo deployment/web --to-revision=2
回滚的原理其实是基于replicaset控制来实现的,因为deployment每次升级都会创建一个新的RS作为记录,这个记录就相当于是每个版本迭代的备份,如下所示;
[root@k8s-master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
web-5cd5f844db 0 0 0 73s
web-65c48b5b5 0 0 0 87s
web-6886c44bb7 0 0 0 51s
web-69ddb96fb8 0 0 0 31s
web-7fbc4b76bd 3 3 3 10s
[root@k8s-master ~]# kubectl rollout history deployment/web
deployment.apps/web
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
4 <none>
5 <none>
其实通过kubectl rollout history这个命令查看回滚历史并不能看到每个版本所使用的镜像,此时如果想指定回滚的版本的话可以通过查看RS的记录来回滚,步骤如下:
(1)先通过RS获取对应发布版本号及镜像版本
注:RS详情里的revision这个字段匹配的就是"kubectl rollout history"的版本号
[root@k8s-master ~]# kubectl describe rs | egrep "revision:|Name:|Image:"
Name: web-5cd5f844db
deployment.kubernetes.io/revision: 2
Image: nginx:1.17
Name: web-65c48b5b5
deployment.kubernetes.io/revision: 1
Image: nginx:1.16
Name: web-6886c44bb7
deployment.kubernetes.io/revision: 3
Image: nginx:1.18
Name: web-69ddb96fb8
deployment.kubernetes.io/revision: 4
Image: nginx:1.19
Name: web-7fbc4b76bd
deployment.kubernetes.io/revision: 5
Image: nginx:1.20
(2)根据查看到的镜像版本及对应发布版本号进行回滚
例如这里我要回滚到nginx1.19版本,则需要指定revision=4
[root@k8s-master ~]# kubectl rollout undo deployment/web --to-revision=4
deployment.apps/web rolled back
(3)会使用对应的rs记录,回滚到该镜像版本
注:其实回滚也可以直接使用正确的镜像重新部署下即可;
当确认项目下线不再使用时,可以进行删除deployment及所使用的其它资源;
[root@k8s-master ~]# kubectl delete deployment/web
deployment.apps "web" deleted
[root@k8s-master ~]# kubectl delete svc/web
DaemonSet功能:
应用场景:网络插件(kube-proxy、calico) 、日志、监控等其它Agent
示例:
部署余个日志采集程序
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat
namespace: kube-system
labels:
app: filebeat
spec:
selector:
matchLabels:
app: filebeat
template:
metadata:
labels:
app: filebeat
spec:
tolerations:
#添加对master节点对容忍,如果不需要master运行的话可以删除此容忍
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: log
image: elastic/filebeat:7.3.2
运行此yaml后并验证
[root@k8s-master ~]# kubectl get pod -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
...
filebeat-89lrs 1/1 Running 0 4m51s 10.244.36.89 k8s-node1 > >
filebeat-8rbw4 1/1 Running 0 4m51s 10.244.235.193 k8s-master > >
filebeat-9gn54 1/1 Running 0 4m51s 10.244.169.137 k8s-node2 > >
filebeat-h72s2 1/1 Running 0 4m51s 10.244.107.238 k8s-node3 > >
...
可以看到daemonset会在每个节点都帮我们启一个filebeat的pod
Job分为普通任务(Job)和定时任务(CronJob)
应用场景:离线数据处理,视频解码等业务;
示例:
使用perl镜像计算圆周率,它负责计算 π 到小数点后 2000 位,并将结果打印出来。
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
#允许执行失败的pod数量,当执行状态status为Failed时,会重新起一个pod运行,默认是6; 0代表不允许pod失败,失败了就不执行了;
backoffLimit: 0
运行此yaml后验证
[root@k8s-master goodgood_study]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pi-n6c54 0/1 Completed 0 21s
[root@k8s-master goodgood_study]# kubectl get job
NAME COMPLETIONS DURATION AGE
pi 1/1 6s 27m
[root@k8s-master goodgood_study]# kubectl describe job/pi
Name: pi
...
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 27m job-controller Created pod: pi-n6c54
Normal Completed 27m job-controller Job completed
#查看这个job对pod运行日志
[root@k8s-master goodgood_study]# kubectl logs -f pod/pi-n6c54
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
应用场景:通知、备份操作等;
示例:
一分钟打印一次当前时间和问候信息
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
#每周的周一到周五的凌晨1点执行
#schedule: "0 1 * * 1-5"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello fandaoshuai;
restartPolicy: OnFailure
运行此yaml后验证
[root@k8s-master ~]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello * * * * * False 0 <none> 11s
[root@k8s-master goodgood_study]# kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-1692695040-rc5v7 0/1 Completed 0 24s
[root@k8s-master goodgood_study]# kubectl logs -f pod/hello-1692695040-rc5v7
Tue Aug 22 09:10:05 UTC 2023
Hello fandaoshuai