在k8s上部署有状态的应用
介绍StatefulSet
有状态的应用
并不是所有的应用都是无状态的,比如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
- StatefulSet除了提供pod模板外,还需要提供持久卷声明模板。StatefulSet会先创建持久卷声明,然后创建pod,并将这个持久卷声明绑定到对应的pod上
- 不论是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}
- StatefulSet关联一个headless模式的服务,每个pod都有独立的DNS记录,在本例中,可以通过kubia-0.headless_service.default.svc.cluster.local访问kubia-0 pod
- 在创建StatefulSet后,会逐个创建pod,只有在当前pod就绪后,才会创建下一个pod,pod的索引会递增。扩容也类似,逐个扩容,将使用下一个还没用到的顺序索引值。
- StatefulSet缩容也是逐步进行,会先删除最高索引值的pod,且在有实例不健康的情况下,不允许进行缩容操作。
- 缩容只会删除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>
更多推荐
所有评论(0)