侧边栏壁纸
博主头像
小周的个人博客 博主等级

行动起来,活在当下

  • 累计撰写 23 篇文章
  • 累计创建 9 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

StatefulSet 控制器

Administrator
2024-06-05 / 0 评论 / 0 点赞 / 0 阅读 / 0 字

对于我们部署的应⽤,⼤体可以分为两类,⼀类是⽆状态应⽤,⼀类是有状态应⽤

  • 无状态应用:像web这种类型的应⽤程序,称为无状态应用,他们不需要存储任何数据⾄本地,也没有任何启动顺序之分和主从角色之分,像这类应⽤,就可以通过RS、Deployment、DaemonSet控制器来进⾏编排和部署,它们所管理的Pod的IP、名字、启动顺序都是随机的。

  • 有状态应用:像MySQL、Redis这类需要存储数据的应⽤程序,称为有状态应用,它们有主从⻆⾊之分,⼜存在先后启动顺序,像这类应用,需要通过StatefulSet控制器来编排和部署。

StatefulSet介绍

在k8s中,StatefulSet 控制器用于管理有状态应用的控制器。它的主要特点如下:

  • 稳定的网络标识:StatefulSet管理的Pod拥有固定的名称,Pod名字称为网络标识,可以通过DNS查询来发现每个Pod。

  • 持久化存储:StatefulSet为每个Pod关联一个PV,实现数据的持久化,并且当Pod故障被重建后,依然会自动使用此前的PV保存数据。

  • 有序部署和扩展:StatefulSet可以定义Pod先后顺序来部署和更新Pod。在扩展时,可以确保有序的扩展,且新生成的Pod名称与现有的Pod保持一致。

  • 有序的缩容:当缩减 StatefulSet 时,它会按照与创建相反的顺序逐个删除其管理的 Pod。这确保了有状态应用的有序关闭和清理。

StatefulSet组成

Headless Service(无头服务):Headless Service给每个Pod分配一个唯一的DNS名称,用来定义Pod的网络标识。如果Pod重建,Pod IP是变化的,但是Pod名称是不变的,所以是以Pod名称来识别。

VolumeClaimTemplate(存储卷申请模板):有状态应用需要持久的存储,对于分布式系统来讲,每个Pod的数据也不一样,所以每个Pod需要有自己的存储卷,而不是共用同一个存储卷。所以statefulset通过VolumeClaimTemplate为每个Pod生成不同的PVC,并绑定PV来实现各Pod有专用存储。

StatefulSet案例

通过前边StorageClass环境为StatefulSet提供动态存储,并通过StatefulSet部署MySQL。

步骤1:创建一个Headless Service给每个Pod分配一个唯一的DNS名称,与在Deployment中的Service的区别是Headless Service没有Cluster IP。

# cat mysql-svc.yml
​
apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
  namespace: test
​
spec:
  clusterIP: None       #不分配ClusterIP,表示这是一个headless服务,headless服务没有自己的ClusterIP,它直接返回后端Pod的IP地址。
  selector:
    app: mysql
  ports:
  - port: 3306
    targetPort: 3306
#创建Service
kubectl create -f mysql-svc.yml
​
#查看Service
kubectl get svc -n test
NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
mysql-svc   ClusterIP   None         <none>        3306/TCP   5s

步骤2:通过StatefulSet部署MySQL。

# cat mysql-sts.yaml
​
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: test
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: "mysql-svc"  #声明它属于哪个Service
  replicas: 3               #副本数
  template:
    metadata:
      labels:
        app: mysql          #要与Service中selector保持一致
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "123456"
        volumeMounts:
        - name: mysql-pvc               #挂载pcv,与模板中定义pvc名称一致
          mountPath: /var/lib/mysql     #挂载到容器的目录
​
  volumeClaimTemplates:                 #pvc的模板
  - metadata:
      name: mysql-pvc                   #定义pvc的名称
    spec:
      accessModes: [ "ReadWriteOnce" ]  #读、写权限,只能被一个节点挂载
      storageClassName: "nfs-client"    #存储类名,通过kubectl get sc查看
      resources:
        requests:
          storage: 6Gi                  #请求的存储空间大小
