Kubernetes-Controller

Kubernetes-Controller

控制器Controller

Controller作用

控制器controller用于控制Pod

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

Controller分类

控制器主要分为:

  • Deployment:部署无状态应用,控制Pod升级,回退
  • ReplicaSet:副本集,控制Pod扩容,缩减
  • ReplicationController:相当于ReplicaSet的老版本,现在建议使用Deployments加ReplicaSet替代RC
  • StatefulSet:部署有状态应用,结合Service、存储等实现对有状态应用的部署
  • DaemonSet:守护进程集,运行在所有集群节点(包括master),比如使用filebeat,node_exporter
  • Job:一次性任务
  • CronJob:周期性任务

Deployment

Deployment功能

  • Deployment集成了上线部署、滚动升级、创建副本、回滚等功能
  • Deployment里包含并使用了ReplicaSet

Deployment用于部署无状态应用

无状态应用的特点:

  • 所有Pod无差别
  • 所有Pod中容器运行同一个Image
  • 所有Pod可以运行在集群中任意node上
  • 所有Pod无启动顺序先后之分
  • 随意Pod数量扩容或缩容
创建deployment类型应用

准备yaml文件

# 获取帮助
[root@master deployment 18:46:21]# kubectl explain deployment
GROUP:      apps
KIND:       Deployment
VERSION:    v1
... ...

[root@master deployment 18:46:58]# vim nginx-deploy.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: web-test
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy	# deployment名称
  namespace: web-test	# 设置命名空间
spec:
  # 副本控制
  replicas: 2
  selector:
    matchLabels:
      app: nginx      	# 匹配模板标签,表示deployment和rs控制器控制带有此标签的Pod
  template:				# Pod的配置模板	
    metadata:
      labels:
        app: nginx    	# Pod标签
    spec:
      restartPolicy: Always
      containers:		# Pod中容器定义
        - name: c1
          image: nginx:1.26-alpine
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
          resources:
            limits:
              cpu: 150m
              memory: 300Mi
            requests:
              cpu: 100m
              memory: 200Mi
          # 存货探针
          livenessProbe:
            httpGet:
              port: http
              path: /index.html

验证yaml文件

[root@master deployment 18:51:25]# kubectl apply -f nginx-deploy.yaml 
deployment.apps/nginx-deploy created

# 验证
[root@master deployment 18:51:33]# kubectl get pods -n web-test 
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-84b89f5f96-7xhhn   1/1     Running   0          26s
nginx-deploy-84b89f5f96-f2ksn   1/1     Running   0          26s

查看deployment名称

[root@master deployment 18:53:21]# kubectl get deployment -n web-test 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   2/2     2            2           2m56s

查看replicas名称

[root@master deployment 18:54:50]# kubectl get replicaset -n web-test 
NAME                      DESIRED   CURRENT   READY   AGE
nginx-deploy-84b89f5f96   2         2         2       3m25s
访问deployment

查看Pod的IP地址

[root@master deployment 18:54:58]# kubectl get pod -o wide -n web-test 
NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
nginx-deploy-84b89f5f96-7xhhn   1/1     Running   0          4m23s   10.244.166.150   node1   <none>           <none>
nginx-deploy-84b89f5f96-f2ksn   1/1     Running   0          4m23s   10.244.104.11    node2   <none>           <none>

查看所有集群节点的网卡

[root@master deployment 18:55:56]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP>  mtu 1480
        inet 10.244.219.64  netmask 255.255.255.255
[root@node1 ~ 13:52:08]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP>  mtu 1480
        inet 10.244.166.128  netmask 255.255.255.255
[root@node2 ~ 13:52:10]# ifconfig tunl0 | head -2
tunl0: flags=193<UP,RUNNING,NOARP>  mtu 1480
        inet 10.244.104.0  netmask 255.255.255.255

可以看见集群节点的IP在10.244.0.0/16 这个大网段内的子网

在任意集群节点上都可以访问此deployment里的Pod

[root@master deployment 18:59:44]# ping -c 2 10.244.166.150
PING 10.244.166.150 (10.244.166.150) 56(84) bytes of data.
64 bytes from 10.244.166.150: icmp_seq=1 ttl=63 time=0.423 ms
64 bytes from 10.244.166.150: icmp_seq=2 ttl=63 time=0.369 ms

--- 10.244.166.150 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.369/0.396/0.423/0.027 ms
[root@node2 ~ 18:56:56]# curl http://10.244.166.150
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
删除deployment中的Pod

强制删除Pod(删除deployment中的Pod)

[root@master deployment 19:00:02]# kubectl delete pod nginx-deploy-84b89f5f96-7xhhn --grace-period=0 --force -n web-test 
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "nginx-deploy-84b89f5f96-7xhhn" force deleted

再次查看,发现又重新启动了一个新的Pod(并且IP发生了变化)

节点也可能会发生变化,这里是2副本效果不明显,可以将副本改成1再测试看看

[root@master deployment 19:02:44]# kubectl get pods -n web-test -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
nginx-deploy-84b89f5f96-f2ksn   1/1     Running   0          11m   10.244.104.11    node2   <none>           <none>
nginx-deploy-84b89f5f96-rmxs6   1/1     Running   0          51s   10.244.166.151   node1   <none>           <none>

总结:

pod的IP不是固定的,就算把整个集群关闭再启动,pod也会自动启动,但是IP地址会发生变化

然IP地址不是固定的,所以需要一个固定的访问endpoint给用户,那么这种方式就是service,这个我们后面再详细研究

Pod版本升级(支持多副本滚动升级)

查看帮助

[root@master deployment 19:02:55]# kubectl set image -h

升级前验证nginx版本

[root@master deployment 19:06:51]# kubectl describe pod nginx-deploy-84b89f5f96-f2ksn -n web-test | grep Image:
    Image:          nginx:1.26-alpine
# or
[root@master deployment 19:08:28]# kubectl exec nginx-deploy-84b89f5f96-f2ksn -n web-test -- nginx -v
nginx version: nginx/1.26.3

