52.k8s的controller管理-4
第4部:controller核心管理
控制器controller
1:controller作用及分类
controller用于控制pod
官方文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/

控制器主要分为:
- Deployments 部署无状态应用,控制pod升级,回退
- ReplicaSet 副本集,控制pod扩容,裁减
- ReplicationController (相当于ReplicaSet的老版本,现在建议使用Deployments加ReplicaSet替代 RC)
- StatefulSets 部署有状态应用,结合Service、存储等实现对有状态应用部署
- DaemonSet 守护进程集,运行在所有集群节点(包括master),比如使用filebeat,node_exporter
- Jobs 一次性
- Cronjob 周期性
2:Deployment
Replicaset控制器的功能
- 支持新的基于集合的selector(以前的rc里没有这种功能)
- 通过改变Pod副本数量实现Pod的扩容和缩容
Deployment控制器的功能
- Deployment集成了上线部署、滚动升级、创建副本、回滚等功能
- Deployment里包含并使用了ReplicaSet
Deployment用于部署无状态应用
无状态应用的特点:
- 所有pod无差别
- 所有pod中容器运行同一个image
- 所有pod可以运行在集群中任意node上
- 所有pod无启动顺序先后之分
- 随意pod数量扩容或缩容
创建deployment类型应用
1:准备YAML文件 获取帮助
[root@docker-master pod.dir]# kubectl explain deployment
GROUP: apps
KIND: Deployment
VERSION: v1
......
编写文件
[root@docker-master pod.dir]# vim nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy #deployment名称
namespace: web-test
spec:
# 副本控制
replicas: 2 #副本集,deployment里使用了replicaset
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:
requests:
cpu: 100m
memory: 200Mi
limits:
cpu: 150m
memory: 300Mi
# 存活探针
livenessProbe:
httpGet:
port: http
path: /index.html
2:应用YAML文件
[root@docker-master pod.dir]# kubectl create ns web-test
namespace/web-test created
[root@docker-master pod.dir]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deploy created
3:验证
[root@docker-master pod.dir]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-84b89f5f96-6vbsv 1/1 Running 0 13m
nginx-deploy-84b89f5f96-bbqsc 1/1 Running 0 13m
查看deployment名称
[root@docker-master pod.dir]# kubectl get deployment -n web-test
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 34s
查看replicaset名称
[root@docker-master pod.dir]# kubectl get replicaset -n web-test
NAME DESIRED CURRENT READY AGE
nginx-deploy-84b89f5f96 2 2 2 14m
访问deployment
1:查看pod的IP地址
[root@docker-master pod.dir]# kubectl get pod -o wide -n web-test
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-84b89f5f96-6vbsv 1/1 Running 0 14m 10.244.248.173 docker-node2 <none> <none>
nginx-deploy-84b89f5f96-bbqsc 1/1 Running 0 14m 10.244.148.223 docker-node1 <none> <none>
2:查看所有集群节点的网卡
[root@docker-master pod.dir]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.219.64 netmask 255.255.255.255
[root@docker-node1 ~]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.148.192 netmask 255.255.255.255
[root@docker-node2 ~]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.248.128 netmask 255.255.255.255
总结:可以看到所有集群节点的IP为10.244.0.0/16这个大网段内的子网
3:在任意集群节点上都可以访问此deploy里的pod
[root@docker-master pod.dir]# ping -c 2 10.244.248.173
PING 10.244.248.173 (10.244.248.173) 56(84) bytes of data.
64 bytes from 10.244.248.173: icmp_seq=1 ttl=63 time=0.886 ms
64 bytes from 10.244.248.173: icmp_seq=2 ttl=63 time=0.695 ms
--- 10.244.248.173 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1003ms
rtt min/avg/max/mdev = 0.695/0.790/0.886/0.099 ms
[root@docker-master pod.dir]# curl http://10.244.248.173
<!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
1:强制删除pod(注意:是删除deployment中的pod)
[root@docker-master pod.dir]# kubectl delete pod nginx-deploy-84b89f5f96-6vbsv -n web-test --grace-period=0 --force
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-6vbsv" force deleted
2:再次查看,发现又重新启动了一个pod(节点发生变化,IP发生变化)
[root@docker-master pod.dir]# kubectl get pod -o wide -n web-test
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-84b89f5f96-bbqsc 1/1 Running 0 21m 10.244.148.223 docker-node1 <none> <none>
nginx-deploy-84b89f5f96-nsb95 1/1 Running 0 5s 10.244.248.174 docker-node2 <none> <none>
总结:pod的IP不是固定的,就算把整个集群关闭再启动,pod也会自动启动,但是IP地址会发生变化 既然IP地址不是固定的,所以需要一个固定的访问endpoint给用户,那么这种方式就是service
pod版本升级
查看帮助
[root@docker-master pod.dir]# kubectl set -h
Configure application resources.
These commands help you make changes to existing application resources.
Available Commands:
env Update environment variables on a pod template
image Update the image of a pod template
resources 使用 Pod 模板更新对象的资源请求/限制
selector 为资源设置选择器
serviceaccount Update the service account of a resource
subject Update the user, group, or service account in a role binding or cluster role
binding
Usage:
kubectl set SUBCOMMAND [options]
Use "kubectl set <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).
升级前验证nginx版本
[root@docker-master pod.dir]# kubectl get pod -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-84b89f5f96-bbqsc 1/1 Running 1 (6m24s ago) 17h
nginx-deploy-84b89f5f96-nsb95 1/1 Running 1 (6m19s ago) 17h
[root@docker-master pod.dir]# kubectl describe pods nginx-deploy-84b89f5f96-bbqsc -n web-test | grep Image
Image: nginx:1.26-alpine
Image ID: docker-pullable://nginx@sha256:1eadbb07820339e8bbfed18c771691970baee292ec4ab2558f1453d26153e22d
[root@docker-master pod.dir]# kubectl exec nginx-deploy-84b89f5f96-bbqsc -n web-test -- nginx -v
nginx version: nginx/1.26.3
升级为1.29版本
# 查看控制器名称
[root@docker-master pod.dir]# kubectl get deploy -n web-test
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 2/2 2 2 18h
[root@docker-master pod.dir]# kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine -n web-test --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deploy image updated
[root@docker-master pod.dir]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-5bcb87f6cf-4f54f 0/1 ContainerCreating 0 20s
nginx-deploy-84b89f5f96-bbqsc 1/1 Running 1 (27m ago) 18h
nginx-deploy-84b89f5f96-nsb95 1/1 Running 1 (26m ago) 17h
[root@docker-master pod.dir]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-5bcb87f6cf-4f54f 1/1 Running 0 2m8s
nginx-deploy-5bcb87f6cf-zqxrt 1/1 Running 0 88s
升级原则:Pod先创建再删除
[root@docker-master pod.dir]# kubectl exec nginx-deploy-5bcb87f6cf-4f54f -n web-test -- nginx -v
nginx version: nginx/1.29.4
说明:
- deployment nginx-deploy代表名为nginx-deploy的deployment
- c1=nginx:1.29-a1pine前面的c1为容器名
- –record 表示会记录
容器名怎么查看?
kubectl describe pod pod名查看kubectl edit deployment deployment名来查看容器名kubectl get deployment deployment名 -o yaml来查看容器名
验证
如果升级的pod数量较多,则需要一定时间,可通过下面命令查看是否已经成功
[root@docker-master pod.dir]# kubectl rollout status deployment nginx-deploy -n web-test
deployment "nginx-deploy" successfully rolled out
pod版本回退
1:查看版本历史信息
[root@docker-master pod.dir]# 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 --namespace=web-test --record=true
2:定义要回退的版本(还需要执行才是真的回退版本)
[root@docker-master pod.dir]# kubectl rollout history deployment nginx-deploy -n web-test --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>
3:执行回退
[root@docker-master pod.dir]# kubectl rollout undo deployment nginx-deploy -n web-test --to-revision=1
deployment.apps/nginx-deploy rolled back
4:验证
回到了1.26版本,但version的ID 变了
[root@docker-master pod.dir]# kubectl rollout history deployment nginx-deploy -n web-test
deployment.apps/nginx-deploy
REVISION CHANGE-CAUSE
2 kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine --namespace=web-test --record=true
3 <none>
[root@docker-master pod.dir]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-84b89f5f96-dts94 1/1 Running 0 50s
nginx-deploy-84b89f5f96-xgxjm 1/1 Running 0 48s
[root@docker-master pod.dir]# kubectl describe pods nginx-deploy-84b89f5f96-dts94 -n web-test | grep Image
Image: nginx:1.26-alpine
Image ID: docker-pullable://nginx@sha256:1eadbb07820339e8bbfed18c771691970baee292ec4ab2558f1453d26153e22d
[root@docker-master pod.dir]# kubectl exec nginx-deploy-84b89f5f96-dts94 -n web-test -- nginx -v
nginx version: nginx/1.26.3
副本扩容
获取帮助
[root@docker-master pod.dir]# kubectl scale -h
1:扩容为3个副本
[root@docker-master pod.dir]# kubectl scale deployment nginx-deploy -n web-test --replicas=3
deployment.apps/nginx-deploy scaled
若故障现象:一直处于ContainerCreating状态
原因:由于网络插件 (Calico)未能正确设置 Pod 网络,导致创建 Pod 时出现了 FailedCreatePodSandBox 错误。
解决方法:由于 Calico 插件出现暂时性故障,可以尝试重启 Calico 组件来解决
[root@docker-master pod.dir]# kubectl rollout restart daemonset calico-node -n kube-system
2:查看
[root@docker-master pod.dir]# kubectl get pods -o wide -n web-test
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-84b89f5f96-2pnql 1/1 Running 0 59s 10.244.248.178 docker-node2 <none> <none>
nginx-deploy-84b89f5f96-dts94 1/1 Running 0 34m 10.244.248.177 docker-node2 <none> <none>
nginx-deploy-84b89f5f96-xgxjm 1/1 Running 0 34m 10.244.148.229 docker-node1 <none> <none>
副本裁减
1:指定副本数为1进行裁减
[root@docker-master pod.dir]# kubectl scale deployment nginx-deploy -n web-test --replicas=1
deployment.apps/nginx-deploy scaled
2:查看验证
[root@docker-master pod.dir]# kubectl get pods -o wide -n web-test
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-84b89f5f96-xgxjm 1/1 Running 0 37m 10.244.148.229 docker-node1 <none> <none>
副本数量可以降为0,有需要就启动,无需要就停止
[root@docker-master pod.dir]# kubectl scale deployment nginx-deploy -n web-test --replicas=0
deployment.apps/nginx-deploy scaled
查看
[root@docker-master pod.dir]# kubectl get deploy -n web-test
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 0/0 0 0 19h
[root@docker-master pod.dir]# kubectl get pods -o wide
No resources found in default namespace.
多副本滚动更新
1:先扩容多副本
[root@docker-master pod.dir]# kubectl scale deployment nginx-deploy -n web-test --replicas=16
deployment.apps/nginx-deploy scaled
2:验证
[root@docker-master pod.dir]# kubectl get pods -n web-test
NAME READY STATUS RESTARTS AGE
nginx-deploy-84b89f5f96-248qv 1/1 Running 0 25s
nginx-deploy-84b89f5f96-2kdsc 1/1 Running 0 25s
nginx-deploy-84b89f5f96-5hqzj 1/1 Running 0 25s
nginx-deploy-84b89f5f96-6zkdt 1/1 Running 0 25s
nginx-deploy-84b89f5f96-85hg6 1/1 Running 0 25s
nginx-deploy-84b89f5f96-b2m4r 1/1 Running 0 25s
nginx-deploy-84b89f5f96-c4585 1/1 Running 0 25s
nginx-deploy-84b89f5f96-c4bx7 1/1 Running 0 25s
nginx-deploy-84b89f5f96-clnzl 1/1 Running 0 25s
nginx-deploy-84b89f5f96-gc2s2 1/1 Running 0 25s
nginx-deploy-84b89f5f96-j52gz 1/1 Running 0 25s
nginx-deploy-84b89f5f96-mvk25 1/1 Running 0 25s
nginx-deploy-84b89f5f96-phk8k 1/1 Running 0 25s
nginx-deploy-84b89f5f96-sjrwb 1/1 Running 0 25s
nginx-deploy-84b89f5f96-w59gb 1/1 Running 0 25s
nginx-deploy-84b89f5f96-z2cnq 1/1 Running 0 25s
3:滚动更新
[root@docker-master pod.dir]# kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine -n web-test --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deploy image updated
4:验证
# 查看Pod名称
[root@docker-master pod.dir]# kubectl get pod -n web-test
[root@docker-master pod.dir]# kubectl describe pod nginx-deploy-5bcb87f6cf-27qkt -n web-test | grep Image
Image: nginx:1.29-alpine
Image ID: docker-pullable://nginx@sha256:b0f7830b6bfaa1258f45d94c240ab668ced1b3651c8a222aefe6683447c7bf55
[root@docker-master pod.dir]# kubectl rollout status deployment nginx-deploy -n web-test
deployment "nginx-deploy" successfully rolled out
删除deployment
删除deployment,里面的pod也会被自动删除
[root@docker-master pod.dir]# kubectl delete deployment nginx-deploy -n web-test
deployment.apps "nginx-deploy" deleted
# 也可以通过删除命名空间全部删除
[root@docker-master pod.dir]# kubectl delete ns web-test
[root@docker-master pod.dir]# kubectl get pod -n web-test
No resources found in web-test namespace.
3:ReplicaSet
提醒:replicaset控制器很少单独使用,不建议脱离deployment
1:编写YAML文件
[root@docker-master controllers_dir]# vim nginx-replicas.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-rc
namespace: default
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: c1
image: nginx:1.26-alpine
ports:
- name: http
containerPort: 80
2:应用YAML文件
[root@docker-master controllers_dir]# kubectl apply -f nginx-replicas.yaml
replicaset.apps/nginx-rc created
3:验证
[root@docker-master controllers_dir]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-rc 4 4 4 24s
[root@docker-master controllers_dir]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-rc-4m8xc 1/1 Running 0 34s
nginx-rc-4n45p 1/1 Running 0 34s
nginx-rc-sx8nv 1/1 Running 0 34s
nginx-rc-zqkrw 1/1 Running 0 34s
[root@docker-master controllers_dir]# kubectl get deployment
No resources found in default namespace.
说明:找不到deployment,说明创建rs并没有创建deployment
是否能扩容,这里先获取帮助信息
[root@docker-master controllers_dir]# kubectl scale -h
进行扩容
[root@docker-master controllers_dir]# kubectl scale replicaset nginx-rc --replicas=2
replicaset.apps/nginx-rc scaled
查看副本数量
[root@docker-master controllers_dir]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-rc 2 2 2 72m
[root@docker-master controllers_dir]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-rc-sx8nv 1/1 Running 0 2m12s
nginx-rc-zqkrw 1/1 Running 0 2m12s
版本升级
[root@docker-master controllers_dir]# kubectl describe pod nginx-rc-sx8nv | grep Image:
Image: nginx:1.26-alpine
[root@docker-master controllers_dir]# kubectl set image replicaset nginx-rc c1=nginx:1.29-alpine --record
Flag --record has been deprecated, --record will be removed in the future
replicaset.apps/nginx-rc image updated
检查,版本并没发生变化,replicaset无法实现版本更新
[root@docker-master controllers_dir]# kubectl describe pod nginx-rc-sx8nv | grep Image:
Image: nginx:1.26-alpine
控制器controller进阶
1:DaemonSet
DaemonSet介绍
- Daemonset能够让所有(或者特定)的节点运行同一个pod。
- 当节点加入到K8s集群中,pod会被(DaemonSet)调度到该节点上运行,当节点从K8S集群中被移 除,被Daemonset调度的pod会被移除。
- 如果删除DaemonSet,所有跟这个DaemonSet相关的pods都会被删除。
- 如果一个DaemonSet的Pod被杀死、停止、或者崩溃,那么DaemonSet将会重新创建一个新的副 本在这台计算节点上。
- DaemonSet一般应用于日志收集、监控采集、分布式存储守护进程等。
DaemonSet应用案例
1:编写YAML文件
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
# 添加污点,master节点不创建守护进程Pod
tolerations: #代表容忍,保证在所有节点运行
- key: node-role.kubernetes.io/master #能容忍的污点key
effect: NoSchedule #能容忍的污点effect
containers:
- name: c1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
resources: #资源限制是为了防止节点资源被占太多(根据实际情况配置)
limits:
memory: 100Mi
requests:
memory: 100Mi
说明:
tolerations:
- key:污点的唯一标识,用于精确匹配节点对应的taint key,格式:node-role.kubernetes.io/<角色名>
- effect:污点的限制行为
- NoSchedule:只限制新的Pod,已运行的Pod不受影响
- PreferNoSchedule:软限制,尽量不调度,集群资源不足时,可以调度
- NoExecute:最严格,既不允许新的Pod调度,还会驱逐已运行的不匹配的Pod
2:应用YAML文件
[root@docker-master controllers_dir]# kubectl apply -f nginx-ds.yaml
daemonset.apps/nginx-ds created
3:验证
没有设置副本数量为什么会创建2个Pod
daemonset作用:确保每个副本至少运行一个Pod副本。该集群有2个node节点,故创建了2个Pod
[root@docker-master controllers_dir]# kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
nginx-ds 2 2 2 2 2 <none> 21s
[root@docker-master controllers_dir]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-ds-ljlfr 1/1 Running 0 41s 10.244.148.248 docker-node1 <none> <none>
nginx-ds-xnzv7 1/1 Running 0 41s 10.244.248.135 docker-node2 <none> <none>
无法进行扩缩容
[root@docker-master controllers_dir]# kubectl scale daemonset nginx-ds --replicas=4
Error from server (NotFound): the server could not find the requested resource
可以进行版本升级
[root@docker-master controllers_dir]# kubectl describe pods nginx-ds-ljlfr | grep Image:
Image: nginx:1.26-alpine
升级操作
[root@docker-master controllers_dir]# kubectl set image daemonset nginx-ds c1=nginx:1.29-alpine
daemonset.apps/nginx-ds image updated
验证,更新到1.29版本
[root@docker-master controllers_dir]# kubectl describe pods nginx-ds-s689j | grep Image
Image: nginx:1.29-alpine
2:Job
job介绍
- 对于ReplicaSet而言,它希望pod保持预期数目、持久运行下去,除非用户明确删除,否则这些对 象一直存在,它们针对的是耐久性任务如web服务等。
- 对于非耐久性任务,比如压缩文件,任务完成后,pod需要结束运行,不需要pod继续保持在系统 中,这个时候就要用到job。
- job负责批量处理短暂的一次性任务(short lived one-of tasks),即仅执行一次的任务,它保证批处 理任务的一个或多个Pod成功结束。
job应用案例
计算圆周率2000位
1:编写YAML文件
[root@docker-master controllers_dir]# vim job-pi.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pod-pi
spec:
template:
metadata:
name: pi
spec:
nodeName: docker-node2
containers:
- name: c1
image: perl
imagePullPolicy: IfNotPresent
command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
restartPolicy: Never
2:应用YAML文件创建job
[root@docker-master controllers_dir]# kubectl apply -f job-pi.yaml
job.batch/pod-pi created
3:验证
[root@docker-master controllers_dir]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-dump-gsf2x 0/1 Completed 0 49m
mysql-pod-0 1/1 Running 0 75m
pod-pi-g6d74 0/1 Completed 0 9s
[root@docker-master controllers_dir]# kubectl logs pod-pi-g6d74
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
创建固定次数job
1:编写YAML
[root@docker-master controllers_dir]# vim job-num.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job-hello
spec:
completions: 10 # 执行job的次数
parallelism: 1 # 执行job的并发数
template:
metadata:
name: hello
spec:
containers:
- name: c1
image: busybox
imagePullPolicy: IfNotPresent
command: ["echo","hello"]
restartPolicy: Never
2:应用YAML文件创建job
[root@docker-master controllers_dir]# kubectl apply -f job-num.yaml
job.batch/job-hello created
3:验证
[root@docker-master controllers_dir]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-hello-2svsk 0/1 Completed 0 59s
job-hello-82sft 0/1 Completed 0 68s
job-hello-9ck4q 0/1 Completed 0 62s
job-hello-d8xrs 0/1 Completed 0 50s
job-hello-hqc7q 0/1 Completed 0 53s
job-hello-ng6hh 0/1 Completed 0 47s
job-hello-rmbjr 0/1 Completed 0 65s
job-hello-sb7nh 0/1 Completed 0 44s
job-hello-vwmkr 0/1 Completed 0 56s
job-hello-w75cf 0/1 Completed 0 72s
[root@docker-master controllers_dir]# kubectl get job
NAME COMPLETIONS DURATION AGE
job-hello 10/10 31s 83s
查看输出内容
[root@docker-master controllers_dir]# kubectl logs job-hello-2svsk
hello
logs后面跟Pod名称,查看的是容器日志
一次性备份MySQL数据库
通过job控制器创建应用备份MySQL数据库
1:MySQL数据库准备
[root@docker-master controllers_dir]# vim mysql.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
spec:
ports:
- port: 3306
name: mysql
clusterIP: None #无头服务
selector:
app: mysql-dump #匹配pod名称
---
apiVersion: apps/v1 #有状态控制器
kind: StatefulSet
metadata:
name: mysql-pod
spec:
selector:
matchLabels:
app: mysql-dump
serviceName: mysql-svc
template:
metadata:
labels:
app: mysql-dump #pod名称
spec:
nodeName: docker-node2 #资源创建到docker-node2
containers:
- name: c1 #容器名称
image: mysql:5.7
imagePullPolicy: IfNotPresent
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
创建用于实现任务的资源清单文件
[root@docker-master controllers_dir]# kubectl apply -f mysql.yaml
service/mysql-svc unchanged
statefulset.apps/mysql-pod created
查看资源
[root@docker-master controllers_dir]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-pod-0 1/1 Running 0 28s 10.244.248.146 docker-node2 <none> <none>
[root@docker-master controllers_dir]# kubectl get statefulsets
NAME READY AGE
mysql-pod 1/1 46s
运行在docker-node2节点,可以查看docker-node2节点数据库目录
[root@docker-node2 ~]# ls /opt/mysqldata
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@docker-master controllers_dir]# vim mysql-dump.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: mysql-dump
spec:
template:
metadata:
name: mysql-bk
spec:
restartPolicy: Never
nodeName: docker-node1
containers:
- name: c1
image: mysql:5.7
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","mysqldump --host=mysql-svc -uroot -pabc123 --databases mysql > /root/mysql_bak.sql"]
volumeMounts:
- mountPath: "/root"
name: mysql-dump-data01
volumes:
- name: mysql-dump-data
hostPath:
path: /opt/mysqldump
应用文件
[root@docker-master controllers_dir]# kubectl apply -f mysql-dump.yaml
job.batch/mysql-dump created
验证
[root@docker-master controllers_dir]# kubectl get job
NAME COMPLETIONS DURATION AGE
mysql-dump 1/1 4s 12s
在docker-node1节点上查看备份sql文件
[root@docker-node1 ~]# ls /opt/mysqldump
mysql_bak.sql
3:cronjob
类似于Linux系统的crontab,在指定的时间周期运行相关的任务
案例:
周期性输出字符
1:编写YAML文件
[root@docker-master controllers_dir]# vim cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: pod-cronjob
spec:
schedule: "* * * * *" #分时日月周
jobTemplate:
spec:
template:
spec:
nodeName: docker-node2
containers:
- name: c1
image: busybox
imagePullPolicy: IfNotPresent
args:
- /bin/sh
- -c
- date;echo hello kubernetes
restartPolicy: OnFailure
2:应用YAML文件创建cronjob
[root@docker-master controllers_dir]# kubectl apply -f cronjob.yaml
cronjob.batch/pod-cronjob created
3:查看验证
[root@docker-master controllers_dir]# kubectl get cj # cj:cronjob的缩写
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
pod-cronjob * * * * * False 0 34s 2m25s
[root@docker-master controllers_dir]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod-cronjob-29482643-r64nm 0/1 Completed 0 78s # 每隔一分钟创建一个Pod
pod-cronjob-29482644-tvmhj 0/1 Completed 0 18s
[root@docker-master controllers_dir]# kubectl delete -f cronjob.yaml
cronjob.batch "pod-cronjob" deleted
周期性备份MySQL数据库
MySQL数据库准备
1:准备YAML文件
[root@docker-master controllers_dir]# vim mysql.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
spec:
ports:
- port: 3306
name: mysql
clusterIP: None
selector:
app: mysql-dump
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-pod
spec:
selector:
matchLabels:
app: mysql-dump
serviceName: mysql-svc
template:
metadata:
labels:
app: mysql-dump
spec:
nodeName: docker-node2
containers:
- name: c1
image: mysql:5.7
imagePullPolicy: IfNotPresent
env:
- name: MYSQL_ROOT_PASSWORD
value: "abc123"
ports:
- containerPort: 3306
volumeMounts:
- mountPath: "/var/lib/mysql"
name: mysql-data
volumes:
- name: mysql-data
hostPath:
path: /opt/mysqldata
2:运行YAML文件
[root@docker-master controllers_dir]# kubectl apply -f mysql.yaml
service/mysql-svc created
statefulset.apps/mysql-pod created
3:验证
[root@docker-master controllers_dir]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-pod-0 1/1 Running 0 49m
4:cronjob控制器类型应用资源清单文件
[root@docker-master controllers_dir]# vim mysql-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-cronjob
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
nodeName: docker-node1
containers:
- name: c1
image: mysql:5.7
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","mysqldump --host=mysql-svc -uroot -pabc123 --databases mysql > /root/mysql`date +%Y%m%d%H%M`.sql"]
volumeMounts:
- name: mysql-cronjob-data
mountPath: "/root"
restartPolicy: Never
volumes:
- name: mysql-cronjob-data
hostPath:
path: /opt/mysql_cronjob
schedule: "*/1 * * * *"表示每一分钟,如果是 schedule: "1 * * * *"表示第一分钟
5:执行应用资源文件
[root@docker-master controllers_dir]# kubectl apply -f mysql-cronjob.yaml
cronjob.batch/mysql-cronjob created
6:查看结果
[root@docker-master controllers_dir]# kubectl get cj
\NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
mysql-cronjob */1 * * * * False 0 14s 35s
[root@docker-master controllers_dir]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-cronjob-29482672-nzglz 0/1 Completed 0 27s
mysql-pod-0 1/1 Running 0 26m
[root@docker-master controllers_dir]# kubectl logs mysql-cronjob-29482672-nzglz
mysqldump: [Warning] Using a password on the command line interface can be insecure.
在docker-node1节点查看mysql备份文件
[root@docker-node1 ~]# ls /opt/mysql_cronjob
mysql202601210207.sql mysql202601210208.sql
控制器controller之StatefulSet
statefulset控制器作用
- Statefulset 是用来管理有状态应用的控制器。
- Statefulset 用来管理应用的部署、扩缩容及滚动更新。
- Statefulset 为 Pod 提供持久存储和持久标识符。
参考文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/statefulset/
无状态应用与有状态应用
1:无状态应用
- 如nginx
- 请求本身包含了响应端为响应这一请求所需的全部信息。每一个请求都像首次执行一样,不会依赖 之前的数据进行响应。
- 不需要持久化的数据
- 无状态应用的多个实例之间互不依赖,可以无序的部署、删除或伸缩
2:有状态应用
- 如MySQL
- 前后请求有关联与依赖
- 需要持久化的数据
- 有状态应用的多个实例之间有依赖,不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。
StatefulSet的特点
- 稳定的、唯一的网络标识符。(无clusterIP通过headless服务实现)
- 稳定的、持久的存储。(通过静态存储PV,PVC,动态存储storageclass实现)
- 有序的、优雅的部署和缩放
- 有序的、自动的滚动更新(从最大数更新,例如:编号2,编号1,编号0)。
StatefulSet的YAML组成
需要三个组成部分:
- headless service: 实现稳定,唯一的网络标识。
- statefulset类型资源: 写法和deployment几乎一致,就是类型不一样。
- volumeClaimTemplate:指定存储卷。
补充:无头服务是指没有cluster-IP,其通过域名解析
创建StatefulSet应用
参考文档:https://kubernetes.io/zh-cn/docs/tutorials/stateful-application/basic-stateful-set/
网络存储NFS部署
1:nfs服务器,地址192.168.108.33
CentOS 7 模版创建
[root@nfs ~]# yum install -y nfs-utils
[root@nfs ~]# mkdir -p /data/nfs
[root@nfs ~]# vim /etc/exports
# 解析:*允许所有用户访问 rw可读写 no_root_squash禁用安全降权规则。
/data/nfs *(rw,no_root_squash,sync)
[root@nfs ~]# systemctl restart nfs-server.service
[root@nfs ~]# systemctl enable nfs-server.service
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
[root@nfs ~]# showmount -e
Export list for nfs:
/data/nfs *
2:所有node节点安装nfs客户端软件包
[root@docker-node1 ~]# yum install -y nfs-utils
[root@docker-node2 ~]# yum install -y nfs-utils
3:验证nfs可用性
[root@docker-node1 ~]# showmount -e 192.168.108.33
Export list for 192.168.108.33:
/data/nfs *
[root@docker-node2 ~]# showmount -e 192.168.108.33
Export list for 192.168.108.33:
/data/nfs *
4:master节点上创建yaml文件
[root@docker-master controllers_dir]# vim nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: c1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
# 挂载
volumeMounts:
- name: nfs-data
mountPath: /usr/share/nginx/html # 容器内网页目录
restartPolicy: Always
volumes:
- name: nfs-data
nfs:
path: /data/nfs # 共享目录
server: 192.168.108.33
5:应用yaml文件
[root@docker-master controllers_dir]# kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deploy created
6:查看存储pod
[root@docker-master controllers_dir]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deploy-767f8b4f98-g2zkd 1/1 Running 0 30s
nginx-deploy-767f8b4f98-jfjs5 1/1 Running 0 30s
7:在nfs服务器上创建index文件
[root@nfs ~]# cd /data/nfs
[root@nfs nfs]# ls
[root@nfs nfs]# echo "hello nfs storage" > index.html
8:在master上可以直接验证查看
[root@docker-master controllers_dir]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deploy-767f8b4f98-g2zkd 1/1 Running 0 2m3s 10.244.148.202 docker-node1 <none> <none>
nginx-deploy-767f8b4f98-jfjs5 1/1 Running 0 2m3s 10.244.248.157 docker-node2 <none> <none>
[root@docker-master controllers_dir]# curl http://10.244.148.202
hello nfs storage
[root@docker-master controllers_dir]# curl http://10.244.248.157
hello nfs storage
PV(持久化存储卷)与 PVC(持久存储卷声明)
kubernetes存储卷的分类太丰富了,每种类型都要写相应的接口与参数才行,这就让维护与管理难度加 大。
kubernetes支持分类查看
参考文档:https://kubernetes.io/zh-cn/docs/concepts/storage/
[root@docker-master controllers_dir]# kubectl explain pod.spec.volumes
persistenvolume(PV)是配置好的一段存储(可以是任意类型的存储卷)
- 也就是说将网络存储共享出来,配置定义成PV。
PersistentVolumeClaim(PVC)是用户pod使用PV的申请请求。
- 用户不需要关心具体的volume实现细节,只需要关心使用需求。
pv与pvc之间的关系
- pv提供存储资源(生产者)
- pvc使用存储资源(消费者)
- 使用pvc绑定pv