#另开一个终端监控Pod创建过程(Pod是有序创建的)
kubectl get pod -w -n test
​
#创建Pod
kubectl create -f mysql-sts.yml
​
#查看Pod信息
kubectl get pod -n test
NAME                         READY   STATUS    RESTARTS      AGE
mysql-0                      1/1     Running   0             2m59s
mysql-1                      1/1     Running   0             2m56s
mysql-2                      1/1     Running   0             2m53s

对于N个副本的StatefulSet,每个Pod都在[0,N)的范围内分配一个数字序号,且是唯一的;

Headless Service访问方式pod-name.service-name.namespace.svc.cluster.local

dig mysql-0.mysql-svc.test.svc.cluster.local @10.96.0.2 +short

提示:10.96.0.2是集群的clusterDNS地址,部署集群时,在kubelet.json文件中定义过。

#查看Pod所使用的pvc(每个Pod都有各自的存储卷)
kubectl get pvc -n test
NAME                STATUS   VOLUME                                     
mysql-pvc-mysql-0   Bound    pvc-027fc813-3d9c-4497-8aed-11c3eb4b99ac   6Gi     
mysql-pvc-mysql-1   Bound    pvc-4ff366a6-1d7c-4cc3-ba04-8d475925924b   6Gi     
mysql-pvc-mysql-2   Bound    pvc-c79048bd-9eed-4630-b79c-32412f28dcdf   6Gi
​
#查看每个pvc对应的pv信息
kubectl get pv
NAME                                        STATUS   CLAIM
pvc-027fc813-3d9c-4497-8aed-11c3eb4b99ac    Bound    test/mysql-pvc-mysql-0
pvc-4ff366a6-1d7c-4cc3-ba04-8d475925924b    Bound    test/mysql-pvc-mysql-1
pvc-c79048bd-9eed-4630-b79c-32412f28dcdf    Bound    test/mysql-pvc-mysql-2
​
#删除mysql-0的Pod,验证Pod名称是否一致,且是否还使用此前的存储卷保存数据
kubectl delete pod mysql-0 -n test
​
#查看Pod,验证Pod名称是否一致,验证是否还使用此前的存储卷保存数据
kubectl get pod -n test
NAME      READY   STATUS    RESTARTS   AGE
mysql-0   1/1     Running   0          3s
mysql-1   1/1     Running   0          16m
mysql-2   1/1     Running   0          16m

扩展Pod,验证Pod的名称是否与现有的Pod保持一致

#查看sts信息
kubectl get sts -n test
​
#通过edit扩容Pod数量
kubectl edit sts mysql -n test
...
  replicas: 4
#查看Pod
kubectl get pod -n test
NAME      READY   STATUS    RESTARTS   AGE
mysql-0   1/1     Running   0          2m27s
mysql-1   1/1     Running   0          28m
mysql-2   1/1     Running   0          28m
mysql-3   1/1     Running   0          4s

缩减Pod,验证它是否会按照与创建相反的顺序逐个删除其管理的Pod

#另开一个终端监控Pod缩减过程(Pod是有序创建的)
kubectl get pod -w -n test
​
#通过edit缩减Pod数量
kubectl edit sts mysql -n test
...
  replicas: 1
#查看Pod
kubectl get pod -n test
NAME      READY   STATUS    RESTARTS   AGE
mysql-0   1/1     Running   0          2m18s

提示:此前Pod所使用的存储并不会删除。如果不在需要可手动删除,先删除pvc(pv会自动删除)在删除后端存储服务器对应的目录。

总结:StatefulSet虽然在⼀定程度上能够实现有状态应⽤的管理,但目前为止将数据库容器化是非常不合理的,容器最初是针对无状态的应用而设计的,而且数据库(特别是关系型数据库)对读写(I/O)的要求较高,为了避免资源竞争,生产环境都会将数据独立出来,部署到物理机或虚拟机中。


0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区