目 录CONTENT

文章目录

k8s | 深入理解 StatefulSet

如风
2023-07-19 / 0 评论 / 0 点赞 / 26 阅读 / 2,212 字

k8s | 深入理解 StatefulSet

StatefulSet 是 Kubernetes 中用于管理有状态应用的资源对象。有状态的含义是:

  • 稳定的网络标识:每个pod都有一个稳定的网络标识,在pod重启时保持不变,可以通过DNS或者其他服务发现访问
  • 有序的部署和扩展:StatefulSet能够按照一定的顺序逐个更新Pod,在新的Pod启动之前,旧的Pod仍然可以提供服务
  • 持久化存储:statefulset 使用 PVC(PersistentVolumeClaim) 为每个pod分配独立的持久化存储,数据重启或重新调度不会丢失

Statefulset 和 deployment

Deployment 和 StatefulSet 都是用来管理pod,都可以用来控制pod副本数和更新策略。

区别:

  • 稳定性和唯一性:deployment是无状态服务,pod都是相互的,没有唯一标识,扩容更新时pod名称会发生改变。而每个由StatefulSet创建出来的Pod都拥有一个序号(从0开始)和一个固定的网络标识,扩容更新时pod不会改变
  • Pod 更新:Deployment 会按照指定的更新策略(如 RollingUpdate)逐步替换 Pod,而 StatefulSet 会按照顺序依次更新每个 Pod,确保每个 Pod 在更新前后都处于稳定状态
  • 存储卷:Deployment 默认使用临时的存储卷(emptyDir),每次 Pod 重启时数据会丢失。而 StatefulSet 支持使用持久化存储卷,可以保留数据

Deployment 和 StatefulSet 是 Kubernetes 中两种不同类型的控制器对象,用于管理无状态和有状态应用的 Pod。Deployment 适用于无状态应用,支持滚动更新,Pod 没有唯一标识;而 StatefulSet 适用于有状态应用,支持有序更新和稳定唯一的 Pod 标识,可以保留数据。

保持应用的拓扑状态

StatefulSet 的拓扑状态是指它的 Pod 在集群中的部署位置和网络标识的状态。StatefulSet 中的 Pod 是按照序号进行命名和部署的,每个 Pod 都有一个唯一的序号。这使得 StatefulSet 中的 Pod 具有固定的标识和顺序,不会随着 Pod 的创建和删除而改变

想要维护应用的拓扑状态,必须保证能用固定的网络标识访问到固定的Pod实例,Kubernetes是通过**Headless Service**给每个Endpoint(Pod)添加固定网络标识的

Headless Service 是 Kubernetes 中 Service 的一种类型,它不为 Pod 提供 Cluster IP,而是通过 DNS 解析提供每个 Pod 的 IP 地址。Headless Service 可以通过访问 Pod 的 DNS 名称来直接与每个 Pod 进行通信,而无需经过 Service 负载均衡。

Headless Service 与 StatefulSet 结合使用时,可以实现有状态应用程序的服务发现。StatefulSet 创建的每个 Pod 都会被赋予一个稳定的 DNS 名称,通常是 Pod 名称加上 StatefulSet 名称。这样,其他应用程序可以通过 DNS 解析直接访问每个 Pod,从而实现有状态应用程序之间的直接通信。

为什么需要 Headless Service?

普通的Service都有ClusterIP,它其实就是一个虚拟IP,会把请求转发到该Service所代理的某一个Pod上,DNS通过Service名直接解析出Pod名对应的IP是不可以的,因为ServiceClusterIp,直接被DNS解析了。

怎么才能让DNS通过Service解析Pod的IP呢?这个时候就需要用到了 Headless Service

实例:创建一个Headless Service代理两个应用Pod实例

# headless-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: app-headless-svc
spec:
  clusterIP: None # <-- Don't forget!!
  selector:
    app: go-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000

创建 Service

kubectl apply -f headless-service.yaml service/app-headless-svc created

可以查看到 这个Service在DNS里对应的A记录