实现nfs类型pv与pvc
1:编写pv的yaml文件
[root@docker-master controllers_dir]# vim pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume #类型pv
metadata:
name: pv-nfs #名称
spec:
# 容量
capacity:
storage: 10Gi
# 访问模式
accessModes:
- ReadWriteMany
nfs:
path: /data/nfs #nfs共享目录
server: 192.168.108.33 #nfs服务器IP
访问模式3种:参考文档: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
- ReadWriteOnce 单节点读写挂载
- ReadOnlyMany 多节点只读挂载
- ReadWriteMany 多节点读写挂载
- ReadWriteOncePod 卷可以被单个 Pod 以读写方式挂载。(1.29新特性)
我们要实现多个nginx跨节点之间的数据共享,所以选择ReadWriteMany模式。
2:创建pv并验证
[root@docker-master controllers_dir]# kubectl apply -f pv-nfs.yaml
persistentvolume/pv-nfs created
[root@docker-master controllers_dir]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 10Gi RWX Retain Available
说明:
- RWX为ReadWriteMany的简写
- Retain是回收策略
- Retain表示不使用了需要手动回收
- 参考: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaim-policy
3:创建pvc的yaml文件
[root@docker-master controllers_dir]# vim pvc-nfs.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs
spec:
accessModes:
- ReadWriteMany # 类型与pv一致,否则无法绑定
resources:
requests:
storage: 10Gi #大小与pv一致
4:应用yaml
[root@docker-master controllers_dir]# kubectl apply -f pvc-nfs.yaml
persistentvolumeclaim/pvc-nfs created
5:验证
[root@docker-master controllers_dir]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Bound pv-nfs 10Gi RWX 11s
查看pv,绑定成功
[root@docker-master controllers_dir]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 10Gi RWX Retain Bound default/pvc-nfs 4m59s
6:创建nginx应用yaml文件
[root@docker-master controllers_dir]# vim nginx-pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-pvc
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
restartPolicy: Always
containers:
- name: c1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: pvc-nfs
7:运行yaml文件
[root@docker-master controllers_dir]# kubectl apply -f nginx-pvc.yaml
deployment.apps/nginx-pvc created
8:验证
[root@docker-master controllers_dir]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-pvc-77699f8c7c-9tw2c 1/1 Running 0 12s 10.244.248.156 docker-node2 <none> <none>
nginx-pvc-77699f8c7c-bbj72 1/1 Running 0 12s 10.244.148.198 docker-node1 <none> <none>
[root@docker-master controllers_dir]# curl http://10.244.248.156
hello nfs storage
[root@docker-master controllers_dir]# curl http://10.244.148.198
hello nfs storage
在nfs中修改index.html首页内容
[root@nfs nfs]# vim index.html
hello, this is nfs storage
再次查看首页
[root@docker-master controllers_dir]# curl http://10.244.148.198
hello, this is nfs storage
[root@docker-master controllers_dir]# curl http://10.244.248.156
hello, this is 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


点开deploy目录

在master节点创建下载目录
[root@docker-master controllers_dir]# mkdir nfs-cli
[root@docker-master controllers_dir]# cd nfs-cli/
1:下载class插件文件
[root@docker-master nfs-cli]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml
--2026-01-21 14:51:47-- https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml
正在解析主机 raw.githubusercontent.com (raw.githubusercontent.com)... 198.18.0.6
正在连接 raw.githubusercontent.com (raw.githubusercontent.com)|198.18.0.6|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:246 [text/plain]
正在保存至: “class.yaml”
100%[========================================================================>] 246 --.-K/s 用时 0s
2026-01-21 14:51:48 (5.61 MB/s) - 已保存 “class.yaml” [246/246])
[root@docker-master nfs-cli]# 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表示存档
应用yaml文件
[root@docker-master nfs-cli]# kubectl apply -f class.yaml
storageclass.storage.k8s.io/nfs-client created
查看资源
[root@docker-master nfs-cli]# kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 18s
- RECLAIMPOLICY pv回收策略,pod或者pvc被删除后,pv是否删除还是保留
- VOLUMEBINDINGMODE Immediate模式下pvc与pv立即绑定,主要是不等待相关pod调度完 成,不关心其运行节点,直接完成
- ALLOWVOLUMEEXPANSION pvc扩容 false不允许,true允许
2:下载并创建rbac
用于apiserver给storage提供自动创建的授权
因为storage自动创建pv需要经过kube-apiserver,所以需要授权。
[root@docker-master nfs-cli]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml
--2026-01-21 14:54:50-- https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml
正在解析主机 raw.githubusercontent.com (raw.githubusercontent.com)... 198.18.0.6
正在连接 raw.githubusercontent.com (raw.githubusercontent.com)|198.18.0.6|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:1900 (1.9K) [text/plain]
正在保存至: “rbac.yaml”
100%[========================================================================>] 1,900 --.-K/s 用时 0s
2026-01-21 14:54:51 (51.8 MB/s) - 已保存 “rbac.yaml” [1900/1900])
应用yaml文件
[root@docker-master nfs-cli]# kubectl apply -f rbac.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
3:创建动态供给的deployment
需要一个deployment来专门实现pv与pvc的自动创建
下载对应的deployment文件
[root@docker-master nfs-cli]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/deployment.yaml
--2026-01-21 14:55:56-- https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/deployment.yaml
正在解析主机 raw.githubusercontent.com (raw.githubusercontent.com)... 198.18.0.6
正在连接 raw.githubusercontent.com (raw.githubusercontent.com)|198.18.0.6|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:1069 (1.0K) [text/plain]
正在保存至: “deployment.yaml”
100%[========================================================================>] 1,069 --.-K/s 用时 0s
2026-01-21 14:55:57 (97.9 MB/s) - 已保存 “deployment.yaml” [1069/1069])
编辑yaml文件
[root@docker-master nfs-cli]# 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.33 #nfs服务器地址
- name: NFS_PATH
value: /data/nfs #共享目录
volumes:
- name: nfs-client-root
nfs:
server: 192.168.108.33 #nfs服务器地址
path: /data/nfs #共享目录
应用yaml文件
[root@docker-master nfs-cli]# kubectl apply -f deployment.yaml
deployment.apps/nfs-client-provisioner created
验证
[root@docker-master nfs-cli]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-56fc4bcc87-hkk89 1/1 Running 0 58s
4:nginx应用使用动态供给
1.创建statefulset应用来调用名为nfs-client的storageclass,以实现动态供给
[root@docker-master nfs-cli]# vim nginx-storageclass.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc #service名称
spec:
ports:
- port: 80
name: web
selector:
app: nginx #service关联pod标签
clusterIP: None #无头服务
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-storageclass #名称+编号=pod名称
spec:
replicas: 2
selector:
matchLabels:
app: nginx #控制器关联pod标签
serviceName: "nginx-svc" #关联service名称
template:
metadata:
labels:
app: nginx #pod标签
spec:
containers:
- name: c1 # 容器名
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- name: web
containerPort: 80
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
# 动态持久化
volumeClaimTemplates: #pvc模板
- metadata:
name: www #构成pvc名称
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-client"
resources:
requests:
storage: 1Gi
2:应用YAML文件
[root@docker-master nfs-cli]# kubectl apply -f nginx-storageclass.yaml
service/nginx-svc created
statefulset.apps/nginx-storageclass created
3:查看资源
[root@docker-master nfs-cli]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-56fc4bcc87-hkk89 1/1 Running 0 33m
nginx-storageclass-0 1/1 Running 0 3s
nginx-storageclass-1 0/1 Pending 0 1s
[root@docker-master nfs-cli]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d23h
nginx-svc ClusterIP None <none> 80/TCP 21s
[root@docker-master nfs-cli]# kubectl get statefulset
NAME READY AGE
nginx-storageclass 2/2 41s
pvc状态
[root@docker-master nfs-cli]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Bound pv-nfs 10Gi RWX 96m
www-nginx-storageclass-0 Bound pvc-80f1db0e-34ab-4fc5-a193-a97732fa99d5 1Gi RWO nfs-client 2m41s
www-nginx-storageclass-1 Bound pvc-1c8f1684-1dd8-410b-b985-72d98bbd8756 1Gi RWO nfs-client 56s
pv状态
[root@docker-master nfs-cli]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 10Gi RWX Retain Bound default/pvc-nfs 101m
pvc-1c8f1684-1dd8-410b-b985-72d98bbd8756 1Gi RWO Delete Bound default/www-nginx-storageclass-1 nfs-client 68s
pvc-80f1db0e-34ab-4fc5-a193-a97732fa99d5 1Gi RWO Delete Bound default/www-nginx-storageclass-0 nfs-client 2m53s
到nfs-server中,查看/data/nfs目录,会发现有两个文件夹,保存两个pod网站数据
[root@nfs nfs]# cd /data/nfs/
[root@nfs nfs]# ls
default-www-nginx-storageclass-0-pvc-80f1db0e-34ab-4fc5-a193-a97732fa99d5 index.html
default-www-nginx-storageclass-1-pvc-1c8f1684-1dd8-410b-b985-72d98bbd8756
往两个目录中分别写入index.html内容进行查看
[root@nfs nfs]# echo "this is storage01" > default-www-nginx-storageclass-0-pvc-80f1db0e-34ab-4fc5-a193-a97732fa99d5/index.html
[root@nfs nfs]# echo "this is storage02" > default-www-nginx-storageclass-1-pvc-1c8f1684-1dd8-410b-b985-72d98bbd8756/index.html
[root@docker-master nfs-cli]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-client-provisioner-56fc4bcc87-hkk89 1/1 Running 0 36m 10.244.248.159 docker-node2 <none> <none>
nginx-storageclass-0 1/1 Running 0 3m43s 10.244.248.165 docker-node2 <none> <none>
nginx-storageclass-1 1/1 Running 0 3m41s 10.244.148.203 docker-node1 <none> <none>
[root@docker-master nfs-cli]# curl http://10.244.248.165
this is storage01
[root@docker-master nfs-cli]# curl http://10.244.148.203
this is storage02
使用kube-dns解析无头服务域名,可以直接看到后端pod的地址
[root@docker-master nfs-cli]# 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 7d23h
metrics-server ClusterIP 10.111.168.59 <none> 443/TCP 7d
[root@docker-master nfs-cli]# 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: 15668
;; 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.148.203
nginx-svc.default.svc.cluster.local. 30 IN A 10.244.248.165
;; Query time: 3 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 三 1月 21 15:42:00 CST 2026
;; MSG SIZE rcvd: 166
解析pod域名
[root@docker-master nfs-cli]# dig -t a nginx-storageclass-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 nginx-storageclass-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: 17527
;; 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:
;nginx-storageclass-0.nginx-svc.default.svc.cluster.local. IN A
;; ANSWER SECTION:
nginx-storageclass-0.nginx-svc.default.svc.cluster.local. 30 IN A 10.244.248.165
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 三 1月 21 15:42:27 CST 2026
;; MSG SIZE rcvd: 157
[root@docker-master nfs-cli]# dig -t a nginx-storageclass-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 nginx-storageclass-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: 23052
;; 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:
;nginx-storageclass-1.nginx-svc.default.svc.cluster.local. IN A
;; ANSWER SECTION:
nginx-storageclass-1.nginx-svc.default.svc.cluster.local. 30 IN A 10.244.148.203
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 三 1月 21 15:42:48 CST 2026
;; MSG SIZE rcvd: 157
在集群里创建pod访问域名,观察负载均衡
[root@docker-master nfs-cli]# kubectl run -it centos --image=centos:7 --image-pull-policy=IfNotPresent
[root@docker-master nfs-cli]# kubectl exec -it centos -- /bin/bash
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is storage01
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is storage02
直接访问pod域名
[root@centos /]# curl http://nginx-storageclass-1.nginx-svc.default.svc.cluster.local.
this is storage02
[root@centos /]# curl http://nginx-storageclass-0.nginx-svc.default.svc.cluster.local.
this is storage01
金丝雀发布更新(灰度发布)
它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。
Statefulset可以使用partition参数来实现金丝雀更新,partition参数可以控制StatefulSet控制器更新的 Pod,下面,就进行StatefulSet控制器的金丝雀更新实战。
[root@docker-master nfs-cli]# kubectl get sts nginx-storageclass -o yaml
......
updateStrategy:
rollingUpdate:
partition: 0 #默认分区号0,表示更新0及大于0的所有pod
type: RollingUpdate
......
说明:
使用patch参数来指定了statefu1set控制器的partition参数为1,表示当更新时,只有Pod的编号大于等 于1的才更新。
修改更新
[root@docker-master nfs-cli]# kubectl patch sts nginx-storageclass -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'
再次观察,值设置为1
updateStrategy:
rollingUpdate:
partition: 1
查看更新前版本
[root@docker-master nfs-cli]# kubectl describe pod nginx-storageclass-0 | grep Image:
Image: nginx:1.26-alpine
[root@docker-master nfs-cli]# kubectl describe pod nginx-storageclass-1 | grep Image:
Image: nginx:1.26-alpine
更新版本
[root@docker-master nfs-cli]# kubectl set image sts/nginx-storageclass c1=nginx:1.29-alpine
statefulset.apps/nginx-storageclass image updated
再次查看版本,发现只有web-1进行了更新
[root@docker-master nfs-cli]# kubectl describe pod nginx-storageclass-0 | grep Image:
Image: nginx:1.26-alpine
[root@docker-master nfs-cli]# kubectl describe pod nginx-storageclass-1 | grep Image:
Image: nginx:1.29-alpine
直观查看pod版本列表
# 以列的形式查看
[root@docker-master nfs-cli]# kubectl get pod -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
centos centos:7
nfs-client-provisioner-56fc4bcc87-hkk89 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
nginx-storageclass-0 nginx:1.26-alpine
nginx-storageclass-1 nginx:1.29-alpine
扩容数量为4,观察版本更新
[root@docker-master nfs-cli]# kubectl scale sts nginx-storageclass --replicas=4
statefulset.apps/nginx-storageclass scaled
[root@docker-master nfs-cli]# kubectl get pod -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
centos centos:7
nfs-client-provisioner-56fc4bcc87-hkk89 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
nginx-storageclass-0 nginx:1.26-alpine
nginx-storageclass-1 nginx:1.29-alpine
nginx-storageclass-2 nginx:1.29-alpine
nginx-storageclass-3 nginx:1.29-alpine
发现:新增的pod都使用的新版本
缩容数量为1,观察版本变化
[root@docker-master nfs-cli]# kubectl scale sts nginx-storageclass --replicas=1
statefulset.apps/nginx-storageclass scaled
[root@docker-master nfs-cli]# kubectl get pod -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
centos centos:7
nfs-client-provisioner-56fc4bcc87-hkk89 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
nginx-storageclass-0 nginx:1.26-alpine
发现,就剩下原来的老版本的pod,说明位置没变,不可变基础设施,再次扩容,观察版本
[root@docker-master nfs-cli]# kubectl scale sts nginx-storageclass --replicas=6
statefulset.apps/nginx-storageclass scaled
[root@docker-master nfs-cli]# kubectl get pod -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
centos centos:7
nfs-client-provisioner-56fc4bcc87-hkk89 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
nginx-storageclass-0 nginx:1.26-alpine
nginx-storageclass-1 nginx:1.29-alpine
nginx-storageclass-2 nginx:1.29-alpine
nginx-storageclass-3 nginx:1.29-alpine
nginx-storageclass-4 nginx:1.29-alpine
nginx-storageclass-5 nginx:1.29-alpine
扩容依旧是按照partition的位置部署新版本
实现全部更新
[root@docker-master nfs-cli]# kubectl patch sts nginx-storageclass -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
statefulset.apps/nginx-storageclass patched
[root@docker-master nfs-cli]# kubectl get pod -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
centos centos:7
nfs-client-provisioner-56fc4bcc87-hkk89 registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
nginx-storageclass-0 nginx:1.29-alpine
nginx-storageclass-1 nginx:1.29-alpine
nginx-storageclass-2 nginx:1.29-alpine
nginx-storageclass-3 nginx:1.29-alpine
nginx-storageclass-4 nginx:1.29-alpine
nginx-storageclass-5 nginx:1.29-alpine
控制器功能对比
| 控制器 | 版本升级/回退 | 副本扩容/缩减 |
|---|---|---|
| Deployment | ✅ | ✅ |
| ReplicaSet | ❌ | ✅ |
| DaemonSet | ✅ | ❌ |
| StatefulSet | ✅ | ✅ |
| Job | ❌ | ❌ |
| CronJob | ❌ | ❌ |
更多推荐

所有评论(0)