Kubernetes-Controller
控制器Controller
Controller作用
控制器controller用于控制Pod
官方文档: https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/
Controller分类
控制器主要分为:
- Deployment:部署无状态应用,控制Pod升级,回退
- ReplicaSet:副本集,控制Pod扩容,缩减
- ReplicationController:相当于ReplicaSet的老版本,现在建议使用Deployments加ReplicaSet替代RC
- StatefulSet:部署有状态应用,结合Service、存储等实现对有状态应用的部署
- DaemonSet:守护进程集,运行在所有集群节点(包括master),比如使用filebeat,node_exporter
- Job:一次性任务
- CronJob:周期性任务
Deployment
Deployment功能
- Deployment集成了上线部署、滚动升级、创建副本、回滚等功能
- Deployment里包含并使用了ReplicaSet
Deployment用于部署无状态应用
无状态应用的特点:
- 所有Pod无差别
- 所有Pod中容器运行同一个Image
- 所有Pod可以运行在集群中任意node上
- 所有Pod无启动顺序先后之分
- 随意Pod数量扩容或缩容
创建deployment类型应用
准备yaml文件
# 获取帮助
[root@master deployment 18:46:21]# kubectl explain deployment
GROUP: apps
KIND: Deployment
VERSION: v1
... ...
[root@master deployment 18:46:58]# vim nginx-deploy.yaml
apiVersion: v1
kind: Namespace
metadata:
name: web-test
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy # deployment名称
namespace: web-test # 设置命名空间
spec:
# 副本控制
replicas: 2
selector:
matchLabels:
app: nginx # 匹配模板标签,表示deployment和rs控制器控制带有此标签的Pod
template: # Pod的配置模板
metadata:
labels:
app: nginx # Pod标签
spec:
restartPolicy: Always
containers: # Pod中容器定义
- name: c1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 150m
memory: 300Mi
requests:
cpu: 100m
memory: 200Mi
# 存货探针
livenessProbe:
httpGet:
port: http
path: /index.html
验证yaml文件
[root@master deployment 18:51:25]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deploy created
# 验证
[root@master deployment 18:51:33]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-84b89f5f96-7xhhn 1/1 Running 0 26s
nginx-deploy-84b89f5f96-f2ksn 1/1 Running 0 26s
查看deployment名称
[root@master deployment 18:53:21]# kubectl get deployment -n web-test
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 2m56s
查看replicas名称
[root@master deployment 18:54:50]# kubectl get replicaset -n web-test
NAME DESIRED CURRENT READY AGE
nginx-deploy-84b89f5f96 2 2 2 3m25s
访问deployment
查看Pod的IP地址
[root@master deployment 18:54:58]# kubectl get pod -o wide -n web-test
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-84b89f5f96-7xhhn 1/1 Running 0 4m23s 10.244.166.150 node1 <none> <none>
nginx-deploy-84b89f5f96-f2ksn 1/1 Running 0 4m23s 10.244.104.11 node2 <none> <none>
查看所有集群节点的网卡
[root@master deployment 18:55:56]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.219.64 netmask 255.255.255.255
[root@node1 ~ 13:52:08]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.166.128 netmask 255.255.255.255
[root@node2 ~ 13:52:10]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.104.0 netmask 255.255.255.255
可以看见集群节点的IP在10.244.0.0/16 这个大网段内的子网
在任意集群节点上都可以访问此deployment里的Pod
[root@master deployment 18:59:44]# ping -c 2 10.244.166.150
PING 10.244.166.150 (10.244.166.150) 56(84) bytes of data.
64 bytes from 10.244.166.150: icmp_seq=1 ttl=63 time=0.423 ms
64 bytes from 10.244.166.150: icmp_seq=2 ttl=63 time=0.369 ms
--- 10.244.166.150 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.369/0.396/0.423/0.027 ms
[root@node2 ~ 18:56:56]# curl http://10.244.166.150
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
删除deployment中的Pod
强制删除Pod(删除deployment中的Pod)
[root@master deployment 19:00:02]# kubectl delete pod nginx-deploy-84b89f5f96-7xhhn --grace-period=0 --force -n web-test
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "nginx-deploy-84b89f5f96-7xhhn" force deleted
再次查看,发现又重新启动了一个新的Pod(并且IP发生了变化)
节点也可能会发生变化,这里是2副本效果不明显,可以将副本改成1再测试看看
[root@master deployment 19:02:44]# kubectl get pods -n web-test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-84b89f5f96-f2ksn 1/1 Running 0 11m 10.244.104.11 node2 <none> <none>
nginx-deploy-84b89f5f96-rmxs6 1/1 Running 0 51s 10.244.166.151 node1 <none> <none>
总结:
pod的IP不是固定的,就算把整个集群关闭再启动,pod也会自动启动,但是IP地址会发生变化
然IP地址不是固定的,所以需要一个固定的访问endpoint给用户,那么这种方式就是service,这个我们后面再详细研究
Pod版本升级(支持多副本滚动升级)
查看帮助
[root@master deployment 19:02:55]# kubectl set image -h
升级前验证nginx版本
[root@master deployment 19:06:51]# kubectl describe pod nginx-deploy-84b89f5f96-f2ksn -n web-test | grep Image:
Image: nginx:1.26-alpine
# or
[root@master deployment 19:08:28]# kubectl exec nginx-deploy-84b89f5f96-f2ksn -n web-test -- nginx -v
nginx version: nginx/1.26.3
升级到1.29版本
语法格式:kubectl set image deployment deploy_name container_name=image_level --record
[root@master deployment 19:08:37]# kubectl get deployment -n web-test
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 17m
[root@master deployment 19:10:57]# kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine --record -n web-test
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deploy image updated
# 验证
[root@master deployment 19:14:24]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-5bcb87f6cf-nm9cz 1/1 Running 0 2m48s
nginx-deploy-5bcb87f6cf-pvsvh 1/1 Running 0 2m50s
[root@master deployment 19:14:42]# kubectl exec nginx-deploy-5bcb87f6cf-nm9cz -n web-test -- nginx -v
nginx version: nginx/1.29.4
命令说明:
- deployment nginx-deploy 代表名为 deploy-nginx 的deployment
- c1=nginx:1.29-alpine 前面的 c1 为容器名
- –record 表示会记录
容器名称查看
kubectl describe pod pod_name kubectl edit deployment deploy_name kubectl get deployment deploy_name -o yaml
验证是否升级成功
[root@master deployment 19:15:04]# kubectl rollout status deployment nginx-deploy -n web-test
deployment "nginx-deploy" successfully rolled out
Pod版本回退
查看版本历史信息
[root@master deployment 19:18:29]# kubectl rollout history deployment nginx-deploy -n web-test
deployment.apps/nginx-deploy
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine --record=true --namespace=web-test
定义要回退的版本(还需要执行才能真的回退版本)
[root@master deployment 19:23:38]# kubectl rollout history deployment -n web-test nginx-deploy --revision=1
deployment.apps/nginx-deploy with revision #1
Pod Template:
Labels: app=nginx
pod-template-hash=84b89f5f96
Containers:
c1:
Image: nginx:1.26-alpine # 可以看见编号1代表能执行到1.26版本
Port: 80/TCP
Host Port: 0/TCP
Limits:
cpu: 150m
memory: 300Mi
Requests:
cpu: 100m
memory: 200Mi
Liveness: http-get http://:http/index.html delay=0s timeout=1s period=10s #success=1 #failure=3
Environment: <none>
Mounts: <none>
Volumes: <none>
执行回退
[root@master deployment 19:26:55]# kubectl rollout undo deployment -n web-test nginx-deploy --to-revision=1
deployment.apps/nginx-deploy rolled back
验证
回到了1.26版本,且revision的ID增加了
[root@master deployment 19:29:45]# kubectl rollout history deployment -n web-test nginx-deploy
deployment.apps/nginx-deploy
REVISION CHANGE-CAUSE
2 kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine --record=true --namespace=web-test
3 <none>
[root@master deployment 19:30:33]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-84b89f5f96-4lkjz 1/1 Running 0 114s
nginx-deploy-84b89f5f96-vmwsx 1/1 Running 0 112s
[root@master deployment 19:31:39]# kubectl describe pod nginx-deploy-84b89f5f96-4lkjz -n web-test | grep Image:
Image: nginx:1.26-alpine
[root@master deployment 19:33:48]# kubectl exec nginx-deploy-84b89f5f96-4lkjz -n web-test -- nginx -v
nginx version: nginx/1.26.3
Pod副本扩容
获取帮助
[root@master deployment 19:34:46]# kubectl scale -h
扩容成4副本
[root@master deployment 19:34:57]# kubectl scale deployment nginx-deploy -n web-test --replicas=4
deployment.apps/nginx-deploy scaled
# 验证
[root@master deployment 19:35:36]# kubectl get deployments -n web-test
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 4/4 4 4 44m
[root@master deployment 19:36:17]# kubectl get pods -n web-test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-84b89f5f96-4lkjz 1/1 Running 0 6m57s 10.244.104.13 node2 <none> <none>
nginx-deploy-84b89f5f96-6qrvh 1/1 Running 0 66s 10.244.104.14 node2 <none> <none>
nginx-deploy-84b89f5f96-vjn5v 1/1 Running 0 66s 10.244.166.154 node1 <none> <none>
nginx-deploy-84b89f5f96-vmwsx 1/1 Running 0 6m55s 10.244.166.153 node1 <none> <none>
Pod副本缩容
修改replicas 的参数即可
[root@master deployment 19:37:40]# kubectl scale deployment nginx-deploy -n web-test --replicas=1
deployment.apps/nginx-deploy scaled
# 验证
[root@master deployment 19:38:18]# kubectl get deployments -n web-test
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 1/1 1 1 46m
[root@master deployment 19:38:37]# kubectl get pods -n web-test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-84b89f5f96-vmwsx 1/1 Running 0 9m10s 10.244.166.153 node1 <none> <none>
副本数量可以降为0,有需要就启动,无需要就停止
[root@master deployment 19:38:57]# kubectl scale deployment nginx-deploy -n web-test --replicas=0
deployment.apps/nginx-deploy scaled
# 验证
[root@master deployment 19:39:55]# kubectl get deployments -n web-test
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 0/0 0 0 48m
[root@master deployment 19:40:07]# kubectl get pods -n web-test
No resources found in web-test namespace.
删除deployment
删除deployment,里面的Pod也会被自动删除
# 先扩容
[root@master deployment 19:40:14]# kubectl scale deployment nginx-deploy -n web-test --replicas=5
deployment.apps/nginx-deploy scaled
[root@master deployment 19:42:31]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-84b89f5f96-26f5q 1/1 Running 0 7s
nginx-deploy-84b89f5f96-4d95d 1/1 Running 0 7s
nginx-deploy-84b89f5f96-7bd8q 1/1 Running 0 7s
nginx-deploy-84b89f5f96-sh2cm 1/1 Running 0 7s
nginx-deploy-84b89f5f96-wrnlx 1/1 Running 0 7s
# 删除
[root@master deployment 19:42:38]# kubectl delete deployment -n web-test nginx-deploy
deployment.apps "nginx-deploy" deleted
# 验证
[root@master deployment 19:43:03]# kubectl get pods -n web-test
No resources found in web-test namespace.
ReplicaSet
replicaset控制器很少单独使用,不建议脱离deployment
- 支持新的基于集合的selector(以前的rc里没有这种功能)
- 通过改变Pod副本数量实现Pod的扩容和缩容
准备yaml文件
[root@master deployment 19:44:54]# vim rs-nginx.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
name: nginx
spec:
containers:
- name: c1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
应用yaml
[root@master deployment 19:45:59]# kubectl apply -f rs-nginx.yaml
replicaset.apps/rs-nginx created
# 验证
[root@master deployment 19:46:06]# kubectl get replicaset
NAME DESIRED CURRENT READY AGE
rs-nginx 2 2 2 19s
[root@master deployment 19:46:25]# kubectl get pods
NAME READY STATUS RESTARTS AGE
rs-nginx-hkwh2 1/1 Running 0 27s
rs-nginx-j7cd8 1/1 Running 0 27s
[root@master deployment 19:47:14]# kubectl get deployments
No resources found in default namespace.
找不到deployment,说明创建rs并没有创建deployment
扩容测试
[root@master deployment 19:47:23]# kubectl scale replicaset rs-nginx --replicas=4
replicaset.apps/rs-nginx scaled
# 验证
[root@master deployment 19:49:00]# kubectl get replicaset
NAME DESIRED CURRENT READY AGE
rs-nginx 4 4 4 3m1s
[root@master deployment 19:49:07]# kubectl get pods
NAME READY STATUS RESTARTS AGE
rs-nginx-d4rj4 1/1 Running 0 13s
rs-nginx-hkwh2 1/1 Running 0 3m7s
rs-nginx-j7cd8 1/1 Running 0 3m7s
rs-nginx-qrpvz 1/1 Running 0 13s
说明replicaset 可以扩缩容
版本测试
# 查看版本
[root@master deployment 19:50:11]# kubectl describe pods rs-nginx-d4rj4 | grep Image:
Image: nginx:1.26-alpine
[root@master deployment 19:51:50]# kubectl set image replicaset rs-nginx c1=nginx:1.29-alpine --record
Flag --record has been deprecated, --record will be removed in the future
replicaset.apps/rs-nginx image updated
# 检查
[root@master deployment 19:53:16]# kubectl describe pods rs-nginx-d4rj4 | grep Image:
Image: nginx:1.26-alpine
说明replicaset 可以扩缩容,版本并没发生变化,replicaset无法实现版本更新
DaemonSet
DaemonSet功能
- Daemonset能够让所有(或者特定)的节点运行同一个pod
- 当节点加入到K8s集群中,pod会被(DaemonSet)调度到该节点上运行,当节点从K8S集群中被移除,被Daemonset调度的pod会被移除
- 如果删除DaemonSet,所有跟这个DaemonSet相关的pods都会被删除
- 如果一个DaemonSet的Pod被杀死、停止、或者崩溃,那么DaemonSet将会重新创建一个新的副本在这台计算节点上
- DaemonSet一般应用于日志收集、监控采集、分布式存储守护进程等
DaemonSet用于部署守护进程
准备yaml文件
[root@master daemonset 15:21:13]# vim ds-nginx.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
name: ds-nginx
spec:
#设置污点
tolerations: # 代表容忍,保证在所有节点运行
- key: node-role.kubernetes.io/master # 能容忍的污点key
effect: NoSchedule # 能容忍的污点effect
containers:
- name: nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 100Mi
requests:
memory: 100Mi
应用yaml文件
[root@master daemonset 15:27:22]# kubectl apply -f ds-nginx.yaml
daemonset.apps/daemonset-nginx created
# 验证
[root@master daemonset 15:27:32]# kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset-nginx 2 2 2 2 2 <none> 7s
[root@master daemonset 15:27:39]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-nginx-28qf7 1/1 Running 0 63s 10.244.166.166 node1 <none> <none>
daemonset-nginx-9xzdv 1/1 Running 0 63s 10.244.104.25 node2 <none> <none>
无法进行扩缩容,可以进行版本升级
版本测试
[root@master daemonset 15:30:37]# kubectl describe pods daemonset-nginx-28qf7 | grep Image:
Image: nginx:1.26-alpine
# 升级操作
[root@master daemonset 15:39:14]# kubectl set image daemonset daemonset-nginx nginx=nginx:latest
daemonset.apps/daemonset-nginx image updated
# 验证
[root@master daemonset 15:40:31]# kubectl describe pods daemonset-nginx-hw9mf | grep Image:
Image: nginx:latest
Job
Job介绍
对于于ReplicaSet而言,它希望pod保持预期数目、持久运行下去,除非用户明确删除,否则这些对象一直存在,它们针对的是耐久性任务如web服务等
对于非耐久性任务,比如压缩文件,任务完成后,pod需要结束运行,不需要pod继续保持在系统中,这个时候就要用到Job
Job负责批量处理短暂的一次性任务(short lived one-of tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束
Job应用案例
计算圆周率2000位
编写yaml文件
[root@master job 15:48:23]# vim job-pi.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
metadata:
name: pod-pi
spec:
nodeName: node2
containers:
- name: c-pi
image: perl
imagePullPolicy: IfNotPresent
command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
restartPolicy: Never
应用yaml文件
[root@master job 15:58:29]# kubectl apply -f job-pi.yaml
job.batch/pi created
# 验证
[root@master job 15:58:35]# kubectl get job
NAME COMPLETIONS DURATION AGE
pi 1/1 6s 25s
[root@master job 15:59:00]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pi-75xzf 0/1 Completed 0 36s
# 查看结果
[root@master job 16:01:59]# kubectl logs pi-75xzf
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
创建固定次数Job
编写yaml文件
[root@master job 16:03:07]# vim job-num.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: busybox-job
spec:
completions: 10 # 执行job次数
parallelism: 2 # 执行job并发数
template:
metadata:
name: busybox-job-pod
spec:
nodeName: node2
containers:
- name: c1
image: busybox
imagePullPolicy: IfNotPresent
command: ["echo","hello"]
restartPolicy: Never
应用yaml文件
[root@master job 16:10:25]# kubectl apply -f job-num.yaml
job.batch/busybox-job created
# 验证
[root@master job 16:10:28]# kubectl get pods
NAME READY STATUS RESTARTS AGE
busybox-job-4bm4t 0/1 Completed 0 77s
busybox-job-6cnb2 0/1 Completed 0 75s
busybox-job-8h7xn 0/1 Completed 0 93s
busybox-job-dd6qw 0/1 Completed 0 74s
busybox-job-gf4xj 0/1 Completed 0 71s
busybox-job-hpfdp 0/1 Completed 0 78s
busybox-job-hzdz7 0/1 Completed 0 93s
busybox-job-kb54l 0/1 Completed 0 72s
busybox-job-mngqh 0/1 Completed 0 80s
busybox-job-vtpb8 0/1 Completed 0 69s
[root@master job 16:12:01]# kubectl get job
NAME COMPLETIONS DURATION AGE
busybox-job 10/10 27s 2m9s
# 查看输出内容
[root@master job 16:12:37]# kubectl logs busybox-job-gf4xj
hello
一次性备份MySQL数据库
通过job控制器创建应用备份mysql数据库
mysql数据库准备
[root@master job 16:22:20]# vim mysql.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-test
namespace: default
spec:
ports:
- port: 3306
name: mysql
clusterIP: None # 无头服务
selector:
app: mysql-dump # 匹配pod标签
---
apiVersion: apps/v1
kind: StatefulSet # 有状态控制器
metadata:
name: db
namespace: default
spec:
selector:
matchLabels:
app: mysql-dump
serviceName: "mysql-test"
template:
metadata:
labels:
app: mysql-dump # pod名称
spec:
nodeName: node1 # 资源创建在node1
containers:
- name: mysql # 容器名称
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD # mysql管理员密码设置
value: "abc123"
ports:
- containerPort: 3306
volumeMounts: # 数据库中数据挂载
- mountPath: "/var/lib/mysql"
name: mysql-data
volumes:
- name: mysql-data
hostPath:
path: /opt/mysqldata
应用yaml文件
[root@master job 16:48:38]# kubectl apply -f mysql.yaml
service/mysql-test unchanged
statefulset.apps/db created
# 验证
[root@master job 16:49:39]# kubectl get svc,statefulset,pod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
service/mysql-test ClusterIP None <none> 3306/TCP 4m42s
NAME READY AGE
statefulset.apps/db 1/1 81s
NAME READY STATUS RESTARTS AGE
pod/db-0 1/1 Running 0 81s
在node1节点,查看数据库目录
[root@node1 ~ 16:53:49]# cd /opt/mysqldata/
[root@node1 mysqldata 16:53:55]# ls
auto.cnf client-cert.pem ibdata1 ibtmp1 performance_schema server-cert.pem
ca-key.pem client-key.pem ib_logfile0 mysql private_key.pem server-key.pem
ca.pem ib_buffer_pool ib_logfile1 mysql.sock public_key.pem sys
创建用于实现备份任务的资源清单
[root@master job 16:54:48]# vim mysql-dump.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: mysql-dump
spec:
template:
metadata:
name: mysql-dump
spec:
nodeName: node2 # 资源城建到node2
containers:
- name: mysql-dump
image: mysql:5.7
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql_back.sql"]
volumeMounts:
- mountPath: "/root"
name: mysql-data
volumes:
- name: mysql-data
hostPath:
path: /opt/mysqldump
restartPolicy: Never
应用yaml文件
[root@master job 17:03:04]# kubectl apply -f mysql-dump.yaml
job.batch/mysql-dump created
# 验证
[root@master job 17:03:33]# kubectl get job,pods
NAME COMPLETIONS DURATION AGE
job.batch/mysql-dump 1/1 4s 42s
NAME READY STATUS RESTARTS AGE
pod/db-0 1/1 Running 0 15m
pod/mysql-dump-hr9mx 0/1 Completed 0 42s
在node2节点上查看备份的sql文件
[root@node2 ~ 17:04:25]# cd /opt/mysqldump/
[root@node2 mysqldump 17:04:35]# ls
mysql_back.sql
CronJob
类似于Linux系统的crontab,在指定的时间周期运行相关的任务
CronJob应用案例
周期性输出字符
编写yaml文件
[root@master cronjob 18:07:48]# vim cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: cronjob1
spec:
schedule: "* * * * *" # 分时日月周
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:latest
args:
- /bin/sh
- -c
- date; echo "hello kubernetes"
imagePullPolicy: IfNotPresent
restartPolicy: OnFailure
应用yaml文件
[root@master cronjob 18:22:16]# kubectl apply -f cronjob.yaml
cronjob.batch/cronjob1 created
# 验证
[root@master cronjob 18:22:39]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
cronjob1 * * * * * False 0 <none> 7s
[root@master cronjob 18:22:56]# kubectl get pod
NAME READY STATUS RESTARTS AGE
cronjob1-29488943-h7wfb 0/1 Completed 0 9s
# 查看内容
[root@master cronjob 18:23:55]# kubectl logs cronjob1-29488943-h7wfb
Sun Jan 25 10:23:00 UTC 2026
hello kubernetes
周期性备份MySQL数据库
MySQL数据库准备
[root@master cronjob 18:24:29]# vim mysql.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-test
namespace: default
spec:
ports:
- port: 3306
name: mysql
clusterIP: None
selector:
app: mysql-dump
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db
namespace: default
spec:
selector:
matchLabels:
app: mysql-dump
serviceName: "mysql-test"
template:
metadata:
labels:
app: mysql-dump
spec:
nodeName: node2
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "abc123"
ports:
- containerPort: 3306
volumeMounts:
- mountPath: "/var/lib/mysql"
name: mysql-data
volumes:
- name: msyql-data
hostPath:
path: /opt/mysqldata
应用yaml文件
[root@master cronjob 18:49:01]# kubectl apply -f mysql.yaml
service/mysql-test created
statefulset.apps/db created
# 验证
[root@master cronjob 19:23:43]# kubectl get statefulset
NAME READY AGE
db 1/1 8s
[root@master cronjob 19:23:51]# kubectl get pods
NAME READY STATUS RESTARTS AGE
db-0 1/1 Running 0 12s
编写cronjob控制mysql备份清单
[root@master cronjob 19:24:59]# vim mysql-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-dump
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
nodeName: node2
containers:
- name: c1
image: mysql:5.7
command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql`date +%Y%m%d%H%M`.sql"]
volumeMounts:
- name: mysql-data
mountPath: "/root"
restartPolicy: Never
volumes:
- name: mysql-data
hostPath:
path: /opt/mysqldump
应用yaml文件
[root@master cronjob 19:35:41]# kubectl apply -f mysql-cronjob.yaml
cronjob.batch/mysql-dump created
# 验证
# 这里需要等待一会,cronjob不是立刻就执行的
[root@master cronjob 19:37:37]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
mysql-dump */1 * * * * False 0 7s 109s
[root@master cronjob 19:38:07]# kubectl get pods
NAME READY STATUS RESTARTS AGE
db-0 1/1 Running 0 14m
mysql-dump-29489017-6fj8h 0/1 Completed 0 102s
mysql-dump-29489018-7nnsz 0/1 Completed 0 42s
# 在node2 节点查看备份内容
[root@node2 opt 19:35:34]# ls mysqldump/
mysql202601251137.sql mysql202601251138.sql mysql202601251139.sql
StatefulSet
StatefulSet功能
- Statefulset 是用来管理有状态应用的控制器
- Statefulset 用来管理应用的部署、扩缩容及滚动更新
- Statefulset 为 Pod 提供持久存储和持久标识符
官方文档: https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/statefulset/
StatefulSet用于部署有状态应用
有状态应用的特点:
- 比如MySQL
- 前后请求有关联与依赖
- 稳定的、持久的存储。(通过静态存储PV,PVC,动态存储storageclass实现)
- 稳定的、唯一的网络标识符。(无clusterIP通过headless服务实现)
- 有序的、优雅的部署和缩放
- 有序的、自动的滚动更新(从最大数更新,例如:编号2,编号1,编号0)
StatefulSet的YAML组成
三部分:
- headless service: 实现稳定,唯一的网络标识
- statefulset类型资源: 写法和deployment几乎一致,就是类型不一样
- volumeClaimTemplate:指定存储卷
创建StatefulSet类型应用
网络存储NFS部署
新建一台虚拟机作为nfs存储节点:IP 192.168.108.130
[root@nfs ~ 19:52:44]# mkdir -p /data/nfs
[root@nfs ~ 19:52:44]# vim /etc/exports
/data/nfs *(rw,no_root_squash,sync)
#解释:*允许所有用户访问 rw可读写 no_root_squash禁用安全降权规则
[root@nfs ~ 19:54:06]# systemctl restart nfs-server.service
[root@nfs ~ 19:56:16]# systemctl enable nfs-server.service
[root@nfs ~ 19:56:45]# systemctl stop firewalld.service
[root@nfs ~ 19:56:49]# setenforce 0
[root@nfs ~ 19:57:26]# showmount -e
Export list for nfs:
/data/nfs *
给所有node节点安装nfs客户端软件包
node1-2
yum install nfs-utils -y
验证nfs可用性
[root@node1 ~ 19:58:40]# showmount -e 192.168.108.130
Export list for 192.168.108.130:
/data/nfs *
[root@node2 ~ 19:58:55]# showmount -e 192.168.108.130
Export list for 192.168.108.130:
/data/nfs *
编写yaml文件
[root@master statefulset 20:00:18]# vim volume-nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: volume-nfs
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
volumeMounts:
- name: documentroot
mountPath: /usr/share/nginx/html
ports:
- containerPort: 80
volumes:
- name: documentroot
nfs:
path: /data/nfs
server: 192.168.108.130
应用yaml文件
[root@master statefulset 20:09:20]# kubectl apply -f volume-nfs.yaml
deployment.apps/volume-nfs created
# 验证
[root@master statefulset 20:09:29]# kubectl get pods
NAME READY STATUS RESTARTS AGE
volume-nfs-55c6597bd4-b5zrx 1/1 Running 0 20s
volume-nfs-55c6597bd4-r9r6l 1/1 Running 0 20s
在nfs服务器上创建index文件
[root@nfs ~ 19:57:31]# cd /data/nfs/
[root@nfs nfs 20:10:23]# ls
[root@nfs nfs 20:10:37]# echo "hello nfs storage" > index.html
在master上直接验证查看
[root@master statefulset 20:09:49]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-nfs-55c6597bd4-b5zrx 1/1 Running 0 119s 10.244.104.44 node2 <none> <none>
volume-nfs-55c6597bd4-r9r6l 1/1 Running 0 119s 10.244.166.173 node1 <none> <none>
[root@master statefulset 20:11:28]# curl http://10.244.104.44
hello nfs storage
[root@master statefulset 20:11:40]# curl http://10.244.166.173
hello nfs storage
PV(持久化存储卷)与 PVC(持久存储卷声明)
kubernetes存储卷的分类太丰富了,每种类型都要写相应的接口与参数才行,这就让维护与管理难度加大
kubernetes支持分类查看
官方文档:https://kubernetes.io/zh-cn/docs/concepts/storage/
persistenvolume(PV)是配置好的一个存储(可以是任意类型的存储卷)
- 也就是说将网络存储共享出来,配置定义成PV
PersistentVolumeClaim(PVC)是用户pod使用PV的申请请求
- 用户不需要关心具体的volume实现细节,只需要关心使用需求
pv和pvc之间的关系
- pv提供存储资源
- pvc使用存储资源
- 使用pvc绑定pv

实现nfs类型pv和pvc
创建pv的yaml文件
[root@master statefulset 20:48:02]# vim pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume # 类型pv
metadata:
name: pv-nfs
spec:
capacity:
storage: 1Gi # 大小
accessModes:
- ReadWriteMany # 访问方式
nfs:
path: /data/nfs
server: 192.168.108.130
我们要实现多个nginx跨节点之间的数据共享,所以选择ReadWriteMany模式
访问方式有三种:
官方文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
- ReadWriteOnce:单节点读写挂载
- ReadOnlyMany:多节点只读挂载
- ReadWriteMany:多节点读写挂载
- ReadWriteOncePod:卷可以被单个Pod以读写方式挂载(1.29新特性)
应用yaml文件,创建pv并验证
[root@master statefulset 21:03:37]# kubectl apply -f pv-nfs.yaml
persistentvolume/pv-nfs created
[root@master statefulset 21:03:51]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 1Gi RWX Retain Available 7s
说明:
- RWX为ReadWriteMany的简写
- Retain是回收策略
- Retain表示不使用了需要手动回收
- 官方文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaim-policy
创建pvc的yaml文件
[root@master statefulset 21:03:58]# vim pvc-nfs.yaml
apiVersion: v1
kind: PersistentVolumeClaim # 类型pvc
metadata:
name: pvc-nfs
spec:
accessModes:
- ReadWriteMany # 访问模式
resources:
requests:
storage: 1Gi # 大小与pv一致
应用yaml文件
[root@master statefulset 21:08:45]# kubectl apply -f pvc-nfs.yaml
persistentvolumeclaim/pvc-nfs created
# 验证
[root@master statefulset 21:08:47]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Bound pv-nfs 1Gi RWX 45s
创建nginx的yaml文件
[root@master statefulset 21:10:02]# vim nginx-pvc-nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-pvc-nfs
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: pvc-nfs
应用yaml文件
[root@master statefulset 21:19:42]# kubectl apply -f nginx-pvc-nfs.yaml
deployment.apps/nginx-pvc-nfs created
[root@master statefulset 21:20:56]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-pvc-nfs-5d8644564b-gqrqn 1/1 Running 0 72s 10.244.166.174 node1 <none> <none>
nginx-pvc-nfs-5d8644564b-w77mg 1/1 Running 0 72s 10.244.104.45 node2 <none> <none>
[root@master statefulset 21:21:00]# curl http://10.244.166.174
hello nfs storage
[root@master statefulset 21:21:23]# curl http://10.244.104.45
hello nfs storage
动态供给
每次使用存储要先创建pv,再创建pvc,非常的繁琐,所以我们可以实现使用存储的动态供给特性
- 静态存储需要用户申请PVC时保证容量和读写类型与预置PV的容量及读写类型完全匹配,而动态存储则无需如此
- 管理员无需预先创建大量的PV作为存储资源
Kubernetes从1.4版起引入了一个新的资源对象StorageClass,可用于将存储资源定义为具有显著特性的类(Class)而不是具体的PV。用户通过PVC直接向意向的类别发出申请,匹配由管理员事先创建的PV,或 者由其按需为用户动态创建PV,这样就免去了需要先创建PV的过程
实现动态供给部署nfs存储
官方插件不支持NFS动态供给,可以使用第三方插件来实现
第三方插件地址: https://github.com/kubernetes-retired/external-storage




创建一个新的目录
[root@master statefulset 21:38:07]# mkdir nfs-cli
[root@master statefulset 21:38:07]# cd nfs-cli/
下载class、rbac、deployment文件
wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml
wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml
wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/deployment.yaml
修改class文件
[root@master nfs-cli 21:53:39]# vim class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass # 类型
metadata:
name: nfs-client # 名称,要使用就需要调用此名称
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 动态供给插件
parameters:
archiveOnDelete: "false" # 删除数据时是否存档,false表示不存档,true表示存档
[root@master nfs-cli 21:59:52]# cp class.yaml storageclass-nfs.yaml
应用yaml文件
[root@master nfs-cli 22:00:36]# kubectl apply -f storageclass-nfs.yaml
storageclass.storage.k8s.io/nfs-client created
[root@master nfs-cli 22:00:45]# kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 19s
说明:
- RECLAIMPOLICY pv回收策略,pod或者pvc被删除后,pv是否删除还是保留
- VOLUMEBINDINGMODE Immediate模式下pvc与pv立即绑定,主要是不等待相关pod调度完成,不关心其运行节点,直接完成
- ALLOWVOLUMEEXPANSION pvc扩容 false不允许,true允许
应用rbac.yaml文件
因为storage自动创建pv需要经过kube-apiserver,所以需要授权
[root@master nfs-cli 22:03:44]# cp rbac.yaml storageclass-nfs-rbac.yaml
[root@master nfs-cli 22:03:44]# kubectl apply -f storageclass-nfs-rabc.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
修改deployment.yaml文件
需要一个deployment来专门实现pv与pvc的自动创建
[root@master nfs-cli 22:04:09]# vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0 # 替换国内镜像源
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.108.130 # nfs服务器地址
- name: NFS_PATH
value: /data/nfs # 共享目录
volumes:
- name: nfs-client-root
nfs:
server: 192.168.108.130 # nfs服务器地址
path: /data/nfs # 共享目录
应用yaml文件
[root@master nfs-cli 22:06:39]# kubectl apply -f deployment.yaml
deployment.apps/nfs-client-provisioner created
[root@master nfs-cli 22:06:47]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-69dff6bc9f-tnr5x 1/1 Running 0 8s
nginx应用使用动态供给
创建statefulSet 应用来调用名为nfs-client的storageclass,以实现动态供给
[root@master nfs-cli 22:06:55]# vim nginx-storageclass-nfs.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None # 无头服务
selector:
app: nginx # service关联pod标签
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web # 名称+编号=pod名称
spec:
serviceName: "nginx-svc" # 关联service名称
replicas: 2
selector:
matchLabels:
app: nginx # 控制器关联pod标签
template:
metadata:
labels:
app: nginx # pod标签
spec:
containers:
- name: nginx-c # 扩缩容用到的容器名
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: # pvc模板
- metadata:
name: www # 构成pvc名称
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-client"
resources:
requests:
storage: 1Gi
应用yaml文件
[root@master nfs-cli 22:23:23]# kubectl apply -f nginx-storageclass-nfs.yaml
service/nginx-svc created
statefulset.apps/web created
[root@master nfs-cli 22:23:29]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-69dff6bc9f-tnr5x 1/1 Running 0 16m
web-0 1/1 Running 0 17s
web-1 1/1 Running 0 15s
[root@master nfs-cli 22:23:46]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
nginx-svc ClusterIP None <none> 80/TCP 78s
[root@master nfs-cli 22:24:00]# kubectl get statefulset
NAME READY AGE
web 2/2 46s
查看pv状态
[root@master nfs-cli 22:24:47]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-355a273e-733f-4b2b-94d0-5734bc5204bb 1Gi RWO Delete Bound default/www-web-1 nfs-client 80s
pvc-e75af000-1841-4ad6-a1a2-8a3d69b26b22 1Gi RWO Delete Bound default/www-web-0 nfs-client 82s
查看pvc状态
[root@master nfs-cli 22:24:51]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pvc-e75af000-1841-4ad6-a1a2-8a3d69b26b22 1Gi RWO nfs-client 84s
www-web-1 Bound pvc-355a273e-733f-4b2b-94d0-5734bc5204bb 1Gi RWO nfs-client 82s
到nfs服务器查看/data/nfs目录,会发现有两个文件夹,保存两个pod网站数据
[root@nfs ~ 22:25:34]# cd /data/nfs/
[root@nfs nfs 22:25:57]# ls
default-www-web-0-pvc-e75af000-1841-4ad6-a1a2-8a3d69b26b22 default-www-web-1-pvc-355a273e-733f-4b2b-94d0-5734bc5204bb
往两个目录中分别写入index.html内容进行查看
[root@nfs nfs 22:25:59]# echo "this is web0" > default-www-web-0-pvc-e75af000-1841-4ad6-a1a2-8a3d69b26b22/index.html
[root@nfs nfs 22:27:28]# echo "this is web1" > default-www-web-1-pvc-355a273e-733f-4b2b-94d0-5734bc5204bb/index.html
# master节点查看
[root@master nfs-cli 22:24:53]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-client-provisioner-69dff6bc9f-tnr5x 1/1 Running 0 21m 10.244.166.175 node1 <none> <none>
web-0 1/1 Running 0 4m50s 10.244.104.46 node2 <none> <none>
web-1 1/1 Running 0 4m48s 10.244.166.176 node1 <none> <none>
[root@master nfs-cli 22:28:19]# curl http://10.244.104.46
this is web0
[root@master nfs-cli 22:28:35]# curl http://10.244.166.176
this is web1
使用kube-dns解析无头服务域名,可以直接看到后端pod的地址
[root@master nfs-cli 22:28:42]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 11d
metrics-server ClusterIP 10.99.68.52 <none> 443/TCP 10d
[root@master nfs-cli 22:29:39]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
nginx-svc ClusterIP None <none> 80/TCP 7m25s
[root@master nfs-cli 22:30:07]# dig -t a nginx-svc.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.16 <<>> -t a nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24089
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nginx-svc.default.svc.cluster.local. IN A
;; ANSWER SECTION:
nginx-svc.default.svc.cluster.local. 30 IN A 10.244.104.46
nginx-svc.default.svc.cluster.local. 30 IN A 10.244.166.176
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 日 1月 25 22:30:43 CST 2026
;; MSG SIZE rcvd: 166
解析pod域名
[root@master nfs-cli 22:32:43]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-69dff6bc9f-tnr5x 1/1 Running 0 26m
web-0 1/1 Running 0 9m20s
web-1 1/1 Running 0 9m18s
[root@master nfs-cli 22:32:49]# dig -t a web-0.nginx-svc.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.16 <<>> -t a web-0.nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28705
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web-0.nginx-svc.default.svc.cluster.local. IN A
;; ANSWER SECTION:
web-0.nginx-svc.default.svc.cluster.local. 30 IN A 10.244.104.46 `看这里`
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 日 1月 25 22:33:06 CST 2026
;; MSG SIZE rcvd: 127
[root@master nfs-cli 22:33:06]# dig -t a web-1.nginx-svc.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.16 <<>> -t a web-1.nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53549
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web-1.nginx-svc.default.svc.cluster.local. IN A
;; ANSWER SECTION:
web-1.nginx-svc.default.svc.cluster.local. 30 IN A 10.244.166.176 `看这里`
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 日 1月 25 22:33:13 CST 2026
;; MSG SIZE rcvd: 127
创建一个测试pod,观察负载均衡
[root@master nfs-cli 22:35:00]# kubectl run -it centos --image=centos:7 --image-pull-policy=IfNotPresent
If you don't see a command prompt, try pressing enter.
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is web0
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is web0
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is web1
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is web1
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
直接访问pod域名
[root@centos /]# curl http://web-0.nginx-svc.default.svc.cluster.local.
this is web0
[root@centos /]# curl http://web-1.nginx-svc.default.svc.cluster.local.
this is web1
金丝雀发布更新(灰度发布)
它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod
Statefulset可以使用partition参数来实现金丝雀更新,partition参数可以控制StatefulSet控制器更新的 Pod,下面,就进行StatefulSet控制器的金丝雀更新实战
[root@master nfs-cli 13:49:21]# kubectl get sts web -o yaml
...
updateStrategy:
rollingUpdate:
partition: 0 #默认分区号0,表示更新0及大于0的所有pod
type: RollingUpdate
...
使用patch参数来指定statefulset控制器的partition参数为1,表示当更新时,只有Pod编号大于等于1的才更新
修改更新
[root@master nfs-cli 13:59:04]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'
# 再次观察,查看patch参数
...
updateStrategy:
rollingUpdate:
partition: 1
type: RollingUpdate
...
查看当前版本
[root@master nfs-cli 13:59:04]# kubectl describe pod web-0 | grep Image:
Image: nginx:1.26-alpine
[root@master nfs-cli 14:01:06]# kubectl describe pod web-1 | grep Image:
Image: nginx:1.26-alpine
更新版本
[root@master nfs-cli 14:02:23]# kubectl set image sts/web nginx-c=nginx:1.29-alpine
statefulset.apps/web image updated
再次查看版本,发现只有web-1的进行了更新
[root@master nfs-cli 14:03:05]# kubectl describe pod web-0 | grep Image:
Image: nginx:1.26-alpine
[root@master nfs-cli 14:03:33]# kubectl describe pod web-1 | grep Image:
Image: nginx:1.29-alpine
查看pod版本列表
[root@master nfs-cli 14:03:38]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-69dff6bc9f-rtkw7 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.29-alpine
扩容数量为4,观察版本更新,发现新增的pod都使用新版本镜像
[root@master nfs-cli 14:06:03]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-69dff6bc9f-rtkw7 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.29-alpine
web-2 nginx:1.29-alpine
web-3 nginx:1.29-alpine
缩容数量为1,观察版本变化
[root@master nfs-cli 14:06:54]# kubectl scale sts web --replicas=1
statefulset.apps/web scaled
[root@master nfs-cli 14:08:24]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-69dff6bc9f-rtkw7 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
发现就剩原来老版本的pod,说明位置没变,不可变的基础设置,再次扩容,观察版本
[root@master nfs-cli 14:08:32]# kubectl scale sts web --replicas=6
statefulset.apps/web scaled
[root@master nfs-cli 14:10:53]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-69dff6bc9f-rtkw7 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.29-alpine
web-2 nginx:1.29-alpine
web-3 nginx:1.29-alpine
web-4 nginx:1.29-alpine
web-5 nginx:1.29-alpine
可以看见扩容依旧按照partition的位置部署新版本
实现全部更新
[root@master nfs-cli 14:12:52]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
statefulset.apps/web patched
[root@master nfs-cli 14:14:00]# kubectl set image sts/web nginx-c=nginx:1.29-alpine
[root@master nfs-cli 14:15:07]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-69dff6bc9f-rtkw7 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.29-alpine
web-1 nginx:1.29-alpine
web-2 nginx:1.29-alpine
web-3 nginx:1.29-alpine
web-4 nginx:1.29-alpine
web-5 nginx:1.29-alpine
总结
| 控制器类型 | 版本升级/回退 | 副本扩容/缩减 |
|---|---|---|
| Deployment | 是 | 是 |
| ReplicaSet | 否 | 是 |
| DaemonSet | 是 | 否 |
| StatefulSet | 是 | 是 |

59

被折叠的 条评论
为什么被折叠?



