共计 6043 个字符,预计需要花费 16 分钟才能阅读完成。
本篇文章给大家分享的是有关怎样浅析 Kubernetes StatefulSet,丸趣 TV 小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着丸趣 TV 小编一起来看看吧。
StatefulSet 和 Deployment 的区别
“Deployment 用于部署无状态服务,StatefulSet 用来部署有状态服务”。
具体的,什么场景需要使用 StatefulSet 呢?官方给出的建议是,如果你部署的应用满足以下一个或多个部署需求,则建议使用 StatefulSet。
稳定的、唯一的网络标识。
稳定的、持久的存储。
有序的、优雅的部署和伸缩。
有序的、优雅的删除和停止。
有序的、自动的滚动更新。
稳定的主要是针对 Pod 发生 re-schedule 后仍然要保持之前的网络标识和持久化存储。这里所说的网络标识包括 hostname、集群内 DNS 中该 Pod 对应的 A Record,并不能保证 Pod re-schedule 之后 IP 不变。要想保持 Pod IP 不变,我们可以借助稳定的 Pod hostname 定制 IPAM 获取固定的 Pod IP。借助 StatefulSet 的稳定的唯一的网络标识特性,我们能比较轻松的实现 Pod 的固定 IP 需求,然后如果使用 Deployment,那么将会复杂的多,你需要考虑滚动更新的过程中的参数控制 (maxSurge、maxUnavailable)、每个应用的 IP 池预留造成的 IP 浪费等等问题。
因此,我想再加一个 StatefulSet 的使用场景:
实现固定的 Pod IP 方案, 可以优先考虑基于 StatefulSet;
最佳实践
StatefulSet 对应 Pod 的存储最好通过 StorageClass 来动态创建:每个 Pod 都会根据 StatefulSet 中定义的 VolumeClaimTemplate 来创建一个对应的 PVC,然后 PVS 通过 StorageClass 自动创建对应的 PV,并挂载给 Pod。所以这种方式,需要你事先创建好对应的 StorageClass。当然,你也可以通过预先由管理员手动创建好对应的 PV,只要能保证自动创建的 PVC 能和这些 PV 匹配上。
为了数据安全,当删除 StatefulSet 中 Pods 或者对 StatefulSet 进行缩容时,Kubernetes 并不会自动删除 StatefulSet 对应的 PV,而且这些 PV 默认也不能被其他 PVC Bound。当你确认数据无用之后再手动去删除 PV 的时候,数据是否删除取决于 PV 的 ReclaimPolicy 配置。Reclaim Policy 支持以下三种:
目前只有 NFS 和 HostPath 支持 Recycle;
EBS,GCE PD, Azure Disk,Openstack Cinder 支持 Delete。
Retain,意味着需要你手动清理;
Recycle,等同于 rm -rf /thevolume/*
Delete,默认值,依赖于后端的存储系统自己实现。
注意:
请小心删除 StatefulSet 对应的 PVC,首先确保 Pods 已经完全 Terminate,然后确定不需要 Volume 中的数据后,再考虑删除 PV。因为删除 PVC 可能触发对应 PV 的自动删除,并根据 StorageClass 中的 recalimPolicy 配置可能造成 volume 中的数据丢失。
因为部署的是有状态应用,我们需要自己创建对应的 Headless Service,注意 Label 要和 StatefulSet 中 Pods 的 Label 匹配。Kubernetes 会为该 Headless Service 创建对应 SRV Records,包含所有的后端 Pods,KubeDNS 会通过 Round Robin 算法进行选择。
在 Kubernetes 1.8+ 中,你必须保证 StatefulSet 的 spec.selector 能匹配.spec.template.metadata.labels,否则会导致 StatefulSet 创建失败。在 Kubernetes 1.8 之前,StatefulSet 的 spec.selector 如果没指定则默认会等同于.spec.template.metadata.labels。
对 StatefulSet 进行缩容前,你需要确认对应的 Pods 都是 Ready 的,否则即使你触发了缩容操作,Kubernetes 也不会真的进行缩容操作。
如何理解稳定的网络标识
StatefulSet 中反复强调的“稳定的网络标识”,主要指 Pods 的 hostname 以及对应的 DNS Records。
HostName:StatefulSet 的 Pods 的 hostname 按照这种格式生成:$(statefulset name)-$(ordinal),ordinal 从 0 ~ N-1(N 为期望副本数)。
StatefulSet Controller 在创建 pods 时,会给 pod 加上一个 pod name label:statefulset.kubernetes.io/pod-name, 然后设置到 Pod 的 pod name 和 hostname 中。
pod name label 有啥用呢?我们可以创建独立的 Service 匹配到这个指定的 pod,然后方便我们单独对这个 pod 进行 debug 等处理。
DNS Records:
Headless Service 的 DNS 解析:$(service name).$(namespace).svc.cluster.local 通过 DNS RR 解析到后端其中一个 Pod。SRV Records 只包含对应的 Running and Ready 的 Pods,不 Ready 的 Pods 不会在对应的 SRV Records 中。
Pod 的 DNS 解析:$(hostname).$(service name).$(namespace).svc.cluster.local 解析到对应 hostname 的 Pod。
如何理解稳定的持久化存储
每个 Pod 对应一个 PVC,PVC 的名称是这样组成的:$(volumeClaimTemplates.name)-$(pod s hostname), 跟对应的 Pod 是一一对应的。
当 Pod 发生 re-schedule(其实是 recreate)后,它所对应的 PVC 所 Bound 的 PV 仍然会自动的挂载到新的 Pod 中。
Kubernetes 会按照 VolumeClaimTemplate 创建 N(N 为期望副本数) 个 PVC,由 PVCs 根据指定的 StorageClass 自动创建 PVs。
当通过级联删除 StatefulSet 时并不会自动删除对应的 PVCs,所以 PVC 需要手动删除。
当通过级联删除 StatefulSet 或者直接删除对应 Pods 时,对应的 PVs 并不会自动删除。需要你手动的去删除 PV。
部署和伸缩时与 Deployment 的区别
当部署有 N 个副本的 StatefulSet 应用时,严格按照 index 从 0 到 N - 1 的递增顺序创建,下一个 Pod 创建必须是前一个 Pod Ready 为前提。
当删除有 N 个副本的 StatefulSet 应用时,严格按照 index 从 N - 1 到 0 的递减顺序删除,下一个 Pod 删除必须是前一个 Pod shutdown 并完全删除为前提。
当扩容 StatefulSet 应用时,每新增一个 Pod 必须是前一个 Pod Ready 为前提。
当缩容 StatefulSet 应用时,没删除一个 Pod 必须是前一个 Pod shutdown 并成功删除为前提。
注意 StatefulSet 的 pod.Spec.TerminationGracePeriodSeconds 不要设置为 0。
Node 网络异常等情况下该如何处理
正常情况下,StatefulSet Controller 会保证集群内同一 namespace 下不会出现多个相同 network identity 的 StatefulSet Pods。
如果集群内出现以上情况,那么有可能导致该有状态应用不能正常工作、甚至出现数据丢失等致命问题。
那么什么情况下会导致出现同一 namespace 下会出现多个相同 network identity 的 StatefulSet Pods 呢?我们考虑下 Node 出现网络 Unreachable 的情况:
如果你使用 Kubernetes 1.5 之前的版本,当 Node Condition 是 NetworkUnavailable 时,node controller 会强制从 apiserver 中删除这个 Node 上的这些 pods 对象,这时 StatefulSet Controller 就会自动在其他 Ready Nodes 上 recreate 同 identity 的 Pods。这样做其实风险是很大的,可能会导致有一段时间有多个相同 network identity 的 StatefulSet Pods,可能会导致该有状态应用不能正常工作。所以尽量不要在 Kubernetes 1.5 之前的版本中使用 StatefulSet,或者你明确知道这个风险并且无视它。
如果你使用 Kubernetes 1.5+ 的版本,当 Node Condition 是 NetworkUnavailable 时,node controller 不会强制从 apiserver 中删除这个 Node 上的这些 pods 对象,这些 pods 的 state 在 apiserver 中被标记为 Terminating 或者 Unknown,因此 StatefulSet Controller 并不会在其他 Node 上再 recreate 同 identity 的 Pods。当你确定了这个 Node 上的 StatefulSet Pods shutdown 或者无法和该 StatefulSet 的其他 Pods 网络不同时,接下来就需要强制删除 apiserver 中这些 unreachable pods object,然后 StatefulSet Controller 就能在其他 Ready Nodes 上 recreate 同 identity 的 Pods,使得 StatefulSet 继续健康工作。
那么在 Kubernetes 1.5+ 中,如何强制从 apiserver 中删除该 StatefulSet pods 呢?有如下三种方法:
如果 Node 永久的无法连接网络或者关机了,意味着能确定这个 Node 上的 Pods 无法与其他 Pods 通信了,不会对 StatefulSet 应用的可用性造成影响,那么建议手动从 apiserver 中删除该 NetworkUnavailable 的 Node,Kubernetes 会自动从 apiserver 中删除它上面的 Pods object。
如果 Node 是因为集群网络脑裂导致的,则建议去检查网络问题并成功恢复,因为 Pods state 已经是 Terminating 或者 Unkown, 所以 kubelet 从 apiserver 中获取到这个信息后就会自动删除这些 Pods。
其他情况才考虑直接手动从 apiserver 中删除这些 Pods,因为这时你无法确定对应的 Pods 是否已经 shutdown 或者对 StatefulSet 应用无影响,强制删除后就可能导致出现同一 namespace 下有多个相同 network identity 的 StatefulSet Pods,所以尽量不要使用这种方法。
kubectl delete pods pod –grace-period=0 –force
小知识:当前 Node Condition 有以下 6 种:
Node ConditionDescriptionOutOfDiskTrue if there is insufficient free space on the node for adding new pods, otherwise FalseReadyTrue if the node is healthy and ready to accept pods, False if the node is not healthy and is not accepting pods, and Unknown if the node controller has not heard from the node in the last 40 secondsMemoryPressureTrue if pressure exists on the node memory – that is, if the node memory is low; otherwise FalseDiskPressureTrue if pressure exists on the disk size – that is, if the disk capacity is low; otherwise FalseNetworkUnavailableTrue if the network for the node is not correctly configured, otherwise FalseConfigOKTrue if the kubelet is correctly configured, otherwise FalseStatefulSet 的 Pod 管理策略
Kubernetes 1.7+,StatefulSet 开始支持 Pod Management Policy 配置,提供以下两种配置:
OrderedReady,StatefulSet 的 Pod 默认管理策略,就是逐个的、顺序的进行部署、删除、伸缩,也是默认的策略。
Parallel,支持并行创建或者删除同一个 StatefulSet 下面的所有 Pods,并不会逐个的、顺序的等待前一个操作确保成功后才进行下一个 Pod 的处理。其实用这种管理策略的场景非常少。
StatefulSet 的更新策略
StatefulSet 的更新策略(由.spec.updateStrategy.type 指定)支持以下两种:
OnDelete, 含义同 Deployment 的 OnDelete 策略,大家应该很熟悉了,不多介绍。
RollingUpdate,滚动更新过程也跟 Deployment 大致相同,区别在于:
所有 ordinal 大于等于 partition 指定的值的 Pods 将会进行滚动更新。
所有 ordinal 小于 partition 指定的值得 Pods 将保持不变。即使这些 Pods 被 recreate,也会按照原来的 pod template 创建,并不会更新到最新的版本。
特殊地,如果 partition 的值大于 StatefulSet 的期望副本数 N,那么将不会触发任何 Pods 的滚动更新。
相当于 Deployment 的 maxSurge=0,maxUnavailable=1(其实 StatefulSet 是不存在这两个配置的)
滚动更新的过程是有序的(逆序),index 从 N - 1 到 0 逐个依次进行,并且下一个 Pod 创建必须是前一个 Pod Ready 为前提,下一个 Pod 删除必须是前一个 Pod shutdown 并完全删除为前提。
支持部分实例滚动更新,部分不更新,通过.spec.updateStrategy.rollingUpdate.partition 来指定一个 index 分界点。
以上就是怎样浅析 Kubernetes StatefulSet,丸趣 TV 小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注丸趣 TV 行业资讯频道。