K8s StatefulSet

作者: AlienPaul | 来源:发表于2020-02-19 12:52 被阅读0次

    什么是StatefulSet

    StatefulSet和Deployment一样,可以保证集群中运行指定个数的pod,也迟滞横向扩展。除此之外StatefulSet中每一个pod会分配一个内部标记用来区分。尽管StatefulSet的pod确实是从同一个pod模板创建的,但每个pod都是不可互换的。无论pod被怎样调度,它们的标记都不会改变。StatefulSet的这个特性,使得其下管理的每个pod具有不同的网络标识(可以指定发送请求到具体哪个pod,这些pod之间也可以相互通信),也可以绑定不同的持久化存储(pod重新调度之后,和它绑定的存储仍然是原先那个)。

    StatefulSet的一些限制和要求

    • pod的存储必须使用StorageClass关联的PVC提供,或者由管理员预先创建好。
    • 删除StatefulSet或者是减小StatefulSet的replicas,k8s不会自动删除和已终止运行的pod绑定的数据卷。这样做是为了保证数据安全。
    • 为了确保StatefulSet管理的每个pod的网络标识不同,需要创建对应的headless service。
    • 当StatefulSet被删除的时候,它不能保证所有被管理的pod都停止运行。因此,在删除StatefulSet之前,需要先将它scale到0个pod。
    • pod管理策略使用默认的OrderedReady,进行滚动升级的时候可能会出现问题,需要手工修复。

    StatefulSet的描述文件

    下面是一个创建StatefulSet的例子,注意在此之前创建了一个配套的headless service。

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: nginx
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      selector:
        matchLabels:
          app: nginx # has to match .spec.template.metadata.labels
      serviceName: "nginx"
      replicas: 3 # by default is 1
      template:
        metadata:
          labels:
            app: nginx # has to match .spec.selector.matchLabels
        spec:
          terminationGracePeriodSeconds: 10
          containers:
          - name: nginx
            image: k8s.gcr.io/nginx-slim:0.8
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
      volumeClaimTemplates:
      - metadata:
          name: www
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "my-storage-class"
          resources:
            requests:
              storage: 1Gi
    

    pod标识

    StatefulSet中每个pod的标识都是不同的。pod标识包含一个整数序号,固定的网络标识和存储标识。无论pod被调度到哪个节点运行,这些标识始终会跟随这个pod。

    整数序号

    如果StatefulSet运行了n个pod,这些pod会被编号,从0到n - 1。

    网络标识

    建立了对应的headless service之后,StatefulSet每个pod对应的DNS遵循如下的命名规则:

    $(statefulset name)-$(ordinal).$(service name).$(namespace).svc.cluster.local
    

    例如:

    web-0.nginx.default.svc.cluster.local
    

    存储标识

    每个pod都分配了一个单独的PV,PV和pod是强关联的。如果pod意外停止,无论再次启动的时候被调度到了何处,它仍然绑定到之前相同的PV上。如果这个pod,甚至是StatefulSet被删除,PV也不会被自动删除。需要手工操作。

    pod命名标签

    StatefulSet创建pod的时候会自动为pod添加一个statefulset.kubernetes.io/pod-name标签。可用于专门为某个特定的pod绑定service。

    StatefulSet的部署和扩缩容

    需要注意如下几点:

    • StatefulSet创建pod的时候是串行化按照顺序执行,从0创建到n-1。
    • 删除pod的时候(比如缩容),按照相反的方向操作,即先删除pod n-1,在删除pod n-2,直到pod0。
    • 创建StatefulSet或者是扩容的之后,当且仅当一个pod运行成功进入就绪状态的时候,下一个pod才会开始创建。
    • 同理,StatefulSet缩容的时候,当且仅当一个pod彻底停止之后,下一个pod才会开始停止过程。

    StatefulSet不应该配置pod.Spec.TerminationGracePeriodSeconds为0,会有潜在的问题。

    Pod管理策略(Pod Management Policy)

    配置项位于.spec.podManagementPolicy。用来配置pod的创建和销毁是否可以并行操作。有如下两个配置值:

    • OrderedReady:pod安装顺序创建和销毁。且每个pod的创建和销毁都必须要求前一个pod已经完全创建或销毁完毕。这个是默认的行为。
    • Parallel:允许同时创建和销毁多个pod,不必等待前一个pod创建或销毁完毕。仅仅对扩容缩容有效,pod update过程不受影响。

    升级策略(update policy)

    用来配置滚动升级的行为。配置项位于.spec.updateStrategy

    可供配置的值如下:

    • OnDelete:.spec.updateStrategy.type设置为OnDelete时,如果pod发生更新,StatefulSet不会更新已经运行的pod,必须将这些pod手工删除。新创建出来的pod是已更新过的pod。
    • RollingUpdate:如果没有配置.spec.updateStrategy,默认使用这个配置。.spec.updateStrategy.type设置为RollingUpdate时,如果发生pod更新,StatefulSet会挨个删除并重新创建所有的pod。操作的顺序为从pod n-1 到 pod0,。即先删除pod n-1,等它彻底停止后,创建新的pod n-1。等pod n-1进入ready状态后,删除pod n-2 ……以此类推,直到操作完pod0。
    • partition:配置一个.spec.updateStrategy.rollingUpdate.partition整数值。发生更新的时候,所有序号大于等于partition的pod会更新,所有序号小于partition的pod不会更新。即便是把序号小于partition的pod删除了,pod还是会按照之前的版本创建,不会更新。

    强制回滚

    如果滚动升级发生问题,某个pod总是无法进入就绪状态,StatefulSet会停止滚动升级,进入等待状态。

    发生这种情况的时候,仅仅将pod template修改正确是不够的。必须手工将无法启动的pod删除掉,StatefulSet会重新以正确的配置创建pod。否则StatefulSet仍会处于无限等待状态。

    其他

    StatefulSet会最大程度确保序号相同的pod同时只运行1个。比如说这个场景:集群中某个节点突然和集群失去网络联系,这个节点又恰好运行了某StatefulSet的一个pod。此时,这个pod不会立刻停止运行,状态会改变为Unknown。如果操作集群其他正常节点,手工删除这个pod,这个pod也不会真正删除,仅会被标记为删除(mark for deletion)。这时候k8s不会创建序号相同的pod,直到那个失去连接的节点重新连接到集群,k8s才会把这个pod删除,并创建出新的序号相同的pod。如果需要强制删除这个pod,可以执行如下命令(web-0为要强制删除的pod名称):

    kubectl delete po web-0 --force --grace-period 0
    

    相关文章

      网友评论

        本文标题:K8s StatefulSet

        本文链接:https://www.haomeiwen.com/subject/ddcafhtx.html