Kubernetes in Action笔记 - (13) Statefulset
了解Statefulset
与ReplicaSet比较
Statefulset 保证了pod在重新调度后保留它们的标识和状态。
与ReplicaSet类似, Statefulset 也是依据Statefulset 的pod模板创建的,也会指定期望的副本个数。
不同的是, Statefulset创建的pod副本并不是完全一样的。每个pod都可以拥有一组独立的数据卷(持久化状态)。pod的名字都是规律的(固定的), 而不是每个新pod都随机获取一个名字。
提供稳定的网络标识
一个Statefulset创建的每个pod都有一个从零开始的顺序索引, 这个会体现在pod的名称和主机名上, 同样还会体现在pod对应的固定存储上。
与普通的pod不一样的是, 有状态的pod有时候需要通过其主机名来定位。无状态Pod都是一样的,所以访问的时候随便选择一个都可以;而有状态的pod是彼此不同的,通常希望操作的是其中特定的一个。
一个Statefulset 通常要求创建一个用来记录每个pod网络标记的headless Service。通过这个Service, 每个pod将拥有独立的DNS记录, 这样集群里它的伙伴或者客户端可以通过主机名方便地找到它。比如说, 一个属于default命名空间, 名为foo的控制服务, 它的一个pod名称为A-0, 那么可以通过下面的完整域名来访问它 : a-0.foo.default.svc.cluster.local
扩缩容 Statefulset
扩容一个Statefulset会使用下一个还没用到的顺序索引值创建一个新的pod实例。比如, 要把一个Statefulset从两个实例扩容到三个实例, 那么新实例的索引值就会是2 (现有实例使用的索引值为0和1)。
缩容一个Statefulset将会最先删除最高索引值的实例,所以缩容的结果是可预知的。作为对比, ReplicaSet 的缩容操作则不同,不知道哪个实例会被删除, 也不能指定先删除哪个实例
因为 Statefulset 缩容任何时候只会操作一个pod实例,所以有状态应用的缩容相对比较慢。举例来说, 一个分布式存储应用若同时下线多个节点, 则可能导致其数据丢失。比如说一个数据项副本数设置为2的数据存储应用,若同时有两个节点下线,一份数据如果它正好保存在这两个节点上记录就会丢失。若缩容是线性的, 则分布式存储应用就有时间把丢失的副本复制到其他节点,保证数据不会丢失。基于以上原因, Statefulset 在有实例不健康的情况下是不允许做缩容操作的 。若一个实例是不健康的, 而这时再缩容一个实例的话, 也就意味着你实际上同时失去了两个集群成员 。
为每个有状态实例提供稳定的专属存储
有状态的pod的存储必须是持久的,并且与pod解耦。必须设置成手动释放,否则数据丢失。
持久卷声明与持久卷是一对一的关系,所以每个Statefulset的 pod 都需要关联到不同的持久卷声明, 与独自的持久卷相对应。
缩容 Statefulset 时会保留持久卷声明, 所以在随后的扩容操作中, 新的pod实例会使用绑定在持久卷上的相同声明和其上的数据
Statefulset 的 at-most-one 的语义
一个 Statefulset 必须保证有状态的pod实例的αt-most-one语义。也就是说一个Statefulset必须在准确确认一个pod不再运行后,才会去创建它的替换pod
在 Statefulset 中发现伙伴节点
一个Statefulset中的成员需要很容易地找到其他的所有成员。当然它可以通过与API服务器通信来获取, 但是K8s的一个目标是设计功能来帮助应用完全感觉不到k8s的存在。因此让应用与API服务器通信的设计是不允许的
DNS中的SRV记录
SRV记录用来指向提供指定服务的服务器的主机名和端口号。k8s通过一个headless service创建SRV记录来指向pod的主机名。
可以在一个临时pod里运行DNS查询工具dig命令, 列出有状态pod的SRV记录。下面的命令运行 一个名为srvlo okup的 一 次性pod(–restart=Never),它会关联控制台(-it)并且在终止后立即删除(–rm)。这个pod依据tutum/dnsutils镜像启动单独的容器, 然后运行dig命令
$ kubectl run -it srvlookup --image=tutum/dnsutils --rm --restart=Never -- dig SRV kubia.default.svc.cluster.local
; ; ANSWER SECTION:
k.d.s.c.l. 30 IN SRV
k.d. s .c.1 . 30 IN SRV
10 33 O kubia-0.kubia.default.svc.cluster.local.
10 33 O kubia-1.kubia.default.svc.cluster.local.
; ; ADDITIONAL SECTION:
kubia-0.kubia.default.svc.cluster.local. 30 IN A 172.17.0.4
kubia-1.kubia.default.svc.cluster.local. 30 IN A 172.17.0.6
上面的 ANSWER SECTION显示了两条指向后台headless service的 SRV记录。 同时如ADDITIONAL SECTION所示, 每个pod都拥有独自的一条记录。
当一个pod要获取一个Statefulset里的其他pod列表时, 需要做的就是触发 一次SRVDNS查询。例如, 在Node.js中查询命令为:
dns.resolveSrv("kubia.default.svc.cluster.local", callBackFunction);
注意: 返回的SRV记录顺序是随机的, 因为它们拥有相同的优先级。
图书资料: