Controller核心管理
控制器controller
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 周期性
Deployment
Replicaset控制器的功能
-
支持新的基于集合的selector(以前的rc里没有这种功能)
-
通过改变Pod副本数量实现Pod的扩容和缩容
Deployment控制器的功能
-
Deployment集成了上线部署、滚动升级、创建副本、回滚等功能
-
Deployment里包含并使用了ReplicaSet
Deployment用于部署无状态应用
无状态应用的特点:
-
所有pod无差别
-
所有pod中容器运行同一个image
-
所有pod可以运行在集群中任意node上
-
所有pod无启动顺序先后之分
-
随意pod数量扩容或缩容
-
例如简单运行一个静态web程序
创建deployment类型应用
帮助信息
[root@master 1-yaml]# kubectl explain deployment
GROUP: apps
KIND: Deployment
VERSION: v1
DESCRIPTION:
Deployment enables declarative updates for Pods and ReplicaSets.
FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata <ObjectMeta>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
spec <DeploymentSpec>
Specification of the desired behavior of the Deployment.
status <DeploymentStatus>
Most recently observed status of the Deployment.
创建deployment类型应用
# 准备yaml文件
[root@master controller]# cat deployment-ngix.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
spec: # 定义资源的规格
replicas: 1 # 副本集,定义pod数量
selector: # 选择器
matchLabels: # 选择器匹配标签
app: deployment-nginx # 需要与模版标签一致
template: # 创建选择器模版
metadata: # 文件元信息,属性信息
labels: # 模版标签
app: deployment-nginx # 标签名
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
# 应用yaml文件
[root@master controller]# kubectl apply -f deployment-ngix.yaml
deployment.apps/deploy-nginx created
# 查看pod
[root@master controller]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-nginx-775b6cbc5-rckkw 1/1 Running 0 5m2s 10.244.104.35 node2 <none> <none>
# 访问查看所有集群节点网卡,
[root@master controller]# ifconfig tunl0
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.219.64 netmask 255.255.255.255
tunnel txqueuelen 1000 (IPIP Tunnel)
RX packets 22884 bytes 7684292 (7.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 23799 bytes 2095877 (1.9 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@node1 ~]# ifconfig tunl0
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.166.128 netmask 255.255.255.255
tunnel txqueuelen 1000 (IPIP Tunnel)
RX packets 2902 bytes 423657 (413.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1945 bytes 225558 (220.2 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@node2 ~]# ifconfig tunl0
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 10.244.104.0 netmask 255.255.255.255
tunnel txqueuelen 1000 (IPIP Tunnel)
RX packets 20900 bytes 1672415 (1.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 21134 bytes 7468913 (7.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# 访问集群中的pod
[root@master controller]# curl 10.244.104.35
<!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>
总结:发现所有节点的ip都为10.244网段
删除deployment中的od
# 删除pod
[root@master controller]# kubectl delete pod deploy-nginx-775b6cbc5-rckkw --grace-period=0 --force
# 查看容器
[root@master controller]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-nginx-775b6cbc5-29wpf 1/1 Running 0 6s 10.244.104.36 node2 <none> <none>
总结:pod的IP不是固定的,就算把整个集群关闭再启动,pod也会自动启动,但是IP地址会发生变化既然IP地址不是固定的,所以需要一个固定的访问endpoint给用户,那么这种方式就是service
pod版本升级
帮助文档
[root@master ~]# kubectl set image -h
Update existing container image(s) of resources.
Possible resources include (case insensitive):
pod (po), replicationcontroller (rc), deployment (deploy), daemonset
(ds), statefulset (sts), cronjob (cj),
replicaset (rs)
Examples:
# Set a deployment's nginx container image to 'nginx:1.9.1', and its busybox
container image to 'busybox'
kubectl set image deployment/nginx busybox=busybox nginx=nginx:1.9.1
# Update all deployments' and rc's nginx container's image to 'nginx:1.9.1'
kubectl set image deployments,rc nginx=nginx:1.9.1 --all
# Update image of all containers of daemonset abc to 'nginx:1.9.1'
kubectl set image daemonset abc *=nginx:1.9.1
# Print result (in yaml format) of updating nginx container image from local
file, without hitting the server
kubectl set image -f path/to/file.yaml nginx=nginx:1.9.1 --local -o yaml
进行升级
# 升级前验证版本
[root@master controller]# kubectl exec deploy-nginx-775b6cbc5-29wpf -- nginx -v
nginx version: nginx/1.26.3
# 升级版本 --record:进行记录
[root@master controller]# kubectl set image deployment deploy-nginx nginx=nginx:1.29-alpine --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/deploy-nginx image updated
[root@master controller]# kubectl describe pod deploy-nginx-86b95dccd6-tk5xm | grep Image:
Image: nginx:1.29-alpine
# 通过命令查看是否成功
[root@master controller]# kubectl rollout status deployment deploy-nginx
deployment "deploy-nginx" successfully rolled out
说明:
-
deployment deploy-nginx代表名为deploy-nginx的deployment
-
nginx=nginx:1.29-a1pine前面的nginx为容器名
-
–record 表示会记录
容器名怎么查看?
-
kubectl describe pod pod名查看
-
kubectl edit deployment deployment名 来查看容器名
-
kubectl get deployment deployment名 -o yam]来查看容器名
pod版本回退
# 查看版本历史消息
[root@master controller]# kubectl rollout history deployment deploy-nginx
deployment.apps/deploy-nginx
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image deployment deploy-nginx nginx=nginx:1.29-alpine --record=true
# 定义要回退的版本,并没有执行,还需要执行才可回退
[root@master controller]# kubectl rollout history deployment deploy-nginx --revision=1
deployment.apps/deploy-nginx with revision #1
Pod Template:
Labels: app=deployment-nginx
pod-template-hash=775b6cbc5
Containers:
nginx:
Image: nginx:1.26-alpine
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
# 执行回退版本
[root@master controller]# kubectl rollout undo deployment deploy-nginx --to-revision=1
deployment.apps/deploy-nginx rolled back
# 查看版本
[root@master controller]# kubectl rollout status deployment deploy-nginx
deployment "deploy-nginx" successfully rolled out
[root@master controller]# kubectl exec deployments/deploy-nginx -- nginx -v
nginx version: nginx/1.26.3
副本扩容
# 查看帮助信息
[root@master controller]# kubectl scale -h
Set a new size for a deployment, replica set, replication controller, or stateful set.
Scale also allows users to specify one or more preconditions for the scale action.
If --current-replicas or --resource-version is specified, it is validated before the scale is attempted, and it is guaranteed that the precondition holds true when the scale is sent to the server.
Examples:
# Scale a replica set named 'foo' to 3
kubectl scale --replicas=3 rs/foo
# Scale a resource identified by type and name specified in "foo.yaml" to 3
kubectl scale --replicas=3 -f foo.yaml
# If the deployment named mysql's current size is 2, scale mysql to 3
kubectl scale --current-replicas=2 --replicas=3 deployment/mysql
# Scale multiple replication controllers
kubectl scale --replicas=5 rc/example1 rc/example2 rc/example3
# Scale stateful set named 'web' to 3
kubectl scale --replicas=3 statefulset/web
Options:
--all=false:
Select all resources in the namespace of the specified resource types
--allow-missing-template-keys=true:
If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.
--current-replicas=-1:
Precondition for current size. Requires that the current size of the resource match this value in order to scale. -1 (default) for no condition.
--dry-run='none':
Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.
-f, --filename=[]:
Filename, directory, or URL to files identifying the resource to set a new size
-k, --kustomize='':
Process the kustomization directory. This flag can't be used together with -f or -R.
-o, --output='':
Output format. One of: (json, yaml, name, go-template, go-template-file, template, templatefile, jsonpath, jsonpath-as-json, jsonpath-file).
-R, --recursive=false:
Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.
--replicas=0:
The new desired number of replicas. Required.
--resource-version='':
资源版本的前提条件。要求当前资源版本与此值匹配才能进行扩缩操作。
-l, --selector='':
Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Matching objects must satisfy all of the specified label constraints.
--show-managed-fields=false:
If true, keep the managedFields when printing objects in JSON or YAML format.
--template='':
Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
--timeout=0s:
The length of time to wait before giving up on a scale operation, zero means don't wait. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).
Usage:
kubectl scale [--resource-version=version] [--current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME) [options]
Use "kubectl options" for a list of global command-line options (applies to all commands).
进行副本扩容
# 扩容副本为4
[root@master controller]# kubectl scale deployment deploy-nginx --replicas=4
deployment.apps/deploy-nginx scaled
# 查看验证
[root@master controller]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deploy-nginx-775b6cbc5-87cbb 1/1 Running 1 (33m ago) 2d16h
deploy-nginx-775b6cbc5-pvtwj 1/1 Running 0 6s
deploy-nginx-775b6cbc5-r64fw 1/1 Running 0 6s
deploy-nginx-775b6cbc5-xf5bq 1/1 Running 0 6s
[root@master controller]# kubectl get replicasets.apps
NAME DESIRED CURRENT READY AGE
deploy-nginx-775b6cbc5 4 4 4 2d17h
副本裁剪
# 制定副本为1进行裁剪
[root@master controller]# kubectl scale deployment deploy-nginx --replicas=1
# 查看验证
deployment.apps/deploy-nginx scaled
[root@master controller]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deploy-nginx-775b6cbc5-87cbb 1/1 Running 1 (37m ago) 2d16h
[root@master controller]# kubectl get replicasets.apps
NAME DESIRED CURRENT READY AGE
deploy-nginx-775b6cbc5 1 1 1 2d17h
副本数量可以降为0,有需要就启动,无需要就停止
[root@master controller]# kubectl scale deployment deploy-nginx --replicas=0
deployment.apps/deploy-nginx scaled
[root@master controller]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
deploy-nginx 0/0 0 0 2d17h
多副本滚动更新
# 扩容多副本
[root@master controller]# kubectl scale deployment deploy-nginx --replicas=8
deployment.apps/deploy-nginx scaled
# 查看
[root@master controller]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deploy-nginx-775b6cbc5-44gxj 1/1 Running 0 1s
deploy-nginx-775b6cbc5-6r5n4 1/1 Running 0 1s
deploy-nginx-775b6cbc5-87qjl 1/1 Running 0 42s
deploy-nginx-775b6cbc5-mglwm 1/1 Running 0 42s
deploy-nginx-775b6cbc5-rqdc5 1/1 Running 0 42s
deploy-nginx-775b6cbc5-sjpqc 1/1 Running 0 42s
deploy-nginx-775b6cbc5-swg67 1/1 Running 0 42s
deploy-nginx-775b6cbc5-wq4ls 1/1 Running 0 42s
# 进行多副本更新
[root@master controller]# kubectl set image deployment deploy-nginx nginx=nginx:1.29-alpine --record
# 验证
[root@master controller]# kubectl describe pod | grep Image:
Image: nginx:1.29-alpine
Image: nginx:1.29-alpine
Image: nginx:1.29-alpine
Image: nginx:1.29-alpine
Image: nginx:1.29-alpine
Image: nginx:1.29-alpine
Image: nginx:1.29-alpine
Image: nginx:1.29-alpine
[root@master controller]# kubectl rollout status deployment deploy-nginx
deployment "deploy-nginx" successfully rolled out
删除deployment
删除deployment,里面的pod也会被自动删除
[root@master controller]# kubectl delete deployments.apps deploy-nginx
deployment.apps "deploy-nginx" deleted
[root@master controller]# kubectl get deployments.apps
No resources found in default namespace.
[root@master controller]# kubectl get pod
No resources found in default namespace.
Replicaset
总结:
- replicaset:可以实现弹性伸缩,不可以实现版本升级。
- deployment:既可以实现弹性伸缩,也可以实现版本升级
提醒:replicaset控制器很少单独使用,不建议脱离deployment
# 编写 yaml 文件
[root@master replicaset]# cat rc-nginx.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rc-nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
# 应用 yaml 文件
[root@master replicaset]# kubectl apply -f rc-nginx.yaml
replicaset.apps/rc-nginx created
# 查看验证
[root@master replicaset]# kubectl get replicasets.apps
NAME DESIRED CURRENT READY AGE
rc-nginx 2 2 2 69s
[root@master replicaset]# kubectl get pod
NAME READY STATUS RESTARTS AGE
rc-nginx-fkngt 1/1 Running 0 54s
rc-nginx-gkbdw 1/1 Running 0 54s
[root@master replicaset]# kubectl get deployments.apps
No resources found in default namespace.
说明:找不到deployment,说明创建rs并没有创建deployment
查看是否可以扩容
[root@master replicaset]# kubectl scale replicaset rc-nginx --replicas=4
replicaset.apps/rc-nginx scaled
# 验证
[root@master replicaset]# kubectl get replicasets.apps
NAME DESIRED CURRENT READY AGE
rc-nginx 4 4 4 3m2s
[root@master replicaset]# kubectl get pod
NAME READY STATUS RESTARTS AGE
rc-nginx-fkngt 1/1 Running 0 2m17s
rc-nginx-gkbdw 1/1 Running 0 2m17s
rc-nginx-mxqr2 1/1 Running 0 4s
rc-nginx-zxm7t 1/1 Running 0 4s
验证是否可以升级
# 升级版本
[root@master replicaset]# kubectl set image replicaset rc-nginx nginx=nginx:1.29-alpine --record
Flag --record has been deprecated, --record will be removed in the future
replicaset.apps/rc-nginx image updated
# 查看版本,发现并没有进行升级
[root@master replicaset]# kubectl describe pod | grep Image:
Image: nginx:1.26-alpine
Image: nginx:1.26-alpine
Image: nginx:1.26-alpine
Image: nginx:1.26-alpine
发现版本没有进行升级
控制器 controller 进阶
DaemonSet
总结:DaemonSet资源可以实现版本升级,无法实现弹性伸缩
DaemonSet介绍
- Daemonset能够让所有(或者特定)的节点运行同一个pod。
- 当节点加入到K8s集群中,pod会被(DaemonSet)调度到该节点上运行,当节点从K8S集群中被移除,被Daemonset调度的pod会被移除。
- 如果删除DaemonSet,所有跟这个DaemonSet相关的pods都会被删除。
- 如果一个DaemonSet的Pod被杀死、停止、或者崩溃,那么DaemonSet将会重新创建一个新的副本在这台计算节点上。
- DaemonSet一般应用于日志收集、监控采集、分布式存储守护进程等
DaemonSet应用案例
# 编写 yaml 文件
[root@master daemonset]# cat daemonset-nginx.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ds-nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
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
# 应用 yaml 文件
[root@master daemonset]# kubectl apply -f daemonset-nginx.yaml
daemonset.apps/ds-nginx created
[root@master daemonset]# kubectl get daemonsets.apps
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
ds-nginx 2 2 2 2 2 <none> 34s
[root@master daemonset]# kubectl get pod
NAME READY STATUS RESTARTS AGE
ds-nginx-kmkdr 1/1 Running 0 39s
ds-nginx-xqnjj 1/1 Running 0 39s
进行版本升级
# 升级版本
[root@master daemonset]# kubectl set image daemonset ds-nginx c1=nginx:1.29-alpine --record
Flag --record has been deprecated, --record will be removed in the future
daemonset.apps/ds-nginx image updated
# 验证版本
[root@master daemonset]# kubectl describe pod | grep Image:
Image: nginx:1.29-alpine
Image: nginx:1.29-alpine
进行扩容
[root@master daemonset]# kubectl scale daemonset ds-nginx --replicas=4
Error from server (NotFound): the server could not find the requested resource
Job
Job介绍
- 对于ReplicaSet而言,它希望pod保持预期数目、持久运行下去,除非用户明确删除,否则这些对象一直存在,它们针对的是耐久性任务如web服务等。
- 对于非耐久性任务,比如压缩文件,任务完成后,pod需要结束运行,不需要pod继续保持在系统中,这个时候就要用到job。
- job负责批量处理短暂的一次性任务(short lived one-of tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
job应用案例
计算圆周率2000位
# 编写 yaml 文件
[root@master job]# cat job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
metadata:
name: pod-pi
spec:
nodeName: node1
containers:
- name: c1
image: perl
imagePullPolicy: IfNotPresent
command: ["Perl","-Mbignum=bpi","-wle","print bpi(20000)"]
restartPolicy: Never
# 应用yaml
[root@master job]# kubectl apply -f job.yaml
# 查看验证
[root@master job]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pi-wnv2r 1/1 Running 0 13s
# 过一段时间继续查看
[root@master job]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pi-wnv2r 0/1 Completed 0 5m45s
# 查看日志
[root@master job]# kubectl logs pi-lvm6z
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
创建固定次数的job
# 编写 yaml 文件
[root@master job]# cat job-10.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: busybox-job
spec:
completions: 10 # 指定job的执行次数
parallelism: 1 # 执行job的并发数
template:
metadata:
name: busybox-job-pod
spec:
containers:
- name: c1
image: busybox
imagePullPolicy: IfNotPresent
command: ["echo","hello"]
restartPolicy: Never
# 应用 yaml 文件
[root@master job]# kubectl apply -f job-10.yaml
job.batch/busybox-job created
# 查看job执行次数
[root@master job]# kubectl get pod
NAME READY STATUS RESTARTS AGE
busybox-job-2vxtt 0/1 Completed 0 17s
busybox-job-6cp6b 0/1 Completed 0 38s
busybox-job-7mgmv 0/1 Completed 0 31s
busybox-job-f58mv 0/1 Completed 0 55s
busybox-job-gr8k8 0/1 Completed 0 41s
busybox-job-pdrbg 0/1 Completed 0 24s
busybox-job-qrqdc 0/1 Completed 0 34s
busybox-job-w7qvb 0/1 Completed 0 27s
busybox-job-zddsd 0/1 Completed 0 48s
busybox-job-zpdqx 0/1 Completed 0 20s
[root@master job]# kubectl logs busybox-job-2vxtt
hello
一次性备份MySQL数据库
通过job控制器创建应用备份MySQL数据库
- 准备 mysql 资源文件
# 准备 mysql 数据库 yaml 文件
[root@master job]# cat mysql.yaml
# service 资源
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
namespace: default
spec:
ports:
- port: 3306
name: mysql
clusterIP: None # 无头服务
selector:
app: mysql-dump
---
# statefulset 控制器资源
apiVersion: apps/v1
kind: StatefulSet # 有状态控制器
metadata:
name: db
namespace: default
spec:
selector:
matchLabels:
app: mysql-dump
serviceName: "mysql-svc"
template:
metadata:
labels:
app: mysql-dump
spec:
nodeName: node1 # 将资源创建到node1
containers:
- name: mysql # 容器名称
image: mysql:5.7
env: # 设置环境变量
- name: MYSQL_ROOT_PASSWORD # 设置mysql管理员密码
value: "123456" # 设置密码
ports:
- containerPort: 3306
volumeMounts:
- mountPath: "/var/lib/mysql"
name: mysql-data
volumes: # 外部存储卷
- name: mysql-data
hostPath:
path: /opt/mysqldata
# 应用 yaml 文件
[root@master job]# kubectl apply -f mysql.yaml
# 验证
[root@master job]# kubectl get pod
NAME READY STATUS RESTARTS AGE
db-0 1/1 Running 0 44s
# node1节点可以查看容器数据库目录
[root@node1 ~]# ls /opt/mysqldata/
auto.cnf client-key.pem ib_logfile1 performance_schema server-key.pem
ca-key.pem ib_buffer_pool ibtmp1 private_key.pem sys
ca.pem ibdata1 mysql public_key.pem
client-cert.pem ib_logfile0 mysql.sock server-cert.pem
- 创建用于实现任务的资源清单文件
# 创建 yaml 文件
[root@master job]# cat job-mysqld.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: mysql-dump
spec:
template:
metadata:
name: mysql-dump
spec:
nodeName: node2
containers:
- name: c1
image: mysql:5.7
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","mysqldump --host=mysql-svc -uroot -p123456 --databases mysql > /root/mysql_back.sql"]
volumeMounts:
- mountPath: "/root"
name: mysql-data
restartPolicy: Never
volumes:
- name: mysql-data
hostPath:
path: /opt/mysqldump
# 应用 yaml 文件
cronjob
类似于Linux系统的crontab,在指定的时间周期运行相关的任务
周期性输出字符
# 创建 yaml 文件
[root@master cronjob]# cat cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: cronjob1
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: c1
image: busybox
imagePullPolicy: IfNotPresent
args:
- /bin/sh
- -c
- date;echo hello kubernetes
restartPolicy: OnFailure
# 应用 yaml 文件
[root@master cronjob]# kubectl apply -f cronjob.yaml
# 查看验证是否按计划执行
[root@master cronjob]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cronjob1-29238302-66dx7 0/1 Completed 0 94s 10.244.104.32 node2 <none> <none>
cronjob1-29238303-8kgpd 0/1 Completed 0 34s 10.244.104.33 node2 <none> <none>
周期性备份数据库
# 创建 mysql 文件
[root@master ~]# cat job/mysql.yaml
# service 资源
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
namespace: default
spec:
ports:
- port: 3306
name: mysql
clusterIP: None # 无头服务
selector:
app: mysql-dump
---
# statefulset 控制器资源
apiVersion: apps/v1
kind: StatefulSet # 有状态控制器
metadata:
name: db
namespace: default
spec:
selector:
matchLabels:
app: mysql-dump
serviceName: "mysql-svc"
template:
metadata:
labels:
app: mysql-dump
spec:
nodeName: node1 # 将资源创建到node1
containers:
- name: mysql # 容器名称
image: mysql:5.7
env: # 设置环境变量
- name: MYSQL_ROOT_PASSWORD # 设置mysql管理员密码
value: "123456" # 设置密码
ports:
- containerPort: 3306
volumeMounts:
- mountPath: "/var/lib/mysql"
name: mysql-data
volumes: # 外部存储卷
- name: mysql-data
hostPath:
path: /opt/mysqldata
# 创建周期备份 yaml 文件
[root@master cronjob]# cat cronjob-mysql.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-dump
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
nodeName: node2
containers:
- name: c2
image: mysql:5.7
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","mysqldump --host=mysql-svc -uroot -p123456 --databases mysql > /root/mysql`date +%Y%m%d%H%M`.sql"]
volumeMounts:
- mountPath: "/root"
name: mysql-data
restartPolicy: Never
volumes:
- name: mysql-data
hostPath:
path: /op/mysqldump2
# 应用 yaml 文件
[root@master cronjob]# kubectl apply -f cronjob-mysql.yaml
# 到node2节点验证是否每分钟备份
[root@node2 ~]# ll /op/mysqldump2/
总用量 7368
-rw-r--r-- 1 root root 3771735 8月 4 17:14 mysql202508040914.sql
-rw-r--r-- 1 root root 3771735 8月 4 17:15 mysql202508040915.sql
控制器controller之StatefulSet
statefulset控制器作用
- Statefulset 是用来管理有状态应用的控制器。
- Statefulset 用来管理应用的部署、扩缩容及滚动更新,
- Statefulset 为 Pod 提供持久存储和持久标识符。
参考文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/statefulset/
无状态应用与有状态应用
无状态应用
- 如nginx
- 请求本身包含了响应端为响应这一请求所需的全部信息。每一个请求都像首次执行一样,不会依赖之前的数据进行响应。
- 不需要持久化的数据
- 无状态应用的多个实例之间互不依赖,可以无序的部署、删除或伸缩
有状态应用
-
如MySQL
-
前后请求有关联与依赖
-
需要持久化的数据
-
有状态应用的多个实例之间有依赖,不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的ID。
StatefulSet的特点
-
稳定的、唯一的网络标识符。(无clusterIP通过headless服务实现)
-
稳定的、持久的存储。(通过静态存储PV,PVC,动态存储storageclass实现)
-
有序的、优雅的部署和缩放
-
有序的、自动的滚动更新(从最大数更新,例如:编号2,编号1,编号0)。
StatefulSet的YAML组成
需要三个组成部分:
- headless service: 实现稳定,唯一的网络标识。
- statefulset类型资源: 写法和deployment几乎一致,就是类型不一样。
- volumeClaimTemplate:指定存储卷。
创建StarefulSet应用
**参考文档:**https://kubernetes.io/zh-cn/docs/tutorials/stateful-application/basic-stateful-set/
网络存储NFS部署
创建nfs共享服务器
# 创建挂载共享目录
[root@NFS ~]# mkdir -p /data/nfs
# 创建分区并格式化
[root@NFS nfs]# gdisk /dev/sdb
[root@NFS ~]# mkfs.xfs /dev/sdb1
# 挂载磁盘
[root@NFS ~]# mount /dev/sdb1 /data/nfs/
# 配置共享目录
# 解析:*允许所有用户访问 rw可读写 no_root_squash禁用安全降权规则。
[root@NFS ~]# cat /etc/exports
/data/nfs *(rw,no_root_squash,sync)
# 启动服务
[root@NFS ~]# systemctl enable nfs --now
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
# 所有节点安装 nfs 客户端软件包
[root@master ~]# yum -y install nfs-utils
[root@node1 ~]# yum -y install nfs-utils
[root@node2 ~]# yum -y install nfs-utils
[root@node1 ~]# showmount -e 10.1.8.111
Export list for 10.1.8.111:
/data/nfs *
创建实现共享yaml文件
# 创建共享 yaml 文件
[root@master statefulset]# cat dep-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: nfs-storage
mountPath: /usr/share/nginx/html
ports:
- containerPort: 80
volumes:
- name: nfs-storage
nfs:
server: 10.1.8.111
path: /data/nfs
# 应用 yaml 文件
[root@master statefulset]# kubectl apply -f dep-nfs.yaml
# 查看pod状态及ip
[root@master statefulset]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-nfs-78bbc4d55c-q4gnh 1/1 Running 0 6m1s 10.244.166.154 node1 <none> <none>
volume-nfs-78bbc4d55c-rzzw4 1/1 Running 0 6m1s 10.244.104.41 node2 <none> <none>
# 创建访问页面
[root@NFS ~]# echo "hello nfs storage" > /data/nfs/index.html
# 主节点验证共享是否成功
[root@master statefulset]# curl 10.244.166.154
hello nfs storage
PV(持久化存储卷)与PVC(持久存储卷声明)
kubernetes存储卷的分类太丰富了,每种类型都要写相应的接口与参数才行,这就让维护与管理难度加大。
kubernetes支持分类查看
参考文档:https://kubernetes.io/zh-cn/docs/concepts/storage/
[root@master statefulset_dir]# kubectl explain pod.spec.volumes
persistenvolume(PV)是配置好的一段存储(可以是任意类型的存储卷)
- 也就是说将网络存储共享出来,配置定义成PV。
PersistentVolumeClaim(PVC)是用户pod使用PV的申请请求。
- 用户不需要关心具体的volume实现细节,只需要关心使用需求。
pv与pvc之间的关系
-
pv提供存储资源(生产者)
-
pvc使用存储资源(消费者)
-
使用pvc绑定pv

实现nfs类型pv与pvc
访问模式:参考文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
-
ReadWriteOnce 单节点读写挂载
-
ReadOnlyMany 多节点只读挂载
-
ReadWriteMany 多节点读写挂载
创建 pv yaml 文件
# 编写 yaml 文件
root@master statefulset]# cat pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs
spec:
capacity: # 申请pv的大小
storage: 10Gi
accessModes: # 访问方式
- ReadWriteMany
nfs:
path: /data/nfs # nfs共享目录
server: 10.1.8.111 # nfs服务器地址
# 应用 yaml 文件
[root@master statefulset]# kubectl apply -f pv-nfs.yaml
persistentvolume/pv-nfs created
# 验证pv
[root@master statefulset]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 10Gi RWX Retain Available 3s
# RWX为ReadWriteMany的缩写
# retain是回收策略
创建pvc的yaml文件
# 创建 yaml 文件
[root@master statefulset]# cat pvc-nfs.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs
spec:
accessModes:
- ReadWriteMany # 访问模式,需要与pv一致
resources:
requests:
storage: 10Gi # 申请大小
# 应用 yaml 文件
[root@master statefulset]# kubectl apply -f pvc-nfs.yaml
# 查看pvc
[root@master statefulset]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Bound pv-nfs 10Gi RWX 9s
# 查看pv,绑定成功
[root@master statefulset]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 10Gi RWX Retain Bound default/pvc-nfs 10m
创建 nginx 应用 yaml 文件
# 创建 yaml 文件
[root@master statefulset]# cat nginx-nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep-nginx-pvc
namespace: default
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: c1
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 60
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: pvc-nfs
# 应用 yaml 文件
[root@master statefulset]# kubectl apply -f nginx-nfs.yaml
# 验证 pod
[root@master statefulset]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dep-nginx-pvc-68b64d7bdc-568bm 1/1 Running 0 63s 10.244.166.155 node1 <none> <none>
dep-nginx-pvc-68b64d7bdc-bhr57 1/1 Running 0 63s 10.244.104.45 node2 <none> <none>
dep-nginx-pvc-68b64d7bdc-gg5tf 1/1 Running 0 63s 10.244.104.39 node2 <none> <none>
dep-nginx-pvc-68b64d7bdc-xfqjj 1/1 Running 0 63s 10.244.166.151 node1 <none> <none>
# 访问验证
[root@master statefulset]# curl 10.244.166.155
hello nfs storage
[root@master statefulset]# curl 10.244.104.45
hello nfs storage
[root@master statefulset]# curl 10.244.104.39
hello nfs storage
[root@master statefulset]# curl 10.244.166.151
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



下载class插件文件
# 下载class插件文件
[root@master nfs-cli]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml
# 查看 yaml 文件
[root@master nfs-cli]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 动态供给插件
parameters:
archiveOnDelete: "false" # 删除数据是否存档
# 应用 yaml 文件
[root@master nfs-cli]# kubectl apply -f class.yaml
storageclass.storage.k8s.io/nfs-client created
# 查看资源
[root@master nfs-cli]# kubectl get storageclasses
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 11s
# RECLAIMPOLICY: pv回收策略,pod或者pvc被删除后,pv是否删除还是保留
# VOLUMEBINDINGMODE Immediate模式下pvc与pv立即绑定,主要是不等待相关pod调度完成,不关心其运行节点,直接完成
# ALLOWVOLUMEEXPANSION pvc扩容 false不允许,true允许
下载rbac文件
因为storage自动创建pv需要经过kube-apiserver,所以需要授权
# 下载并创建rbac文件
[root@master nfs-cli]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml
# 查看 rbac 文件
[root@master nfs-cli]# cat rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
# 应用 rbac 文件
[root@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
创建动态供给的deployment
需要一个deployment来专门实现pv与pvc的自动创建
# 下载 deployment 文件
[root@master nfs-cli]# wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/deployment.yaml
# 修改 deployment 文件
[root@master nfs-cli]# cat 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: 10.1.8.111 # 指定NFS地址
- name: NFS_PATH
value: /data/nfs # 指定挂载目录
volumes:
- name: nfs-client-root
nfs:
server: 10.1.8.111 # 指定NFS地址
path: /data/nfs # 指定挂载目录
# 应用 deployment 文件
[root@master nfs-cli]# kubectl apply -f deployment.yaml
deployment.apps/nfs-client-provisioner created
# 查看 pod 资源
[root@master nfs-cli]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-56b4c6986f-pbt7f 1/1 Running 0 10s
nginx应用使用动态供给
创建statefulset应用来调用名为nfs-client的storageclass,以实现动态供给
# 创建 yaml 文件
[root@master nfs-cli]# cat nginx-class-nfs.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx
spec:
ports:
- name: web
port: 80
clusterIP: None # 无头服务
selector:
app: nginx # 关联pod标签
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: nginx-svc # 管理service名称
replicas: 2
selector:
matchLabels:
app: nginx # 关联pod标签
template:
metadata:
labels:
app: nginx # pod标签
spec:
containers:
- name: nginx-c1 # 扩缩容会用到容器名
image: nginx:1.26-alpine
imagePullPolicy: IfNotPresent
ports:
- name: web
containerPort: 80
volumeMounts:
- name: www # 与Volume的name一致
mountPath: /usr/share/nginx/html
volumeClaimTemplates: # pvc模版
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-client" # storageClass名称
resources:
requests:
storage: 10Gi
# 应用 yaml 文件
[root@master nfs-cli]# kubectl apply -f nginx-class-nfs.yaml
service/nginx-svc unchanged
statefulset.apps/web created
# 验证
[root@master nfs-cli]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-client-provisioner-56b4c6986f-pbt7f 1/1 Running 0 29m 10.244.166.156 node1 <none> <none>
web-0 1/1 Running 0 6m12s 10.244.104.43 node2 <none> <none>
web-1 1/1 Running 0 6m10s 10.244.166.152 node1 <none> <none>
# 查看 service
[root@master nfs-cli]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
nginx-svc ClusterIP None <none> 80/TCP 2m39s
# 查看 pv与pvc 的绑定
[root@master nfs-cli]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-77ffebbf-e011-4447-89e3-dfd0976f6511 10Gi RWO Delete Bound default/www-web-0 nfs-client 73s
pvc-e21fcf3a-72e0-42bb-a703-176ed3eef062 10Gi RWO Delete Bound default/www-web-1 nfs-client 71s
[root@master nfs-cli]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pvc-77ffebbf-e011-4447-89e3-dfd0976f6511 10Gi RWO nfs-client 77s
www-web-1 Bound pvc-e21fcf3a-72e0-42bb-a703-176ed3eef062 10Gi RWO nfs-client 75s
到nfs-server中,查看/data/nfs目录,会发现有两个文件夹,保存两个pod网站数据
[root@NFS ~]# ls /data/nfs/
default-www-web-0-pvc-77ffebbf-e011-4447-89e3-dfd0976f6511 index.html
default-www-web-1-pvc-e21fcf3a-72e0-42bb-a703-176ed3eef062
# 分别写入index.html 内容查看
[root@NFS ~]# echo "this is web0" > /data/nfs/default-www-web-0-pvc-77ffebbf-e011-4447-89e3-dfd0976f6511/index.html
[root@NFS ~]# echo "this is web1" > /data/nfs/default-www-web-1-pvc-e21fcf3a-72e0-42bb-a703-176ed3eef062/index.html
# 访问验证
[root@master nfs-cli]# curl 10.244.104.43
this is web0
[root@master nfs-cli]# curl 10.244.166.152
this is web1
使用kube-dns解析无头服务域名,查看后端pod地址
# 查看kube-dns
[root@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 8d
# 解析无头服务
[root@master nfs-cli]# dig -t a nginx-svc.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-50.el7 <<>> -t a nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37016
;; 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.42
nginx-svc.default.svc.cluster.local. 30 IN A 10.244.166.158
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 二 8月 05 17:14:04 CST 2025
;; MSG SIZE rcvd: 166
# 解析pod域名
[root@master nfs-cli]# dig -t a web-0.nginx-svc.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-50.el7 <<>> -t a web-0.nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49031
;; 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.42
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 二 8月 05 17:15:09 CST 2025
;; MSG SIZE rcvd: 127
[root@master nfs-cli]# dig -t a web-1.nginx-svc.default.svc.cluster.local. @10.96.0.10
; <<>> DiG 9.9.4-RedHat-9.9.4-50.el7 <<>> -t a web-1.nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58790
;; 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.158
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 二 8月 05 17:15:04 CST 2025
;; MSG SIZE rcvd: 127
在集群里创建pod访问域名,观察负载均衡
# 创建centospod,并访问svc观察负载均衡
[root@master nfs-cli]# kubectl run -it centos --image=centos:7 --image-pull-policy=IfNotPresent
[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
金丝雀发布更新(灰度发布)
它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。
Statefulset可以使用partition参数来实现金丝雀更新,partition参数可以控制StatefulSet控制器更新的Pod,下面就进行StatefulSet控制器的金丝雀更新实战。
# 获取 StatefulSet yaml文件
[root@master nfs-cli]# kubectl get statefulsets web -o yaml
......
updateStrategy:
rollingUpdate:
partition: 0 # 默认分区号0,表示更新0及大于0的所有pod
type: RollingUpdate
......
使用patch参数来指定了statefu1set控制器的partition参数为1,表示当更新时,只有Pod的编号大于等于1的才更新。
# 使用 patch 参数指定StatefuleSet控制器的partition参数为1,无交互
[root@master nfs-cli]# kubectl patch statefulsets.apps web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition": 3}}}}'
statefulset.apps/web patched
# 再次观察
[root@master nfs-cli]# kubectl get statefulsets.apps web -o yaml
......
updateStrategy:
rollingUpdate:
partition: 3
type: RollingUpdate
......
# 也可交互式编辑
[root@master nfs-cli]# kubectl edit statefulsets.apps web
进行版本更新
# 查看版本
[root@master nfs-cli]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-56b4c6986f-dv4vc registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.26-alpine
web-2 nginx:1.26-alpine
web-3 nginx:1.26-alpine
web-4 nginx:1.26-alpine
web-5 nginx:1.26-alpine
# 更新版本
[root@master nfs-cli]# kubectl set image statefulset/web nginx-c1=nginx:1.29-alpine
statefulset.apps/web image updated
# 再次查看版本
[root@master nfs-cli]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-56b4c6986f-dv4vc registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.26-alpine
web-2 nginx:1.26-alpine
web-3 nginx:1.29-alpine
web-4 nginx:1.29-alpine
web-5 nginx:1.29-alpine
扩容数量,再次观察
# 扩容数量
[root@master nfs-cli]# kubectl scale statefulset web --replicas=10
statefulset.apps/web scaled
# 验证版本 columns:显示列
[root@master nfs-cli]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-56b4c6986f-dv4vc registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.26-alpine
web-2 nginx:1.26-alpine
web-3 nginx:1.29-alpine
web-4 nginx:1.29-alpine
web-5 nginx:1.29-alpine
web-6 nginx:1.29-alpine
web-7 nginx:1.29-alpine
web-8 nginx:1.29-alpine
web-9 nginx:1.29-alpine
结论:新增pod都为新版本
缩容数量观察版本
# 缩容数量
[root@master nfs-cli]# kubectl scale statefulset web --replicas=3
statefulset.apps/web scaled
# 查看版本
[root@master nfs-cli]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-56b4c6986f-dv4vc registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.26-alpine
web-2 nginx:1.26-alpine
结论:缩减的只有老版本,不可变基础设施
再次扩容,验证版本****
# 扩容数量
[root@master nfs-cli]# kubectl scale statefulset web --replicas=8
statefulset.apps/web scaled
# 验证版本
[root@master nfs-cli]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-56b4c6986f-dv4vc registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.26-alpine
web-2 nginx:1.26-alpine
web-3 nginx:1.29-alpine
web-4 nginx:1.29-alpine
web-5 nginx:1.29-alpine
web-6 nginx:1.29-alpine
web-7 nginx:1.29-alpine
结论:只要升级过版本之后,再次扩容超过partition的版本均为最新版本
nginx:1.29-alpine
web-7 nginx:1.29-alpine
web-8 nginx:1.29-alpine
web-9 nginx:1.29-alpine
**<font color='red'>结论:新增pod都为新版本</font>**
**缩容数量观察版本**
```bash
# 缩容数量
[root@master nfs-cli]# kubectl scale statefulset web --replicas=3
statefulset.apps/web scaled
# 查看版本
[root@master nfs-cli]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-56b4c6986f-dv4vc registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.26-alpine
web-2 nginx:1.26-alpine
结论:缩减的只有老版本,不可变基础设施
再次扩容,验证版本****
# 扩容数量
[root@master nfs-cli]# kubectl scale statefulset web --replicas=8
statefulset.apps/web scaled
# 验证版本
[root@master nfs-cli]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name Image
nfs-client-provisioner-56b4c6986f-dv4vc registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0 nginx:1.26-alpine
web-1 nginx:1.26-alpine
web-2 nginx:1.26-alpine
web-3 nginx:1.29-alpine
web-4 nginx:1.29-alpine
web-5 nginx:1.29-alpine
web-6 nginx:1.29-alpine
web-7 nginx:1.29-alpine
结论:只要升级过版本之后,再次扩容超过partition的版本均为最新版本

1559

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



