目录

控制器controller

controller作用及分类

Deployment

Replicaset控制器的功能

Deployment控制器的功能

Deployment用于部署无状态应用

创建deployment类型应用

访问deployment

删除deployment中的pod

pod版本升级

pod版本回退

副本扩容

副本裁减

多副本滚动更新

删除deployment

Replicaset

控制器controller进阶

DaemonSet

DaemonSet介绍

DaemonSet应用案例

Job

job介绍

job应用案例

cronjob

控制器controller之StatefulSet

statefulset控制器作用

无状态应用与有状态应用

无状态应用

有状态应用

statefulset的特点

statefulset的YAML组成

创建statefulset应用

网络存储NFS部署

PV(持久化存储卷)与 PVC(持久存储卷声明)

实现nfs类型pv与pvc

动态供给

金丝雀发布更新


控制器controller

controller作用及分类

controller用于控制pod

控制器主要分为:

  • 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类型应用

准备yaml文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-nginx
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: c1
        image: nginx:1.26-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
        # 资源限制
        resources:
          requests:
            memory: "150Mi"
          limits:
            memory: "200Mi"
        # 存活探针
        livenessProbe:
          tcpSocket:
            port: http
          initialDelaySeconds: 5
          periodSeconds: 5
        #  就绪探针
        readinessProbe:
          httpGet:
            port: http
            path: /index.html
          initialDelaySeconds: 3
          periodSeconds: 3

验证

kubectl get pod

查看deployment名称

kubectl get deployment

查看replicaset名称

kubectl get replicaset
#或
kubectl get rs

访问deployment

查看pod的IP地址

kubectl get pod -o wide

可以看到pod在node2节点,pod的IP为10.244.104.10

查看所有集群节点的网卡

ifconfig tunl0 | head -2

总结:可以看到所有集群节点的IP为10.244.0.0/16这个大网段内的子网

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

ping -c 4 10.244.166.145
curl http://10.244.166.145

删除deployment中的pod

强制删除pod(注意:是删除deployment中的pod)

kubectl delete pod podname --grace-period=0 --force

再次查看,会发现又重新启动了一个pod(节点发生变化,IP发生变化)

总结:pod的IP不是固定的,就算把整个集群关闭再启动,pod也会自动启动,但是IP地址会发生变化 。既然IP地址不是固定的,所以需要一个固定的访问endpoint给用户,那么这种方式就是service

pod版本升级

查看帮助

kubectl set image -h

升级前验证nginx版本

kubectl describe pods deployment-nginx-57c677596f-fqb6v | grep Image:
kubectl exec deployment-nginx-57c677596f-fqb6v -- nginx -v

升级为1.29版本

kubectl set image deployment deploy-nginx nginx=nginx:1.29-alpine --record
kubectl exec deploy-nginx-b5d6b46fb-f56rg -- nginx -v

说明:

  • deployment deploy-nginx代表名为deploy-nginx的deployment

  • nginx=nginx:1.29-alpine前面的nginx为容器名

  • --record 表示会记录

容器名怎么查看?

  • kubectl describe pod pod名 查看

  • kubectl edit deployment deployment名 来查看容器名

  • kubectl get deployment deployment名 -o yaml 来查看容器名

验证

如果升级的pod数量较多,则需要一定时间,可通过下面命令查看是否已经成功

kubectl rollout status deployment deploy-nginx

pod版本回退

查看历史版本信息

kubectl rollout history deployment deploy-nginx

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

kubectl rollout history deployment deploy-nginx --revision=1

执行回退

kubectl rollout undo deployment deploy-nginx --to-revision=1

验证

回到了1.26版本,但version的ID 变了

kubectl rollout history deployment deploy-nginx
kubectl describe pod deploy-nginx-66d785bdb5-8jjdw | grep Image
kubectl exec deploy-nginx-66d785bdb5-8jjdw -- nginx -v

总结:

  • 升级:kubectl set image deployment deployment-nginx c1=nginx:1.27-alpine --record

  • 查看历史记录:kubectl rollout history deployment deployment-nginx

  • 查看指定版本信息:kubectl rollout history deployment deployment-nginx --revision=序号

  • 回退:kubectl rollout undo deployment deployment-nginx --to-revision=序号

  • 无论是升级还是回退,pod都是先创建再删除

副本扩容

获取帮助

kubectl scale -h

扩容为2个副本

kubectl scale deployment deploy-nginx --replicas=2

查看

kubectl get pods -o wide

继续扩容(我们这里只有2个node,但是可以大于node节点数据)

kubectl scale deployment deployment-nginx --replicas=4

副本裁减

指定副本数为1进行裁减

kubectl scale deployment deployment-nginx --replicas=1

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

