这里将介绍Kubernetes工作负载资源中的StatefulSet
创建StatefulSet
不同于RC、RS、Deployment可以用于部署无状态的应用。而对于有状态的应用而言,其要求Pod需要具有稳定的、唯一的网标识符,稳定的、持久的存储。这对于RS、Deployment而言是无法满足的。为此K8s中提供了一种专用于有状态应用的StatefulSet,其可以保证当一个有状态的Pod被删除后(比如人工手动删除),K8s则会创建一个与之完全一致的Pod出来,包括Pod名称、网络主机名、存储等
对于StatefulSet的Pod而言,即使其被重新调度到别的节点,其也必须挂载旧Pod此前所使用的存储。为此Pod所使用的必须是PV持久卷,且需要与Pod解耦。故需要将每个Pod绑定各自的PVC持久卷声明。为此在StatefulSet的定义中,我们需设置PVC模板即可。以便StatefulSet能够按照PVC模板创建出与Pod数量相同的PVC。而PV持久卷则既可以是管理员提前创建的,也可以是动态制备的
这里我们先手动创建两个PV
1 | # 创建持久卷PV |
效果如下所示
对于StatefulSet而言,其还需要提前创建一个Headless Service
1 | # 创建 Headless Service |
现在我们开始创建StatefulSet,配置文件如下所示
1 | # 创建 StatefulSet |
效果如下所示,两个Pod分别绑定各自的PVC。而这两个PVC进一步地分别使用了我们之前创建的两个PV。与此同时,对于StatefulSet创建的Pod而言,其名称命名规则是StatefulSet名称加索引编号
测试
该应用支持通过POST请求将数据存储到容器内的/var/data路径下,通过GET请求获取容器内的/var/data路径下的数据内容。这里我们先启动一个代理,然后利用API服务器访问指定的Pod。效果如下所示,符合预期
对于包含N个Pod副本的StatefulSet而言,其会按照索引顺序依次创建N个Pod。即先创建索引为0的Pod,再创建索引为1的Pod,再创建索引为2的Pod,以此类推。而当我们进行缩容的时候,则它们是按照索引逆序的顺序依次终止Pod的,即顺序为N-1、N-2、N-3、…、2、1、0。现在我们将该StatefulSet的Pod副本数缩容为1
1 | # 将StatefulSet的Pod副本数调整为指定数量 |
效果如下所示。而且即使缩容了,索引1的Pod所使用的PVC、PV也依然会被保留。这样当你再次扩容时,其依然会创建一个索引为1的Pod,且依然会绑定此前索引为1的Pod所使用的PVC。无论这个新Pod会被调度哪个集群节点当中
现在我们重新将该StatefulSet扩容到2。可以看到索引为1的Pod再次使用了之前的PVC。且访问该Pod可以查询到此前的数据,进一步验证了这个结果
查询SRV记录
现在我们创建一个Pod演示如何用于获取该StatefulSet中全部Pod的网络信息
1 | # 创建一个包含dig、ping命令的Pod |
在创建StatefulSet时我们指定了一个Headless Service。其目的在于该Headless Service会创建出相应的SRV记录。通过SRV记录我们就可以知道来该服务对应Pod的域名、IP、端口等信息了。其中该StatefulSet的域名规则一般如下所示
1 | # StatefulSet的域名规则 |
效果如下所示。这样我们就可以实现获取StatefulSet中全部Pod的网络地址了
参考文献
- Kubernetes in Action中文版 Marko Luksa著
- 深入剖析Kubernetes 张磊著