k8s入门到实战(九)—— StatefulSet详细介绍及示例

2024-03-31 1909阅读

Statefulset

如果我们需要部署多个 MySQL 实例,就需要用到 StatefulSet。

k8s入门到实战(九)—— StatefulSet详细介绍及示例
(图片来源网络,侵删)

StatefulSet 是用来管理有状态的应用。一般用于管理数据库、缓存等。

与 Deployment 类似, StatefulSet 用来管理 pod 集合的部署和扩缩。

Deployment 无序(mysql-xxxxxx-xxx mysql-xxxxxx-xxx mysql-xxxxxx- xxx)用来部署无状态应用。StatefulSet(mysql-xxxxxx-1 mysql-xxxxxx-2 mysql-xxxxxx-3)用来有状态应用。

StatefulSet 的核心功能就是通过某种方式记录这些状态,然后在 Pod 被重新创建时能够为新 Pod 恢复这些状态

StatefulSet 本质上是 Deployment 的一种变体,在 v1.9 版本中已成为 GA 版本,它为了解决有状态服务的问题,它所管理的 Pod 拥有固定的 Pod 名称,启停顺序,在 StatefulSet 中,Pod 名字称为网络标识(hostname),还必须要用到共享存储。

在 Deployment 中,与之对应的服务是 service,而在 StatefulSet 中与之对应的 headless service,headless service,即无头服务,与 service 的区别就是它没有 Cluster IP:,解析它的名称时将返回该 Headless Service 对应的全部 Pod 的 Endpoint 列表。

除此之外,StatefulSet 在 Headless Service 的基础上又为 StatefulSet 控制的每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为:

$(podname).(headless server name)

$(podname).(headless server name).namespace.svc.cluster.local

StatefulSet 为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为: $(podname).(headless server name),也就意味着服务间是通过 Pod 域名来通信而非 Pod IP,因为当 Pod 所在 Node 发生故障时,Pod 会被飘移到其它 Node 上,Pod IP 会发生变化,但是 Pod 域名不会有变化。

StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQDN 为:(service name).(namespace).svc.cluster.local,其中,“cluster.local” 指的是集群的域名。

什么是 statefulset

在 k8s 中,StatefulSet 是一种用于管理有状态应用的资源对象。与一般的 deployment 不同,StatefulSet 提供了一种有序部署和管理有状态应用的方式。

StatefulSet 主要用于部署需要持久化存储和唯一标识的应用,例如数据库或分布式存储系统。它为每个 Pod 实例分配一个唯一的标识符,并根据这个标识符进行有序的创建、更新和删除操作。

StatefulSet 在创建和删除 Pod 实例时,会按照一定的顺序进行操作,确保每个 Pod 实例的唯一标识符和网络标识符的稳定性。这使得有状态应用可以保持持久化存储的连接,并且具备可靠的网络标识符,以便于应用之间的通信。

StatefulSet 还提供了一些其他的功能,如有序的缩放、滚动更新、有状态服务的 DNS 解析等。它使用有状态服务的特性,提供了高可用性、可伸缩性和可靠性。

总之,StatefulSet 是 k8s 中用于管理有状态应用的一种资源对象,它为有状态应用提供了有序的部署、更新和删除操作,并保证每个 Pod 实例的唯一标识符和网络标识符的稳定性。

statefulset 优点