/app # nslookup app-headless-svc.default.svc.cluster.local
Server:		10.96.0.10
Address:	10.96.0.10:53

Name:	app-headless-svc.default.svc.cluster.local
Address: 10.1.0.38
Name:	app-headless-svc.default.svc.cluster.local
Address: 10.1.0.39

DNS查询会返回HeadlessService代理的两个Endpoint (Pod)对应的IP,这样客户端就能通过Headless Service拿到每个EndPoint的 IP,如果有需要可以自己在客户端做些负载均衡策略。Headless Service还有一个重要用处(也是使用StatefulSet时需要Headless Service的真正原因),它会为代理的每一个StatefulSet创建出来的Endpoint也就是Pod添加DNS域名解析,这样Pod之间就可以相互访问。

这个分配给Pod的DNS域名就是Pod的固定唯一网络标识,即使发生重建和调度DNS域名也不会改变

总结

Headless Service为代理的每一个StatefulSet创建出来的Pod添加DNS域名解析。所以在用StatefulSet编排实例之间有主从关系这样的有状态应用时,Pod相互之间就能以podName.serviceName.namesapce.svc.cluster.local 这个域名格式进行通信,这样就不用在担心Pod被重新调度到其他的节点上后IP的变化

保持实例的存储状态

StatefulSet 中的 Pod 使用持久化存储PV,PVC( PersistentVolume 或 PersistentVolumeClaim),每个 Pod 都有自己独立的持久化存储,这使得 Pod 可以保留它们的数据状态,即使 Pod 被重新调度到其他节点

为什么不用volume?

在一个Pod里声明 Volume,由于hostPath类型的Volume是基于宿主机目录的,如果一旦Pod发生重新调度,去了其他节点,就没有办法在新节点上把Pod的存储数据恢复回来了

集群持久数据卷资源的配置和使用是通过PVPVC完成的

关系

image-20230719151557533

Persistent Volume(PV)

持久卷PV是集群资源就像节点也是集群资源一样。它 是管理员提前预分配的存储资源,独立于任何特定的Pod或Namespace。PV的生命周期与集群中的资源无关,因此即使在Pod被删除后,PV仍然可以保持数据。

Persistent Volume Claim(PVC)

PVC 是一个用于请求PV的声明。PVC允许用户向Kubernetes请求一定数量和类型的存储资源。PVC 是由开发者创建的,并绑定到集群中的一个或多个PV上。当PVC绑定到PV上后,Pod可以通过PVC来访问PV提供的持久化存储

可以用编程领域的接口实现的关系来理解PVCPV的关系。PVC创建出来后需要和PV完成绑定才能使用, 我们不需要关注绑定的细节

实例:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pv-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pv-pod
spec:
  containers:
    - name: pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: pv-storage
  volumes:
    - name: pv-storage
      persistentVolumeClaim:
        claimName: pv-claim

只需要声明它的类型是 persistentVolumeClaim,然后指定 PVC 的名字,完全不用关心持久卷本身的定义

PVC模板

StatefulSet的定义里我们可以额外添加了一个spec.volumeClaimTemplates字段。它跟 Pod模板(spec.template字段)的作用类似。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi

Statefulset 总结

StatefulSet就像是一种特殊的Deployment,它使用Kubernetes里的两个标准功能:Headless ServicePVC,实现了对的拓扑状态和存储状态的维护。

StatefulSet通过Headless Service , 为它管控的每个Pod创建了一个固定保持不变的DNS域名,来作为Pod在集群内的网络标识。加上为Pod进行编号并严格按照编号顺序进行Pod调度,这些机制保证了StatefulSet对维护应用拓扑状态的支持。

而借由StatefulSet定义文件中的volumeClaimTemplates声明Pod使用的PVC,它创建出来的PVC会以名称编号这些约定与它创建出来的Pod进行绑定,借由PVC独立于Pod的生命周期和两者之间的绑定机制的帮助,StatefulSet完成了应用存储状态的维护。

参考链接

0

评论区