kubectl scale deployment deployment-nginx --replicas=0

查看(pod?deployment?replicas?)

pod没有了,但是deployment和replicaset还在

多副本滚动更新

先扩容多副本

kubectl scale deployment deployment-nginx --replicas=16

滚动更新

kubectl set image deployment deployment-nginx nginx=nginx:1.29-alpine --record

验证

kubectl describe pods deployment-nginx-78568c956b-2lwq6 | grep Image

kubectl rollout status deployment deployment-nginx

删除deployment

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

kubectl delete deployment deployment-nginx

Replicaset

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replicaset-nginx
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: c1
        image: nginx:1.26-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80

应用YAML文件,验证

kubectl get rs

kubectl get pods

kubectl get deployment

说明:找不到对应的deployment,说明创建rs并没有创建deployment

进行扩容

kubectl scale replicaset rs-nginx --replicas=4

查看副本数量

kubectl get rs
kubectl get pods

版本升级

kubectl describe pods rs-nginx-2ftcr | grep Image:

kubectl set image replicaset replicaset-nginx c1=nginx:latest --record

检查,版本并没发生变化,replicaset无法实现版本更新

kubectl describe pods rs-nginx-2ftcr | grep Image:

控制器controller进阶

DaemonSet

DaemonSet介绍
  • Daemonset能够让所有(或者特定)的节点运行同一个pod。

  • 当节点加入到K8s集群中,pod会被(DaemonSet)调度到该节点上运行,当节点从K8S集群中被移 除,被Daemonset调度的pod会被移除。

  • 如果删除DaemonSet,所有跟这个DaemonSet相关的pods都会被删除。

  • 如果一个DaemonSet的Pod被杀死、停止、或者崩溃,那么DaemonSet将会重新创建一个新的副 本在这台计算节点上。

  • DaemonSet一般应用于日志收集、监控采集、分布式存储守护进程等。

DaemonSet应用案例
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-nginx
  namespace: default
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      tolerations:    #代表容忍,保证在所有节点运行(仅容忍node节点的污点,master不容忍)
      - key: node-role.kubernetes.io/master    #能容忍的污点key
        effect: NoSchedule    #能容忍的污点effect
      containers:
      - name: c1
        image: nginx:1.26-alpine
        imagePullPolicy: IfNotPresent
        resources:    #资源限制是为了防止节点资源被占太多
          requests:
            memory: "150Mi"
          limits:
            memory: "200Mi"

应用YAML文件

kubectl apply -f daemonset-nginx.yml

验证

kubectl get daemonset

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

kubectl describe pod daemonset-nginx-hf8kp | grep Image:
kubectl set image daemonset daemonset-nginx c1=nginx:1.29-alpine --record

总结:daemonset无法扩缩容,但可以升级回退版本

Job

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

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

  • job负责批量处理短暂的一次性任务,即执行一次的任务,他保证批处理任务的一个或多个Pod成功结束。

job应用案例
  • 计算圆周率2000位
apiVersion: batch/v1
kind: Job
metadata:
  name: job
  namespace: default
spec:
  template:
    metadata:
      name: pod-pi
    spec:
      nodeName: node1
      containers:
      - name: job-pi
        image: perl
        imagePullPolicy: IfNotPresent
        command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
      restartPolicy: Never

任务执行结束,变为completed

kubectl logs job-9w5tb

  • 创建固定次数job
apiVersion: batch/v1
kind: Job
metadata:
  name: job2
  namespace: default
spec:
  completions: 10  #执行的总次数
  parallelism: 1   #每一步并发执行pod数量
  template:
    metadata:
      name: job-count-pod
    spec:
      containers:
      - name: busybox
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ["echo","hello"]
      restartPolicy: Never

查看

kubectl get pod

kubectl get job

验证输出

kubectl logs job2-4q88x

  • 一次性备份MySQL数据库

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

1:MySQL数据库准备

vim mysqld.yml
#写入
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

创建用于实现任务的资源清单文件

kubectl apply -f mysqld.yml

查看资源

kubectl get pod -o wide
kubectl get statefulsets

运行在node1节点,可以查看node1节点数据库目录

ls /opt/mysqldata/

创建用于实现任务的资源清单文件

vim job_mysqld.yml
#写入
apiVersion: batch/v1
kind: Job
metadata:
  name: mysql-dump
spec:
  template:
    metadata:
      name: mysql-dump
    spec:
      nodeName: node2
      containers:
      - name: mysql-dump
        image: mysql:5.7
        command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql_back.sql"]
        volumeMounts:
        - mountPath: "/root"
          name: mysql-data
      restartPolicy: Never
      volumes:
      - name: mysql-data
        hostPath:
          path: /opt/mysqldump

cronjob

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

  • 周期性输出字符
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob1
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo hello kubernetes
            imagePullPolicy: IfNotPresent
          restartPolicy: OnFailure

应用并验证

kubectl apply -f cronjob.yml
kubectl get cronjob

kubectl get pod

pod会每分钟生成一个

kubectl logs cronjob1-29294286-sb8g6

  • 周期性备份MySQL数据库

MySQL数据库准备

vim mysqld.yml
#写入
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: node2         #将资源创建到node2
      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文件

kubectl apply -f mysqld.yml

验证

kubectl get pod

cronjob控制器类型应用资源清单文件

vim cronjob_mysqld.yml
#写入
apiVersion: batch/v1
kind: CronJob
metadata:
  name: mysql-dump
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          nodeName: node1
          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

在node1节点查看mysql备份文件

控制器controller之StatefulSet

statefulset控制器作用

  • statefulset是用来管理有状态应用的控制器

  • statefulset用来管理应用的部署、扩缩容及滚动更新

  • statefulset为pod提供持久存储和持久标识符

无状态应用与有状态应用

无状态应用
  • 请求本身包含了响应端为响应这一请求所需的全部信息。每一个请求都像首次执行一样,不会依赖之前的数据进行响应

  • 不需要持久化的数据

  • 无状态应用的多个实例之间互不依赖,可以无序的部署、删除或伸缩

有状态应用
  • 前后请求有关联与依赖

  • 需要持久化的数据

  • 有状态应用的多个实例之间有依赖,不能相互替换:无论怎么调度,每个pod都有一个永久不变的ID

statefulset的特点
  • 稳定的、唯一的网络标识符。(无ClusterIP通过headless服务实现)

  • 稳定的、持久的存储(通过静态存储PV,PVC,动态存储storageclass实现)

  • 有序的、优雅的部署和缩放

  • 有序的、自动的滚动更新(从最大数更新,例如:编号2,编号1,编号0)

statefulset的YAML组成

需要三个部分组成:

  • headless service:实现稳定,唯一的网络标识

  • statefulset类型资源:写法和deployment几乎一致,就是类型不一样

  • volumeClaimTemplate:指定存储卷

创建statefulset应用

网络存储NFS部署

1:nfs服务器,地址192.168.18.138

[root@nfsserver ~]# mkdir -p /data/nfs
[root@nfsserver ~]# vim /etc/exports
#写入
/opt/k8s_disk   *(rw,no_root_squash,sync)
#解析:*允许所有用户访问;rw可读写;no_root_squash禁用安全降权规则。

[root@nfsserver ~]# systemctl restart nfs-server.service
[root@nfsserver ~]# systemctl enable nfs-server.service
[root@nfsserver ~]# systemctl stop firewalld.service
[root@nfsserver ~]# setenforce 0
[root@nfsserver ~]# showmount -e

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

yum install nfs-utils -y

3:验证nfs可用性

showmount -e 192.168.18.138

4:master节点上创建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
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: nfs-disks
      volumes:
      - name: nfs-disks
        nfs:
          path: /opt/k8s_disk
          server: 192.168.18.138

5:应用yaml文件

kubectl apply -f dep-volume-nfs.yml

6:查看存储pod

kubectl get pod

7:在nfs服务器上创建index文件

[root@nfsserver ~]# cd /opt/k8s_disk/
[root@nfsserver k8s_disk]# echo "hello nfs storage" > index.html

8:在master上可以直接验证查看

kubectl get pod -o wide
curl 10.244.166.134
curl 10.244.104.8

PV(持久化存储卷)与 PVC(持久存储卷声明)

kubernetes存储卷的分类太丰富了,每种类型都要写相应的接口与参数才行,这就让维护与管理难度加大。 kubernetes支持分类查看 参考文档:https://kubernetes.io/zh-cn/docs/concepts/storage/

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

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

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

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

pv与pvc之间的关系

  • pv提供存储资源(生产者)

  • pvc使用存储资源(消费者)

  • 使用pvc绑定pv

实现nfs类型pv与pvc

1:编写pv的yaml文件

apiVersion: v1
kind: PersistentVolume    #类型pv
metadata:
  name: pv-nfs    #名称
spec:
  capacity:
    storage: 10Gi    #大小
  accessModes:
    - ReadWriteMany    #访问方式
  nfs:
    path: /opt/k8s_disk    #nfs共享目录
    server: 192.168.18.138    #nfs服务器IP

访问模式3种:

  • ReadWriteOnce 单节点读写挂载

  • ReadOnlyMany 多节点只读挂载

  • ReadWriteMany 多节点读写挂载

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