k8s 中的 StatefulSet 具有以下优点:

  • 稳定的网络标识符:每个 StatefulSet 的 Pod 实例都具有稳定的网络标识符,这使得其他应用可以通过直接使用该标识符来访问和通信。这对于有状态应用非常重要,因为它们通常需要持久的网络标识符来保持连接。
  • 有序的创建和删除:StatefulSet 按照一定的顺序创建和删除 Pod 实例,这确保了应用在启动和关闭时的有序性。这对于有状态应用非常重要,因为它们通常需要按顺序启动和关闭,以避免数据丢失或损坏。
  • 持久化存储:StatefulSet 可以与持久化存储卷(如PersistentVolume)结合使用,以确保数据的持久性和可靠性。每个 Pod 实例都可以使用独立的存储卷,这对于有状态应用非常重要,因为它们通常需要在重新启动后保留数据。
  • 有序的缩放和滚动更新:StatefulSet 支持有序的缩放和滚动更新,可以根据需要增加或减少 Pod 实例的数量,并确保这些操作按顺序进行。这对于有状态应用非常重要,因为它们的缩放和更新通常需要遵循特定的顺序和规则。
  • 服务发现和 DNS 解析:StatefulSet 可以为每个 Pod 实例创建一个稳定的网络 DNS 名称,使得其他应用可以通过该名称来发现和访问它们。这对于有状态应用非常重要,因为它们通常需要通过名称进行服务发现和通信。

    总的来说,StatefulSet 在 k8s 中为有状态应用提供了一种可靠、稳定和有序的部署、管理和操作方式,使得有状态应用可以更好地运行和维护。

    statefulset 示例

    1. 编辑 yaml 文件nginx-sf.yaml
    # headless service,即无头服务,nginx, ClusterIP: None
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      ports:
        - port: 80
          name: web
      clusterIP: None
      selector:
        app: nginx
    ---
    # StatefulSet, web, 3个副本pod nginx,自动创建3个pvc - 自动创建3个pv
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      selector:
        matchLabels:
          app: nginx
      serviceName: "nginx"
      replicas: 3
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
            - name: nginx
              image: nginx:1.20.1
              ports:
                - containerPort: 80
                  name: web
              volumeMounts:
                - name: www
                  mountPath: /usr/share/nginx/html
      # 存储卷申请模版,指定了pvc名称,pvc的大小,申请的类型....
      volumeClaimTemplates: # pvc template
        - metadata:
            name: www
          spec:
            accessModes: ["ReadWriteOnce"]
            storageClassName: "local-path"
            resources:
              requests:
                storage: 1Gi
    

    注意:这文件中使用的 storageClassName 为 local-path,是在之前介绍存储类的时候的创建的,如果没有这个 local-path 是无法创建 pvc 的,如果没有,编写 yaml 文件创建 local-path

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: local-path
    provisioner: rancher.io/local-path
    volumeBindingMode: WaitForFirstConsumer
    reclaimPolicy: Delete
    
    1. 执行 yaml 文件
    [root@k8s-master k8s]# vi nginx-sf.yaml
    [root@k8s-master k8s]# kubectl apply -f nginx-sf.yaml 
    service/nginx created
    statefulset.apps/web created
    
    1. 查看 pod 和 pvc
    [root@k8s-master k8s]# kubectl get pvc
    NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    www-web-0   Bound    pvc-3050033b-638f-4d03-80d6-be6e270ac02a   1Gi        RWO            local-path     34m
    www-web-1   Bound    pvc-e22cd565-5f89-4b57-8be7-c4f648d52214   1Gi        RWO            local-path     9m15s
    www-web-2   Bound    pvc-e79aa081-176a-439f-875e-8119c021930e   1Gi        RWO            local-path     8m53s
    [root@k8s-master k8s]# kubectl get pod
    NAME    READY   STATUS    RESTARTS   AGE
    web-0   1/1     Running   0          81s
    web-1   1/1     Running   0          57s
    web-2   1/1     Running   0          48s
    
    1. pod 和 pvc 创建完毕,名字也是按顺序起的,不是 deployment 那种随机字符串的格式
    2. 进入容器内部,访问首页
    [root@k8s-master k8s]# kubectl get pod -o wide
    NAME    READY   STATUS    RESTARTS   AGE     IP                NODE        NOMINATED NODE   READINESS GATES
    web-0   1/1     Running   0          3m16s   192.169.36.106    k8s-node1              
    web-1   1/1     Running   0          2m52s   192.169.169.161   k8s-node2              
    web-2   1/1     Running   0          2m43s   192.169.36.107    k8s-node1              
    [root@k8s-master k8s]# kubectl exec -it web-0 /bin/bash
    kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
    root@web-0:/# curl 192.169.36.106:80
    
    403 Forbidden
    
    

    403 Forbidden


    nginx/1.20.1

    访问成功,我们创建的没有问题

    为什么需要 headless service 无头服务?

    在用 Deployment 时,每一个 Pod 名称是没有顺序的,是随机字符串,因此是 Pod 名称是无序的,但是在 statefulset 中要求必须是有序 ,每一个pod 不能被随意取代,pod 重建后 pod 名称还是一样的。而 pod IP 是变化的,所以是以 Pod 名称来识别。pod 名称是 pod 唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个 Pod 一个唯一的名称 。

    为什么需要 volumeClaimTemplate?

    对于有状态的副本集都会用到持久存储,对于分布式系统来讲,它的最大特点是数据是不一样的,所以各个节点不能使用同一存储卷,每个节点有自已的专用存储,但是如果在 Deployment 中的 Pod template 里定义的存储卷,是所有副本集共用一个存储卷,数据是相同的,因为是基于模板来的 ,而 statefulset 中每个 Pod 都要自已的专有存储卷,所以 statefulset 的存储卷就不能再用 Pod 模板来创建了,于是 statefulSet 使用 volumeClaimTemplate,称为卷申请模板,它会为每个 Pod 生成不同的 pvc,并绑定 pv, 从而实现各 pod 有专用存储。这就是为什么要用volumeClaimTemplate 的原因。

    稳定的存储:在 StatefulSet 中使用 VolumeClaimTemplate,为每个 Pod 创建持久卷声明(PVC)。 请注意,当 Pod 或者 StatefulSet 被删除时,持久卷声明和关联的持久卷不会被删除。

    结论

    使用 StatefulSet 创建 pod,按照顺序依次创建。 StatefulSet name 名 - 0/1/2/3/4 依次类推

    无论如何删除 pod,再次启动,名称不会发生变化。

    动态创建的 pvc 名字也不会发生变化。

    在真实的项目中,redis,mysql 持久化存储的 pod 都是使用 StatefulSet 来部署的,创建有状态应用。

    无论 pod ip 怎么变化,服务名不变,项目中就可以通过服务名来访问,域名只能在容器内部访问(对应项目启动的 pod)

    测试:使用域名访问

    root@web-0:/# curl web-1.nginx
    
    403 Forbidden
    
    

    403 Forbidden


    nginx/1.20.1 root@web-0:/# curl web-2.nginx.default.svc.cluster.local 403 Forbidden

    403 Forbidden


    nginx/1.20.1

    可以看到,完全可以通过域名来访问

    总结

    有状态应用 statefulset 无状态应用 deployment

    Headless Service 给 deployment 的 pod 分了名字,然后 StatefulSet 将这种名字锁死。

    StatefulSet 可以让 pod 的名字不变 + PVC,使得 pod 对应的 volume 不会变,也就是存储了存储状态。

    Pod 标识:在具有 N 个副本的 StatefulSet中,每个 Pod 会被分配一个从 0 到 N-1 的整数序号,该序号在此 StatefulSet 上是唯一的。

    部署扩缩容前提保证:

    • 对于包含 N 个 副本的 ,当部署 Pod 时,它们是依次创建的,顺序为 0…N-1。
    • 当删除 Pod 时,它们是逆序终止的,顺序为 N-1…0。
    • 在将扩缩操作应用到 Pod 之前,它前面的所有 Pod 必须是 Running 和 Ready 状态。
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]