Kubernetes-Controller核心管理

Controller核心管理

控制器controller

controller作用及分类

controller用于控制pod

**官方文档:**https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/

image-20250801162122963

控制器主要分为:

  • 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 84 17:14 mysql202508040914.sql
-rw-r--r-- 1 root root 3771735 84 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组成

需要三个组成部分:

  1. headless service: 实现稳定,唯一的网络标识。
  2. statefulset类型资源: 写法和deployment几乎一致,就是类型不一样。
  3. 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

image-20250805134053302

实现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

image-20250805151011885

image-20250805151021591

image-20250805151025703

下载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的版本均为最新版本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值