2:创建pv并验证

kubectl apply -f pv-nfs.yml
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 1Gi     RWX   Retain Available        73s

说明:

  • RWX为ReadWriteMany的简写

  • Retain是回收策略

  • Retain表示不使用了需要手动回收

3:创建pvc的yaml文件

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi

4:应用yaml

kubectl apply -f pvc-nfs.yml

5:验证

kubectl get pvc

查看pv,绑定成功

kubectl get pv

6:创建nginx应用yaml文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-nginx-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
        ports:
        - containerPort: 80
      volumes:
      - name: www
        persistentVolumeClaim:
          claimName: pvc-nfs

7:运行yaml文件

kubectl apply -f dep-nginx-nfs.yml

8:验证

kubectl get pod -o wide
curl http://10.244.166.135

可修改index.html以便与之前实验区分

动态供给

1:下载class插件文件

wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/class.yaml
cp class.yaml storageclass-nfs.yml
vim class.yaml
#写入
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
  archiveOnDelete: "false"
kubectl apply -f storageclass-nfs.yml
kubectl get storageclass

  • RECLAIMPOLICY pv回收策略,pod或者pvc被删除后,pv是否删除还是保留

  • VOLUMEBINDINGMODE Immediate模式下pvc与pv立即绑定,主要是不等待相关pod调度完成,不关心其运行节点,直接完成

  • ALLOWVOLUMEEXPANSION pvc扩容 false不允许,true允许

2:下载并创建rbac

wget https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml
cp rbac.yaml storageclass-nfs-rbac.yaml
kubectl apply -f storageclass-nfs-rbac.yaml

3:创建动态供给的deployment

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

下载对应的deployment文件

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

编辑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.18.138    #nfs服务器地址
            - name: NFS_PATH
              value: /opt/k8s_disk    #路径
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.18.138    #nfs服务器地址
            path: /opt/k8s_disk    #路径

应用

kubectl apply -f deployment.yaml
kubectl get pod

4:nginx应用使用动态供给

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

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc    #service名称
  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
        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文件

kubectl apply -f nginx-storageclass-nfs.yml

查看资源

kubectl get pod
kubectl get service
kubectl get statefulset
kubectl get pvc
kubectl get pv

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

[root@nfsserver ~]# cd /opt/k8s_disk/
[root@nfsserver k8s_disk]# ls

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

[root@nfsserver k8s_disk]# echo "this is web0" > default-www-web-0-pvc-a307f611-9d7e-4948-94dd-7daf3a864393/index.html
[root@nfsserver k8s_disk]# echo "this is web1" > default-www-web-1-pvc-9aaf423c-0ffb-4f22-a1d7-14698c2c7e2e/index.html
[root@master]# kubectl get pod -o wide

[root@master ~]# curl http://10.244.166.136
this is web0
[root@master ~]# curl http://10.244.104.7
this is web1

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

kubectl get svc -n kube-system

dig -t a nginx-svc.default.svc.cluster.local. @10.96.0.10

解析pod域名

dig -t a web-0.nginx-svc.default.svc.cluster.local. @10.96.0.10

尝试删除web0后观察发现新创建的pod名字没变,但IP变了,而web0依然可以被解析,说明statefulset是通过域名解析的

在集群里创建pod访问域名,观察负载均衡

kubectl run -it centos --image=centos:7 --image-pull-policy=IfNotPresent
curl http://nginx-svc.default.svc.cluster.local.

金丝雀发布更新

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

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

kubectl get sts web -o yaml
...
  updateStrategy:
    rollingUpdate:
      partition: 0     #默认分区号0,表示更新0及大于0的所有pod
    type: RollingUpdate
...

说明:

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

修改更新

kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'

再次观察,值设置为1

updateStrategy:
  rollingUpdate:
    partition: 1

查看更新前版本

kubectl describe pod web-0 | grep Image:
kubectl describe pod web-1 | grep Image:

更新版本

[root@master ~]# kubectl set image sts/web nginx-c=nginx:1.29-alpine
statefulset.apps/web image updated

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

kubectl describe pod web-1 | grep Image:
kubectl describe pod web-0 | grep Image:

直观查看pod版本列表

kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image

扩容数量为4,观察版本更新

kubectl scale sts web --replicas=4
kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image

发现:新增的pod都使用的新版本

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

kubectl scale sts web --replicas=1
kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image

发现,就剩下原来的老版本的pod,说明位置没变,不可变基础设施,再次扩容,观察版本会发现扩容依旧是按照partition的位置部署新版本

实现全部更新

kubectl patch sts web -p '{"spec:"{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
kubectl set image sts/web nginx-c=nginx:1.29-alpine
kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image

更多推荐