升级到1.29版本

语法格式:kubectl set image deployment deploy_name container_name=image_level --record

[root@master deployment 19:08:37]# kubectl get deployment -n web-test 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   2/2     2            2           17m

[root@master deployment 19:10:57]# kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine --record -n web-test 
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deploy image updated

# 验证
[root@master deployment 19:14:24]# kubectl get pods -n web-test 
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-5bcb87f6cf-nm9cz   1/1     Running   0          2m48s
nginx-deploy-5bcb87f6cf-pvsvh   1/1     Running   0          2m50s

[root@master deployment 19:14:42]# kubectl exec nginx-deploy-5bcb87f6cf-nm9cz -n web-test -- nginx -v
nginx version: nginx/1.29.4

命令说明:

  • deployment nginx-deploy 代表名为 deploy-nginx 的deployment
  • c1=nginx:1.29-alpine 前面的 c1 为容器名
  • –record 表示会记录

容器名称查看

kubectl describe pod pod_name
kubectl edit deployment deploy_name
kubectl get deployment deploy_name -o yaml

验证是否升级成功

[root@master deployment 19:15:04]# kubectl rollout status deployment nginx-deploy -n web-test 
deployment "nginx-deploy" successfully rolled out
Pod版本回退

查看版本历史信息

[root@master deployment 19:18:29]# kubectl rollout history deployment nginx-deploy -n web-test 
deployment.apps/nginx-deploy 
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine --record=true --namespace=web-test

定义要回退的版本(还需要执行才能真的回退版本)

[root@master deployment 19:23:38]# kubectl rollout history deployment -n web-test nginx-deploy --revision=1
deployment.apps/nginx-deploy with revision #1
Pod Template:
  Labels:	app=nginx
	pod-template-hash=84b89f5f96
  Containers:
   c1:
    Image:	nginx:1.26-alpine		# 可以看见编号1代表能执行到1.26版本
    Port:	80/TCP
    Host Port:	0/TCP
    Limits:
      cpu:	150m
      memory:	300Mi
    Requests:
      cpu:	100m
      memory:	200Mi
    Liveness:	http-get http://:http/index.html delay=0s timeout=1s period=10s #success=1 #failure=3
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

执行回退

[root@master deployment 19:26:55]# kubectl rollout undo deployment -n web-test nginx-deploy --to-revision=1
deployment.apps/nginx-deploy rolled back

验证

回到了1.26版本,且revision的ID增加了

[root@master deployment 19:29:45]# kubectl rollout history deployment -n web-test nginx-deploy 
deployment.apps/nginx-deploy 
REVISION  CHANGE-CAUSE
2         kubectl set image deployment nginx-deploy c1=nginx:1.29-alpine --record=true --namespace=web-test
3         <none>
[root@master deployment 19:30:33]# kubectl get pods -n web-test 
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-84b89f5f96-4lkjz   1/1     Running   0          114s
nginx-deploy-84b89f5f96-vmwsx   1/1     Running   0          112s
[root@master deployment 19:31:39]# kubectl describe pod nginx-deploy-84b89f5f96-4lkjz -n web-test | grep Image:
    Image:          nginx:1.26-alpine
[root@master deployment 19:33:48]# kubectl exec nginx-deploy-84b89f5f96-4lkjz -n web-test -- nginx -v
nginx version: nginx/1.26.3
Pod副本扩容

获取帮助

[root@master deployment 19:34:46]# kubectl scale -h

扩容成4副本

[root@master deployment 19:34:57]# kubectl scale deployment nginx-deploy -n web-test --replicas=4
deployment.apps/nginx-deploy scaled

# 验证
[root@master deployment 19:35:36]# kubectl get deployments -n web-test 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   4/4     4            4           44m

[root@master deployment 19:36:17]# kubectl get pods -n web-test -o wide
NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
nginx-deploy-84b89f5f96-4lkjz   1/1     Running   0          6m57s   10.244.104.13    node2   <none>           <none>
nginx-deploy-84b89f5f96-6qrvh   1/1     Running   0          66s     10.244.104.14    node2   <none>           <none>
nginx-deploy-84b89f5f96-vjn5v   1/1     Running   0          66s     10.244.166.154   node1   <none>           <none>
nginx-deploy-84b89f5f96-vmwsx   1/1     Running   0          6m55s   10.244.166.153   node1   <none>           <none>
Pod副本缩容

修改replicas 的参数即可

[root@master deployment 19:37:40]# kubectl scale deployment nginx-deploy -n web-test --replicas=1
deployment.apps/nginx-deploy scaled

# 验证
[root@master deployment 19:38:18]# kubectl get deployments -n web-test 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   1/1     1            1           46m

[root@master deployment 19:38:37]# kubectl get pods -n web-test -o wide
NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
nginx-deploy-84b89f5f96-vmwsx   1/1     Running   0          9m10s   10.244.166.153   node1   <none>           <none>

副本数量可以降为0,有需要就启动,无需要就停止

[root@master deployment 19:38:57]# kubectl scale deployment nginx-deploy -n web-test --replicas=0
deployment.apps/nginx-deploy scaled

# 验证
[root@master deployment 19:39:55]# kubectl get deployments -n web-test 
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy   0/0     0            0           48m
[root@master deployment 19:40:07]# kubectl get pods -n web-test 
No resources found in web-test namespace.
删除deployment

删除deployment,里面的Pod也会被自动删除

# 先扩容
[root@master deployment 19:40:14]# kubectl scale deployment nginx-deploy -n web-test --replicas=5
deployment.apps/nginx-deploy scaled
[root@master deployment 19:42:31]# kubectl get pods -n web-test 
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-84b89f5f96-26f5q   1/1     Running   0          7s
nginx-deploy-84b89f5f96-4d95d   1/1     Running   0          7s
nginx-deploy-84b89f5f96-7bd8q   1/1     Running   0          7s
nginx-deploy-84b89f5f96-sh2cm   1/1     Running   0          7s
nginx-deploy-84b89f5f96-wrnlx   1/1     Running   0          7s

