有状态的应用

并不是所有的应用都是无状态的,比如ES集群。ES集群需要感知集群中每个节点的主机名,而且每个节点都有自己独立的存储。节点可以下线,但是节点重新上线后,主机名、IP、存储都需要和上线前保持一致。如果将ES部署在k8s,用ReplicaSet去管理,那pod重建后,主机名和IP会发生变更。此外,ReplicaSet管理的pod副本,共享同一个持久化存储,无法为每个pod提供独立的存储。虽然,对于ES而言,各个节点的数据可以部署在同一个卷上,但是这也失去了分布式的优点。

k8s的Statefulset是专门为有状态应用服务的,可以为pod提供稳定的pod名称,主机名和独立的存储,通过DNS的SRV记录提供稳定的网络标识

Statefulset

apiVersion: v1
kind: Service
metadata:
  name: headless_service
spec:
  clusterIP: None # 创建headless服务,statefulset的控制service必须是headless模式
  selector:
    app: kubia
  ports:
  - name: http
    port: 80
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: kubia
spec:
  serviceName: headless_service # 服务名称
  replicas: 2
  template:
    metadata:
      labels:
        app: kubia
    spec:
      containers:
      - name: kubia
        image: test_image
        ports:
        - name: http
          containerPort: 8080
        volumeMounts:
        - name: data
          mountPath: /var/data
  volumeClaimTemplates: # 持久卷声明模板
  - metadata:
      name: data
    spec:
      resources:
        requests:
          storage: 1Mi
      accessModes:
      - ReadWriteOnce
  1. StatefulSet除了提供pod模板外,还需要提供持久卷声明模板。StatefulSet会先创建持久卷声明,然后创建pod,并将这个持久卷声明绑定到对应的pod上
  2. 不论是pod还是持久卷声明,其名称都是有规律的。pod的名称是<name in pod template>-<index>,在本例中,名称为{kubia-0, kubia-1};持久卷声明名称是<name in pvc template>-<name in pod template>-<index>,因此在本例中,名称为{data-kubia-0, data-kubia-1}
  3. StatefulSet关联一个headless模式的服务,每个pod都有独立的DNS记录,在本例中,可以通过kubia-0.headless_service.default.svc.cluster.local访问kubia-0 pod
  4. 在创建StatefulSet后,会逐个创建pod,只有在当前pod就绪后,才会创建下一个pod,pod的索引会递增。扩容也类似,逐个扩容,将使用下一个还没用到的顺序索引值。
  5. StatefulSet缩容也是逐步进行,会先删除最高索引值的pod,且在有实例不健康的情况下,不允许进行缩容操作。
  6. 缩容只会删除pod,不会删除持久卷声明,持久卷声明需要手动删除。因为删除持久卷声明会删除数据,而这对于有状态应用是致命的

At-most-one

StatefulSet会确保当前不会存在两个完全一致的pod同时运行,避免两个相同的pod在处理相同的文件。

因此,k8s需要明确知道一个pod已经终止,这就要涉及到k8s的各组件是如何协调工作的。API服务器只会更新各资源的状态,最终是由各资源的控制器,将资源状态收敛到期望的状态。各节点上的kublet实际管理着pod,并将pod的状态上报给控制平面。因此,当kublet上报pod已经终止时,k8s才会为其创建一个替代pod。

举个例子,当我么执行

kubectl delete pod kubia-0

只是将kubia-0标记删除,此时StatefulSet并不会为kubia-0创建一个替代pod。只有kublet上报了kubia-0已经终止,StatefulSet才会开始创建替代pod。如果kubia-0所在的节点下线,那么pod的状态将会一直是Terminating,k8s永远不会创建替代pod,除非节点上线或者执行强制删除命令。

kubectl delete po kubia-0 --force --grace-period 0 # 强制删除pod

通过API服务器访问pod

这部分和StatefulSet关系不大,只是介绍API服务器的一个功能,即可以作为代理直接连接到指定的pod,URL格式如下

<apiServerHost>:<port>/api/v1/namespaces/<namespace>/pods/<pod-name>/proxy/<path>

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