zoukankan      html  css  js  c++  java
  • KubernetesStatefulset

    1. 简介

    StatefulSet 是用来管理有状态应用的工作负载Api对象。

    StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。

    Deployment 类似, StatefulSet 管理基于相同容器规约的一组 Pod。

    但和 Deployment 不同的是, StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

    如果希望使用存储卷为工作负载提供持久存储,可以使用 StatefulSet 作为解决方案的一部分。 尽管 StatefulSet 中的单个 Pod 仍可能出现故障, 但持久的 Pod 标识符使得将现有卷与替换已失败 Pod 的新 Pod 相匹配变得更加容易。

    2. 什么时候使用StatefulSet

    StatefulSets 对于需要满足以下一个或多个需求的应用程序很有价值:

    • 稳定的、唯一的网络标识符。
    • 稳定的、持久的存储。
    • 有序的、优雅的部署和缩放。
    • 有序的、自动的滚动更新。

    在上面描述中,“稳定的”意味着 Pod 调度或重调度的整个过程是有持久性的。 如果应用程序不需要任何稳定的标识符或有序的部署、删除或伸缩,则应该使用 由一组无状态的副本控制器提供的工作负载来部署应用程序,比如 Deployment 能更适用于你的无状态应用部署需要。

    3. 限制

    • 给定 Pod 的存储必须由 PersistentVolume 驱动基于所请求的 storage class 来提供,或者由管理员预先提供。
    • 删除或者收缩 StatefulSet 并不会删除它关联的存储卷。 这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。
    • StatefulSet 当前需要 无头服务 来负责 Pod 的网络标识。你需要负责创建此服务。
    • 当删除 StatefulSets 时,StatefulSet 不提供任何终止 Pod 的保证。 为了实现 StatefulSet 中的 Pod 可以有序地且体面地终止,可以在删除之前将 StatefulSet 缩放为 0。
    • 在默认 Pod 管理策略(OrderedReady) 时使用 滚动更新,可能进入需要人工干预 才能修复的损坏状态。

    4. StatefulSet 原理

    StatefulSet由Service和volumeClaimTemplates组成。Service中的多个Pod将会被分别编号,并挂载volumeClaimTemplates中声明的PV。

    注意: 官方提示 StatefulSets 在1.9中是稳定的

    StatefulSet 除了要与PV卷捆绑使用以存储Pod的状态数据,还要与Headless Service配合使用,在每个StatfulSet的定义中要声明它属于哪个Headless Service.Headless Service 与普通Service的关键区别在于, Headless Service它没有Cluster IP,如果解析Headless Service的DNS域名,则返回的是该Service对应的全部Pod的Endpoint列表。

    StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod实力创建了一个DNS域名,这个域名的格式为: ${podname}.${headless service name}

    比如一个3节点的Kafka的StatefulSet集群,对应的Headless Service的名字为kafka,StatefulSet的名字为kafka,则StatefulSet 里面的3个Pod的DNS分别为kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,这些DNS名称可以直接在集群的配置文件中固定下来。

    简单点说:没有部署HeadlessService的话,PetSet/StatefulSet下的pod,无法通过域名进行访问。

    5. quick start

    5.1 创建sts

    创建资源模板信息 web.yaml 其中包括 一个 headless-service(无头服务)和 一个 StatefulSet

    经测试 svc 的 name 必须与 sts 的 spec.serviceName 相等,否则无法通过路由规则找到容器服务

    这里为了方便就挂载了一个空目录,如果有自己的 storageClass 也可以使用

    apiVersion: v1
    kind: Service
    metadata:
      # must be equal sts .spec.serviceName
      name: nginx-sn
      labels:
        app: nginx
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: nginx
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      # must be equal headless-svc metadata.name
      serviceName: "nginx-sn"
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:latest
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: nginx-volume
              mountPath: /usr/share/nginx/html
          volumes:
          - name: nginx-volume
            # 为了演示方便,挂载个空目录
            emptyDir: {}
      # 如果有自己的 storageClass 可以使用以下的方式
      #volumeClaimTemplates:
      #- metadata:
      #    name: www
      #  spec:
      #    accessModes: [ "ReadWriteOnce" ]
      #    storageClassName: "your-storage-class"
      #    resources:
      #      requests:
      #        storage: 1Gi      
    

    创建资源

    $ kubectl create -f web.yaml
    

    5.2 查看sts

    查看sts 信息

    $ kubectl get -f web.yaml -owide
    # 输出内容如下
    # headless svc
    NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
    service/nginx-sn   ClusterIP   None         <none>        80/TCP    20m   app=nginx
    # sts
    NAME                   READY   AGE   CONTAINERS   IMAGES
    statefulset.apps/web   2/2     20m   nginx        nginx:latest
    

    也可以使用命令分开查询

    查看svc

    $ kubectl get svc/nginx-sn -owide
    NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
    nginx-sn   ClusterIP   None         <none>        80/TCP    22m   app=nginx
    

    查看sts

    $ kubectl get sts -owide
    NAME   READY   AGE   CONTAINERS   IMAGES
    web    2/2     22m   nginx        nginx:latest
    

    也可以查看endpoints 列表信息,可以看到绑定到了两个pod

    kubectl get endpoints/nginx-sn -owide
    NAME       ENDPOINTS                             AGE
    nginx-sn   10.100.132.137:80,10.100.132.142:80   23m
    

    pod信息如下

    $ kubectl get po -owide
    NAME                          READY   STATUS    RESTARTS   AGE    IP               NODE           NOMINATED NODE   READINESS GATES
    web-0                         1/1     Running   0          24m    10.100.132.137   k8s-woker-01   <none>           <none>
    web-1                         1/1     Running   0          24m    10.100.132.142   k8s-woker-01   <none>           <none>
    

    5.3 修改/删除 sts

    sts 修改删除没什么特别的,操作基本和deploy一样,这里就不再赘述,说几点验证过的结论。

    1. 直接删除sts对应的pods时,sts会重新调度生成一个新的pod(pod ip会变,但是编号不变)。比如删除的是po/web-0,sts会重新调度生成一个web-0。
    2. sts 也可以修改对应的副本数,新生成的pod 编号会依次递增。
    3. 假设现在有三个pod 分别为:web-0、web-1、web-2,如果删除web-1,sts会重新调度生成一个新的web-1,之前的pod保持不变

    6. 小结

    6.1 有序索引

    对于具有 N 个副本的 StatefulSet,StatefulSet 中的每个 Pod 将被分配一个整数序号, 从 0 到 N-1,该序号在 StatefulSet 上是唯一的。比如sts name=nginx ,replicas=3 则对应的pod名称依次为nginx-0、nginx-1、nginx-2

    6.2 稳定的网络 ID

    StatefulSet 可以使用 "无头服务" 控制它的 Pod 的网络域。管理域的这个服务的格式为: $(服务名称).$(命名空间).svc.cluster.local,其中 cluster.local 是集群域。 一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 子域,格式为: $(pod 名称).$(所属服务的 DNS 域名),其中所属服务由 StatefulSet 的 serviceName 域来设定。

    下面给出一些选择集群域、服务名、StatefulSet 名、及其怎样影响 StatefulSet 的 Pod 上的 DNS 名称的示例:

    集群域名 服务(名称空间/名字) StatefulSet(名字空间/名字) StatefulSet 域名 Pod DNS Pod 主机名
    cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1}
    cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1}
    kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..N-1}.nginx.foo.svc.kube.local web-{0..N-1}

    说明: 集群域会被设置为 cluster.local,除非有其他配置

    6.3 部署和扩缩保证

    • 对于包含 N 个 副本的 StatefulSet,当部署 Pod 时,它们是依次创建的,顺序为 0..N-1
    • 当删除 Pod 时,它们是逆序终止的,顺序为 N-1..0
    • 在将缩放操作应用到 Pod 之前,它前面的所有 Pod 必须是 Running 和 Ready 状态。
    • 在 Pod 终止之前,所有的继任者必须完全关闭。

    StatefulSet 不应将 pod.Spec.TerminationGracePeriodSeconds 设置为 0。 这种做法是不安全的,要强烈阻止。如果要强制删除pod使用以下命令:

    $ kubectl delete pods <pod> --grace-period=0 --force
    

    在上面的 nginx 示例被创建后,会按照 web-0、web-1、web-2 的顺序部署三个 Pod。 在 web-0 进入 Running 和 Ready状态前不会部署 web-1。在 web-1 进入 Running 和 Ready 状态前不会部署 web-2。 如果 web-1 已经处于 Running 和 Ready 状态,而 web-2 尚未部署,在此期间发生了 web-0 运行失败,那么 web-2 将不会被部署,要等到 web-0 部署完成并进入 Running 和 Ready 状态后,才会部署 web-2。

    如果用户想将示例中的 StatefulSet 收缩为 replicas=1,首先被终止的是 web-2。 在 web-2 没有被完全停止和删除前,web-1 不会被终止。 当 web-2 已被终止和删除、web-1 尚未被终止,如果在此期间发生 web-0 运行失败, 那么就不会终止 web-1,必须等到 web-0 进入 Running 和 Ready 状态后才会终止 web-1。

    6.4 稳定的存储

    对于 StatefulSet 中定义的每个 VolumeClaimTemplate,每个 Pod 接收到一个 PersistentVolumeClaim。 当一个 Pod 被调度(重新调度)到节点上时,它的 volumeMounts 会挂载与其 PersistentVolumeClaims 相关联的 PersistentVolume。 请注意,当 Pod 或者 StatefulSet 被删除时,与 PersistentVolumeClaims 相关联的 PersistentVolume 并不会被删除。要删除它必须通过手动方式来完成。

  • 相关阅读:
    leetcode 175 Combine Two Tables join用法
    spark学习及环境配置
    html表格设计
    免费的论文查重网站
    php利用msqli访问数据库并实现分页,
    php利用href进行页面传值的正确姿势
    php+mysql时报错:Unknown column '' in 'field list'解决方案
    使用XMLHttpRequest解析json
    用自定义的函数将gps转换为高德坐标
    WeakHashMap回收时机
  • 原文地址:https://www.cnblogs.com/ludangxin/p/15717856.html
Copyright © 2011-2022 走看看