# 删除
[root@master deployment 19:42:38]# kubectl delete deployment -n web-test nginx-deploy 
deployment.apps "nginx-deploy" deleted

# 验证
[root@master deployment 19:43:03]# kubectl get pods -n web-test 
No resources found in web-test namespace.

ReplicaSet

replicaset控制器很少单独使用,不建议脱离deployment

  • 支持新的基于集合的selector(以前的rc里没有这种功能)
  • 通过改变Pod副本数量实现Pod的扩容和缩容

准备yaml文件

[root@master deployment 19:44:54]# vim rs-nginx.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
      name: nginx
    spec:
      containers:
      - name: c1
        image: nginx:1.26-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80

应用yaml

[root@master deployment 19:45:59]# kubectl apply -f rs-nginx.yaml 
replicaset.apps/rs-nginx created

# 验证
[root@master deployment 19:46:06]# kubectl get replicaset 
NAME       DESIRED   CURRENT   READY   AGE
rs-nginx   2         2         2       19s
[root@master deployment 19:46:25]# kubectl get pods
NAME             READY   STATUS    RESTARTS        AGE
rs-nginx-hkwh2   1/1     Running   0               27s
rs-nginx-j7cd8   1/1     Running   0               27s
[root@master deployment 19:47:14]# kubectl get deployments 
No resources found in default namespace.

找不到deployment,说明创建rs并没有创建deployment

扩容测试

[root@master deployment 19:47:23]# kubectl scale replicaset rs-nginx --replicas=4
replicaset.apps/rs-nginx scaled

# 验证
[root@master deployment 19:49:00]# kubectl get replicaset 
NAME       DESIRED   CURRENT   READY   AGE
rs-nginx   4         4         4       3m1s
[root@master deployment 19:49:07]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
rs-nginx-d4rj4   1/1     Running   0          13s
rs-nginx-hkwh2   1/1     Running   0          3m7s
rs-nginx-j7cd8   1/1     Running   0          3m7s
rs-nginx-qrpvz   1/1     Running   0          13s

说明replicaset 可以扩缩容

版本测试

# 查看版本
[root@master deployment 19:50:11]# kubectl describe pods rs-nginx-d4rj4 | grep Image:
    Image:          nginx:1.26-alpine
    
[root@master deployment 19:51:50]# kubectl set image replicaset rs-nginx c1=nginx:1.29-alpine --record
Flag --record has been deprecated, --record will be removed in the future
replicaset.apps/rs-nginx image updated

# 检查
[root@master deployment 19:53:16]# kubectl describe pods rs-nginx-d4rj4 | grep Image:
    Image:          nginx:1.26-alpine

说明replicaset 可以扩缩容,版本并没发生变化,replicaset无法实现版本更新

DaemonSet

DaemonSet功能

  • Daemonset能够让所有(或者特定)的节点运行同一个pod
  • 当节点加入到K8s集群中,pod会被(DaemonSet)调度到该节点上运行,当节点从K8S集群中被移除,被Daemonset调度的pod会被移除
  • 如果删除DaemonSet,所有跟这个DaemonSet相关的pods都会被删除
  • 如果一个DaemonSet的Pod被杀死、停止、或者崩溃,那么DaemonSet将会重新创建一个新的副本在这台计算节点上
  • DaemonSet一般应用于日志收集、监控采集、分布式存储守护进程等

DaemonSet用于部署守护进程

准备yaml文件

[root@master daemonset 15:21:13]# vim ds-nginx.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
      name: ds-nginx
    spec:
      #设置污点
      tolerations:								# 代表容忍,保证在所有节点运行
      - key: node-role.kubernetes.io/master		# 能容忍的污点key
        effect: NoSchedule						# 能容忍的污点effect
      containers:
      - name: nginx
        image: nginx:1.26-alpine
        imagePullPolicy: IfNotPresent
        resources:
          limits:
            memory: 100Mi
          requests:
            memory: 100Mi

应用yaml文件

[root@master daemonset 15:27:22]# kubectl apply -f ds-nginx.yaml 
daemonset.apps/daemonset-nginx created

# 验证
[root@master daemonset 15:27:32]# kubectl get daemonset
NAME              DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset-nginx   2         2         2       2            2           <none>          7s

[root@master daemonset 15:27:39]# kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
daemonset-nginx-28qf7   1/1     Running   0          63s   10.244.166.166   node1   <none>           <none>
daemonset-nginx-9xzdv   1/1     Running   0          63s   10.244.104.25    node2   <none>           <none>

无法进行扩缩容,可以进行版本升级

版本测试
[root@master daemonset 15:30:37]# kubectl describe pods daemonset-nginx-28qf7 | grep Image: 
    Image:          nginx:1.26-alpine
    
# 升级操作
[root@master daemonset 15:39:14]# kubectl set image daemonset daemonset-nginx nginx=nginx:latest
daemonset.apps/daemonset-nginx image updated

# 验证
[root@master daemonset 15:40:31]# kubectl describe pods daemonset-nginx-hw9mf | grep Image:
    Image:          nginx:latest

Job

Job介绍

对于于ReplicaSet而言,它希望pod保持预期数目、持久运行下去,除非用户明确删除,否则这些对象一直存在,它们针对的是耐久性任务如web服务等

对于非耐久性任务,比如压缩文件,任务完成后,pod需要结束运行,不需要pod继续保持在系统中,这个时候就要用到Job

