ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

k8s-statefulset

2021-12-22 01:31:55  阅读:280  来源: 互联网

标签:web statefulset name nginx StatefulSet sts Pod k8s


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 并不会被删除。要删除它必须通过手动方式来完成。

标签:web,statefulset,name,nginx,StatefulSet,sts,Pod,k8s
来源: https://www.cnblogs.com/ludangxin/p/15717856.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有