Job负责批量处理短暂的一次性任务(short lived one-of tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束

Job应用案例

计算圆周率2000位

编写yaml文件

[root@master job 15:48:23]# vim job-pi.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      name: pod-pi
    spec:
      nodeName: node2
      containers:
      - name: c-pi
        image: perl
        imagePullPolicy: IfNotPresent
        command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
      restartPolicy: Never

应用yaml文件

[root@master job 15:58:29]# kubectl apply -f job-pi.yaml 
job.batch/pi created

# 验证
[root@master job 15:58:35]# kubectl get job
NAME   COMPLETIONS   DURATION   AGE
pi     1/1           6s         25s
[root@master job 15:59:00]# kubectl get pods
NAME                    READY   STATUS      RESTARTS   AGE
pi-75xzf                0/1     Completed   0          36s

# 查看结果
[root@master job 16:01:59]# kubectl logs pi-75xzf
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
创建固定次数Job

编写yaml文件

[root@master job 16:03:07]# vim job-num.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: busybox-job
spec:
  completions: 10       # 执行job次数
  parallelism: 2        # 执行job并发数
  template:
    metadata:
      name: busybox-job-pod
    spec:
      nodeName: node2
      containers:
        - name: c1
          image: busybox
          imagePullPolicy: IfNotPresent
          command: ["echo","hello"]
      restartPolicy: Never

应用yaml文件

[root@master job 16:10:25]# kubectl apply -f job-num.yaml 
job.batch/busybox-job created

# 验证
[root@master job 16:10:28]# kubectl get pods
NAME                READY   STATUS      RESTARTS   AGE
busybox-job-4bm4t   0/1     Completed   0          77s
busybox-job-6cnb2   0/1     Completed   0          75s
busybox-job-8h7xn   0/1     Completed   0          93s
busybox-job-dd6qw   0/1     Completed   0          74s
busybox-job-gf4xj   0/1     Completed   0          71s
busybox-job-hpfdp   0/1     Completed   0          78s
busybox-job-hzdz7   0/1     Completed   0          93s
busybox-job-kb54l   0/1     Completed   0          72s
busybox-job-mngqh   0/1     Completed   0          80s
busybox-job-vtpb8   0/1     Completed   0          69s

[root@master job 16:12:01]# kubectl get job
NAME          COMPLETIONS   DURATION   AGE
busybox-job   10/10         27s        2m9s

# 查看输出内容
[root@master job 16:12:37]# kubectl logs busybox-job-gf4xj
hello
一次性备份MySQL数据库

通过job控制器创建应用备份mysql数据库

mysql数据库准备

[root@master job 16:22:20]# vim mysql.yaml
apiVersion: v1
kind: Service
metadata: 
  name: mysql-test
  namespace: default
spec:
  ports:
    - port: 3306
      name: mysql
  clusterIP: None       # 无头服务
  selector: 
    app: mysql-dump     # 匹配pod标签
---
apiVersion: apps/v1
kind: StatefulSet       # 有状态控制器
metadata:
  name: db
  namespace: default
spec:
  selector:
    matchLabels:
      app: mysql-dump
  serviceName: "mysql-test"
  template:
    metadata:
      labels:
        app: mysql-dump         # pod名称
    spec:
      nodeName: node1           # 资源创建在node1
      containers:
        - name: mysql           # 容器名称
          image: mysql:5.7
          env:
            - name: MYSQL_ROOT_PASSWORD         # mysql管理员密码设置
              value: "abc123"
          ports:
            - containerPort: 3306
          volumeMounts:                         # 数据库中数据挂载
            - mountPath: "/var/lib/mysql"
              name: mysql-data
      volumes:
        - name: mysql-data
          hostPath:
            path: /opt/mysqldata

应用yaml文件

[root@master job 16:48:38]# kubectl apply -f mysql.yaml 
service/mysql-test unchanged
statefulset.apps/db created

# 验证
[root@master job 16:49:39]# kubectl get svc,statefulset,pod 
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP    9d
service/mysql-test   ClusterIP   None         <none>        3306/TCP   4m42s

NAME                  READY   AGE
statefulset.apps/db   1/1     81s

NAME       READY   STATUS    RESTARTS   AGE
pod/db-0   1/1     Running   0          81s

在node1节点,查看数据库目录

[root@node1 ~ 16:53:49]# cd /opt/mysqldata/
[root@node1 mysqldata 16:53:55]# ls
auto.cnf    client-cert.pem  ibdata1      ibtmp1      performance_schema  server-cert.pem
ca-key.pem  client-key.pem   ib_logfile0  mysql       private_key.pem     server-key.pem
ca.pem      ib_buffer_pool   ib_logfile1  mysql.sock  public_key.pem      sys

创建用于实现备份任务的资源清单

[root@master job 16:54:48]# vim mysql-dump.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: mysql-dump
spec:
  template:
    metadata:
      name: mysql-dump
    spec:
      nodeName: node2           # 资源城建到node2
      containers:
      - name: mysql-dump
        image: mysql:5.7
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql_back.sql"]
        volumeMounts:
        - mountPath: "/root"
          name: mysql-data
      volumes:
      - name: mysql-data
        hostPath: 
          path: /opt/mysqldump
      restartPolicy: Never

应用yaml文件

[root@master job 17:03:04]# kubectl apply -f mysql-dump.yaml 
job.batch/mysql-dump created

# 验证
[root@master job 17:03:33]# kubectl get job,pods
NAME                   COMPLETIONS   DURATION   AGE
job.batch/mysql-dump   1/1           4s         42s

NAME                   READY   STATUS      RESTARTS   AGE
pod/db-0               1/1     Running     0          15m
pod/mysql-dump-hr9mx   0/1     Completed   0          42s

在node2节点上查看备份的sql文件

[root@node2 ~ 17:04:25]# cd /opt/mysqldump/
[root@node2 mysqldump 17:04:35]# ls
mysql_back.sql

CronJob

类似于Linux系统的crontab,在指定的时间周期运行相关的任务

CronJob应用案例

周期性输出字符

编写yaml文件

[root@master cronjob 18:07:48]# vim cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob1
spec:
  schedule: "* * * * *"         # 分时日月周
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: hello
              image: busybox:latest
              args:
              - /bin/sh
              - -c
              - date; echo "hello kubernetes"
              imagePullPolicy: IfNotPresent
          restartPolicy: OnFailure

应用yaml文件

[root@master cronjob 18:22:16]# kubectl apply -f cronjob.yaml 
cronjob.batch/cronjob1 created

# 验证
[root@master cronjob 18:22:39]# kubectl get cronjob
NAME       SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob1   * * * * *   False     0        <none>          7s
[root@master cronjob 18:22:56]# kubectl get pod
NAME                      READY   STATUS      RESTARTS   AGE
cronjob1-29488943-h7wfb   0/1     Completed   0          9s

# 查看内容
[root@master cronjob 18:23:55]# kubectl logs cronjob1-29488943-h7wfb 
Sun Jan 25 10:23:00 UTC 2026
hello kubernetes
周期性备份MySQL数据库

MySQL数据库准备

[root@master cronjob 18:24:29]# vim mysql.yaml
apiVersion: v1
kind: Service 
metadata:
  name: mysql-test
  namespace: default
spec:
  ports:
    - port: 3306
      name: mysql
  clusterIP: None
  selector:
    app: mysql-dump
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  namespace: default
spec:
  selector:
    matchLabels:
      app: mysql-dump
  serviceName: "mysql-test"
  template:
    metadata:
      labels:
        app: mysql-dump
    spec:
      nodeName: node2
      containers:
        - name: mysql
          image: mysql:5.7
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: "abc123"
          ports:
            - containerPort: 3306
          volumeMounts:
            - mountPath: "/var/lib/mysql"
              name: mysql-data
      volumes:
        - name: msyql-data
          hostPath:
            path: /opt/mysqldata

应用yaml文件

[root@master cronjob 18:49:01]# kubectl apply -f mysql.yaml 
service/mysql-test created
statefulset.apps/db created

# 验证
[root@master cronjob 19:23:43]# kubectl get statefulset
NAME   READY   AGE
db     1/1     8s
[root@master cronjob 19:23:51]# kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
db-0   1/1     Running   0          12s

编写cronjob控制mysql备份清单

[root@master cronjob 19:24:59]# vim mysql-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: mysql-dump
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          nodeName: node2
          containers:
          - name: c1
            image: mysql:5.7
            command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql`date +%Y%m%d%H%M`.sql"]
            volumeMounts:
            - name: mysql-data
              mountPath: "/root"
          restartPolicy: Never
          volumes:
            - name: mysql-data
              hostPath:
                path: /opt/mysqldump

应用yaml文件

[root@master cronjob 19:35:41]# kubectl apply -f mysql-cronjob.yaml 
cronjob.batch/mysql-dump created

# 验证
# 这里需要等待一会,cronjob不是立刻就执行的
[root@master cronjob 19:37:37]# kubectl get cronjob
NAME         SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
mysql-dump   */1 * * * *   False     0        7s              109s

[root@master cronjob 19:38:07]# kubectl get pods
NAME                        READY   STATUS      RESTARTS   AGE
db-0                        1/1     Running     0          14m
mysql-dump-29489017-6fj8h   0/1     Completed   0          102s
mysql-dump-29489018-7nnsz   0/1     Completed   0          42s

# 在node2 节点查看备份内容
[root@node2 opt 19:35:34]# ls mysqldump/
mysql202601251137.sql  mysql202601251138.sql  mysql202601251139.sql

StatefulSet

StatefulSet功能

  • Statefulset 是用来管理有状态应用的控制器
  • Statefulset 用来管理应用的部署、扩缩容及滚动更新
  • Statefulset 为 Pod 提供持久存储和持久标识符

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

StatefulSet用于部署有状态应用

有状态应用的特点:

  • 比如MySQL
  • 前后请求有关联与依赖
  • 稳定的、持久的存储。(通过静态存储PV,PVC,动态存储storageclass实现)
  • 稳定的、唯一的网络标识符。(无clusterIP通过headless服务实现)
  • 有序的、优雅的部署和缩放
  • 有序的、自动的滚动更新(从最大数更新,例如:编号2,编号1,编号0)

StatefulSet的YAML组成

三部分:

  • headless service: 实现稳定,唯一的网络标识
  • statefulset类型资源: 写法和deployment几乎一致,就是类型不一样
  • volumeClaimTemplate:指定存储卷

创建StatefulSet类型应用

网络存储NFS部署

新建一台虚拟机作为nfs存储节点:IP 192.168.108.130

[root@nfs ~ 19:52:44]# mkdir -p /data/nfs

[root@nfs ~ 19:52:44]# vim /etc/exports
/data/nfs       *(rw,no_root_squash,sync)
#解释:*允许所有用户访问    rw可读写     no_root_squash禁用安全降权规则

[root@nfs ~ 19:54:06]# systemctl restart nfs-server.service
[root@nfs ~ 19:56:16]# systemctl enable nfs-server.service
[root@nfs ~ 19:56:45]# systemctl stop firewalld.service
[root@nfs ~ 19:56:49]# setenforce 0

[root@nfs ~ 19:57:26]# showmount -e
Export list for nfs:
/data/nfs *

给所有node节点安装nfs客户端软件包

node1-2

yum install nfs-utils -y

验证nfs可用性

[root@node1 ~ 19:58:40]# showmount -e 192.168.108.130
Export list for 192.168.108.130:
/data/nfs *

[root@node2 ~ 19:58:55]# showmount -e 192.168.108.130
Export list for 192.168.108.130:
/data/nfs *

编写yaml文件

[root@master statefulset 20:00:18]# vim volume-nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: volume-nfs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.26-alpine
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: documentroot
          mountPath: /usr/share/nginx/html
        ports:
        - containerPort: 80
      volumes:
        - name: documentroot
          nfs:
            path: /data/nfs
            server: 192.168.108.130

应用yaml文件

[root@master statefulset 20:09:20]# kubectl apply -f volume-nfs.yaml 
deployment.apps/volume-nfs created

# 验证
[root@master statefulset 20:09:29]# kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
volume-nfs-55c6597bd4-b5zrx   1/1     Running   0          20s
volume-nfs-55c6597bd4-r9r6l   1/1     Running   0          20s

在nfs服务器上创建index文件

[root@nfs ~ 19:57:31]# cd /data/nfs/
[root@nfs nfs 20:10:23]# ls
[root@nfs nfs 20:10:37]# echo "hello nfs storage" > index.html

在master上直接验证查看

[root@master statefulset 20:09:49]# kubectl get pod -o wide
NAME                          READY   STATUS    RESTARTS   AGE    IP               NODE    NOMINATED NODE   READINESS GATES
volume-nfs-55c6597bd4-b5zrx   1/1     Running   0          119s   10.244.104.44    node2   <none>           <none>
volume-nfs-55c6597bd4-r9r6l   1/1     Running   0          119s   10.244.166.173   node1   <none>           <none>

[root@master statefulset 20:11:28]# curl http://10.244.104.44
hello nfs storage
[root@master statefulset 20:11:40]# curl http://10.244.166.173
hello nfs storage
PV(持久化存储卷)与 PVC(持久存储卷声明)

kubernetes存储卷的分类太丰富了,每种类型都要写相应的接口与参数才行,这就让维护与管理难度加大

kubernetes支持分类查看

官方文档:https://kubernetes.io/zh-cn/docs/concepts/storage/

persistenvolume(PV)是配置好的一个存储(可以是任意类型的存储卷)

  • 也就是说将网络存储共享出来,配置定义成PV

PersistentVolumeClaim(PVC)是用户pod使用PV的申请请求

  • 用户不需要关心具体的volume实现细节,只需要关心使用需求

pv和pvc之间的关系

  • pv提供存储资源
  • pvc使用存储资源
  • 使用pvc绑定pv

在这里插入图片描述

实现nfs类型pv和pvc

创建pv的yaml文件

[root@master statefulset 20:48:02]# vim pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume          # 类型pv
metadata:
  name: pv-nfs
spec:
  capacity:
    storage: 1Gi                # 大小
  accessModes:
  - ReadWriteMany               # 访问方式
  nfs:
    path: /data/nfs
    server: 192.168.108.130

我们要实现多个nginx跨节点之间的数据共享,所以选择ReadWriteMany模式

访问方式有三种:

官方文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes

  • ReadWriteOnce:单节点读写挂载
  • ReadOnlyMany:多节点只读挂载
  • ReadWriteMany:多节点读写挂载
  • ReadWriteOncePod:卷可以被单个Pod以读写方式挂载(1.29新特性)

应用yaml文件,创建pv并验证

[root@master statefulset 21:03:37]# kubectl apply -f pv-nfs.yaml 
persistentvolume/pv-nfs created

[root@master statefulset 21:03:51]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-nfs   1Gi        RWX            Retain           Available                                   7s

说明:

  • RWX为ReadWriteMany的简写
  • Retain是回收策略
    • Retain表示不使用了需要手动回收
    • 官方文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaim-policy

创建pvc的yaml文件

[root@master statefulset 21:03:58]# vim pvc-nfs.yaml
apiVersion: v1
kind: PersistentVolumeClaim     # 类型pvc
metadata:
  name: pvc-nfs
spec:
  accessModes:
  - ReadWriteMany       # 访问模式
  resources:
    requests:
      storage: 1Gi        # 大小与pv一致

应用yaml文件

[root@master statefulset 21:08:45]# kubectl apply -f pvc-nfs.yaml 
persistentvolumeclaim/pvc-nfs created

# 验证
[root@master statefulset 21:08:47]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-nfs   Bound    pv-nfs   1Gi        RWX                           45s

创建nginx的yaml文件

[root@master statefulset 21:10:02]# vim nginx-pvc-nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-pvc-nfs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.26-alpine
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
      volumes:
      - name: www
        persistentVolumeClaim:
          claimName: pvc-nfs

应用yaml文件

[root@master statefulset 21:19:42]# kubectl apply -f nginx-pvc-nfs.yaml 
deployment.apps/nginx-pvc-nfs created

[root@master statefulset 21:20:56]# kubectl get pod -o wide
NAME                             READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
nginx-pvc-nfs-5d8644564b-gqrqn   1/1     Running   0          72s   10.244.166.174   node1   <none>           <none>
nginx-pvc-nfs-5d8644564b-w77mg   1/1     Running   0          72s   10.244.104.45    node2   <none>           <none>

[root@master statefulset 21:21:00]# curl http://10.244.166.174
hello nfs storage
[root@master statefulset 21:21:23]# curl http://10.244.104.45
hello nfs storage
动态供给

每次使用存储要先创建pv,再创建pvc,非常的繁琐,所以我们可以实现使用存储的动态供给特性

  • 静态存储需要用户申请PVC时保证容量和读写类型与预置PV的容量及读写类型完全匹配,而动态存储则无需如此
  • 管理员无需预先创建大量的PV作为存储资源

Kubernetes从1.4版起引入了一个新的资源对象StorageClass,可用于将存储资源定义为具有显著特性的类(Class)而不是具体的PV。用户通过PVC直接向意向的类别发出申请,匹配由管理员事先创建的PV,或 者由其按需为用户动态创建PV,这样就免去了需要先创建PV的过程

实现动态供给部署nfs存储

官方插件不支持NFS动态供给,可以使用第三方插件来实现

第三方插件地址: https://github.com/kubernetes-retired/external-storage

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建一个新的目录

[root@master statefulset 21:38:07]# mkdir nfs-cli
[root@master statefulset 21:38:07]# cd nfs-cli/

下载class、rbac、deployment文件

wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml
wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml
wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/deployment.yaml

修改class文件

[root@master nfs-cli 21:53:39]# vim class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass				# 类型
metadata:
  name: nfs-client				# 名称,要使用就需要调用此名称
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 动态供给插件
parameters:
  archiveOnDelete: "false"		# 删除数据时是否存档,false表示不存档,true表示存档
  
[root@master nfs-cli 21:59:52]# cp class.yaml storageclass-nfs.yaml

应用yaml文件

[root@master nfs-cli 22:00:36]# kubectl apply -f storageclass-nfs.yaml 
storageclass.storage.k8s.io/nfs-client created

[root@master nfs-cli 22:00:45]# kubectl get storageclass
NAME         PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  19s

说明:

  • RECLAIMPOLICY pv回收策略,pod或者pvc被删除后,pv是否删除还是保留
  • VOLUMEBINDINGMODE Immediate模式下pvc与pv立即绑定,主要是不等待相关pod调度完成,不关心其运行节点,直接完成
  • ALLOWVOLUMEEXPANSION pvc扩容 false不允许,true允许

应用rbac.yaml文件

因为storage自动创建pv需要经过kube-apiserver,所以需要授权

[root@master nfs-cli 22:03:44]# cp rbac.yaml storageclass-nfs-rbac.yaml

[root@master nfs-cli 22:03:44]# kubectl apply -f storageclass-nfs-rabc.yaml 
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created

修改deployment.yaml文件

需要一个deployment来专门实现pv与pvc的自动创建

[root@master nfs-cli 22:04:09]# vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0         # 替换国内镜像源
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 192.168.108.130		# nfs服务器地址
            - name: NFS_PATH
              value: /data/nfs				# 共享目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.108.130			# nfs服务器地址
            path: /data/nfs					# 共享目录

应用yaml文件

[root@master nfs-cli 22:06:39]# kubectl apply -f deployment.yaml 
deployment.apps/nfs-client-provisioner created

[root@master nfs-cli 22:06:47]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-69dff6bc9f-tnr5x   1/1     Running   0          8s

nginx应用使用动态供给

创建statefulSet 应用来调用名为nfs-client的storageclass,以实现动态供给

[root@master nfs-cli 22:06:55]# vim nginx-storageclass-nfs.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None               # 无头服务
  selector:
    app: nginx                  # service关联pod标签
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web                     # 名称+编号=pod名称
spec:
  serviceName: "nginx-svc"      # 关联service名称
  replicas: 2
  selector:
    matchLabels:
      app: nginx                # 控制器关联pod标签
  template:
    metadata:
      labels:
        app: nginx              # pod标签
    spec:
      containers:
      - name: nginx-c           # 扩缩容用到的容器名
        image: nginx:1.26-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:          # pvc模板
  - metadata:
      name: www                 # 构成pvc名称
    spec:
      accessModes: ["ReadWriteOnce"] 
      storageClassName: "nfs-client"
      resources:
        requests:
          storage: 1Gi

应用yaml文件

[root@master nfs-cli 22:23:23]# kubectl apply -f nginx-storageclass-nfs.yaml 
service/nginx-svc created
statefulset.apps/web created

[root@master nfs-cli 22:23:29]# kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-69dff6bc9f-tnr5x   1/1     Running   0          16m
web-0                                     1/1     Running   0          17s
web-1                                     1/1     Running   0          15s

[root@master nfs-cli 22:23:46]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   11d
nginx-svc    ClusterIP   None         <none>        80/TCP    78s

[root@master nfs-cli 22:24:00]# kubectl get statefulset
NAME   READY   AGE
web    2/2     46s

查看pv状态

[root@master nfs-cli 22:24:47]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-355a273e-733f-4b2b-94d0-5734bc5204bb   1Gi        RWO            Delete           Bound    default/www-web-1   nfs-client              80s
pvc-e75af000-1841-4ad6-a1a2-8a3d69b26b22   1Gi        RWO            Delete           Bound    default/www-web-0   nfs-client              82s

查看pvc状态

[root@master nfs-cli 22:24:51]# kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pvc-e75af000-1841-4ad6-a1a2-8a3d69b26b22   1Gi        RWO            nfs-client     84s
www-web-1   Bound    pvc-355a273e-733f-4b2b-94d0-5734bc5204bb   1Gi        RWO            nfs-client     82s

到nfs服务器查看/data/nfs目录,会发现有两个文件夹,保存两个pod网站数据

[root@nfs ~ 22:25:34]# cd /data/nfs/
[root@nfs nfs 22:25:57]# ls
default-www-web-0-pvc-e75af000-1841-4ad6-a1a2-8a3d69b26b22  default-www-web-1-pvc-355a273e-733f-4b2b-94d0-5734bc5204bb

往两个目录中分别写入index.html内容进行查看

[root@nfs nfs 22:25:59]# echo "this is web0" > default-www-web-0-pvc-e75af000-1841-4ad6-a1a2-8a3d69b26b22/index.html
[root@nfs nfs 22:27:28]# echo "this is web1" > default-www-web-1-pvc-355a273e-733f-4b2b-94d0-5734bc5204bb/index.html

# master节点查看
[root@master nfs-cli 22:24:53]# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
nfs-client-provisioner-69dff6bc9f-tnr5x   1/1     Running   0          21m     10.244.166.175   node1   <none>           <none>
web-0                                     1/1     Running   0          4m50s   10.244.104.46    node2   <none>           <none>
web-1                                     1/1     Running   0          4m48s   10.244.166.176   node1   <none>           <none>

[root@master nfs-cli 22:28:19]# curl http://10.244.104.46
this is web0
[root@master nfs-cli 22:28:35]# curl http://10.244.166.176
this is web1

使用kube-dns解析无头服务域名,可以直接看到后端pod的地址

[root@master nfs-cli 22:28:42]# kubectl get svc -n kube-system 
NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
kube-dns         ClusterIP   10.96.0.10    <none>        53/UDP,53/TCP,9153/TCP   11d
metrics-server   ClusterIP   10.99.68.52   <none>        443/TCP                  10d

[root@master nfs-cli 22:29:39]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   11d
nginx-svc    ClusterIP   None         <none>        80/TCP    7m25s

[root@master nfs-cli 22:30:07]# dig -t a nginx-svc.default.svc.cluster.local. @10.96.0.10

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.16 <<>> -t a nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24089
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nginx-svc.default.svc.cluster.local. IN	A

;; ANSWER SECTION:
nginx-svc.default.svc.cluster.local. 30	IN A	10.244.104.46
nginx-svc.default.svc.cluster.local. 30	IN A	10.244.166.176

;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 日 125 22:30:43 CST 2026
;; MSG SIZE  rcvd: 166

解析pod域名

[root@master nfs-cli 22:32:43]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-69dff6bc9f-tnr5x   1/1     Running   0          26m
web-0                                     1/1     Running   0          9m20s
web-1                                     1/1     Running   0          9m18s

[root@master nfs-cli 22:32:49]# dig -t a web-0.nginx-svc.default.svc.cluster.local. @10.96.0.10

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.16 <<>> -t a web-0.nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28705
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web-0.nginx-svc.default.svc.cluster.local. IN A

;; ANSWER SECTION:
web-0.nginx-svc.default.svc.cluster.local. 30 IN A 10.244.104.46	`看这里`

;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 日 125 22:33:06 CST 2026
;; MSG SIZE  rcvd: 127

[root@master nfs-cli 22:33:06]# dig -t a web-1.nginx-svc.default.svc.cluster.local. @10.96.0.10

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.16 <<>> -t a web-1.nginx-svc.default.svc.cluster.local. @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53549
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web-1.nginx-svc.default.svc.cluster.local. IN A

;; ANSWER SECTION:
web-1.nginx-svc.default.svc.cluster.local. 30 IN A 10.244.166.176		`看这里`

;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: 日 125 22:33:13 CST 2026
;; MSG SIZE  rcvd: 127

创建一个测试pod,观察负载均衡

[root@master nfs-cli 22:35:00]# kubectl run -it centos --image=centos:7 --image-pull-policy=IfNotPresent
If you don't see a command prompt, try pressing enter.
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is web0
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is web0
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is web1
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.
this is web1
[root@centos /]# curl http://nginx-svc.default.svc.cluster.local.

直接访问pod域名

[root@centos /]# curl http://web-0.nginx-svc.default.svc.cluster.local.
this is web0
[root@centos /]# curl http://web-1.nginx-svc.default.svc.cluster.local.
this is web1
金丝雀发布更新(灰度发布)

它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod

Statefulset可以使用partition参数来实现金丝雀更新,partition参数可以控制StatefulSet控制器更新的 Pod,下面,就进行StatefulSet控制器的金丝雀更新实战

[root@master nfs-cli 13:49:21]# kubectl get sts web -o yaml
...
  updateStrategy:
    rollingUpdate:
      partition: 0			#默认分区号0,表示更新0及大于0的所有pod
    type: RollingUpdate
...

使用patch参数来指定statefulset控制器的partition参数为1,表示当更新时,只有Pod编号大于等于1的才更新

修改更新

[root@master nfs-cli 13:59:04]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'

# 再次观察,查看patch参数
...
  updateStrategy:
    rollingUpdate:
      partition: 1
    type: RollingUpdate
...

查看当前版本

[root@master nfs-cli 13:59:04]# kubectl describe pod web-0 | grep Image:
    Image:          nginx:1.26-alpine
[root@master nfs-cli 14:01:06]# kubectl describe pod web-1 | grep Image:
    Image:          nginx:1.26-alpine

更新版本

[root@master nfs-cli 14:02:23]# kubectl set image sts/web nginx-c=nginx:1.29-alpine
statefulset.apps/web image updated

再次查看版本,发现只有web-1的进行了更新

[root@master nfs-cli 14:03:05]# kubectl describe pod web-0 | grep Image:
    Image:          nginx:1.26-alpine
[root@master nfs-cli 14:03:33]# kubectl describe pod web-1 | grep Image:
    Image:          nginx:1.29-alpine

查看pod版本列表

[root@master nfs-cli 14:03:38]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name                                      Image
nfs-client-provisioner-69dff6bc9f-rtkw7   registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0                                     nginx:1.26-alpine
web-1                                     nginx:1.29-alpine

扩容数量为4,观察版本更新,发现新增的pod都使用新版本镜像

[root@master nfs-cli 14:06:03]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name                                      Image
nfs-client-provisioner-69dff6bc9f-rtkw7   registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0                                     nginx:1.26-alpine
web-1                                     nginx:1.29-alpine
web-2                                     nginx:1.29-alpine
web-3                                     nginx:1.29-alpine

缩容数量为1,观察版本变化

[root@master nfs-cli 14:06:54]# kubectl scale sts web --replicas=1
statefulset.apps/web scaled
[root@master nfs-cli 14:08:24]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name                                      Image
nfs-client-provisioner-69dff6bc9f-rtkw7   registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0                                     nginx:1.26-alpine

发现就剩原来老版本的pod,说明位置没变,不可变的基础设置,再次扩容,观察版本

[root@master nfs-cli 14:08:32]# kubectl scale sts web --replicas=6
statefulset.apps/web scaled
[root@master nfs-cli 14:10:53]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name                                      Image
nfs-client-provisioner-69dff6bc9f-rtkw7   registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0                                     nginx:1.26-alpine
web-1                                     nginx:1.29-alpine
web-2                                     nginx:1.29-alpine
web-3                                     nginx:1.29-alpine
web-4                                     nginx:1.29-alpine
web-5                                     nginx:1.29-alpine

可以看见扩容依旧按照partition的位置部署新版本

实现全部更新

[root@master nfs-cli 14:12:52]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
statefulset.apps/web patched
[root@master nfs-cli 14:14:00]# kubectl set image sts/web nginx-c=nginx:1.29-alpine
[root@master nfs-cli 14:15:07]# kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name                                      Image
nfs-client-provisioner-69dff6bc9f-rtkw7   registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0                                     nginx:1.29-alpine
web-1                                     nginx:1.29-alpine
web-2                                     nginx:1.29-alpine
web-3                                     nginx:1.29-alpine
web-4                                     nginx:1.29-alpine
web-5                                     nginx:1.29-alpine

总结

控制器类型版本升级/回退副本扩容/缩减
Deployment
ReplicaSet
DaemonSet
StatefulSet
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值