1.1 有状态应用管理statefulset

StatefulSet(有状态集,缩写为sts)常用于部署有状态的且需要有序启动的应用程序,比如在进行SpringCloud项目容器化时,Eureka的部署是比较适合用StatefulSet部署方式的,可以给每个Eureka实例创建一个唯一且固定的标识符,并且每个Eureka实例无需配置多余的Service,其余Spring Boot应用可以直接通过Eureka的Headless Service即可进行注册。

1.1.1 statefulset基本概念

- StatefulSet主要用于管理有状态应用程序的工作负载API对象。比如在生产环境中,可以部署ElasticSearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集群、Kafka集群和ZooKeeper集群等。
- 和Deployment类似,一个StatefulSet也同样管理着基于相同容器规范的Pod。不同的是,StatefulSet为每个Pod维护了一个粘性标识。这些Pod是根据相同的规范创建的,但是不可互换,每个Pod都有一个持久的标识符,在重新调度时也会保留,一般格式为StatefulSetName-Number。
- 比如定义一个名字是Redis-Sentinel的StatefulSet,指定创建三个Pod,那么创建出来的Pod名字就为Redis-Sentinel-0、Redis-Sentinel-1、Redis-Sentinel-2。
- 而StatefulSet创建的Pod一般使用Headless Service(无头服务)进行通信,和普通的Service的区别在于Headless Service没有ClusterIP,它使用的是Endpoint进行互相通信,Headless一般的格式为:
- statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local。

说明:
serviceName为Headless Service的名字,创建StatefulSet时,必须指定Headless Service名称;
0..N-1为Pod所在的序号,从0开始到N-1;
statefulSetName为StatefulSet的名字;
namespace为服务所在的命名空间;
.cluster.local为Cluster Domain(集群域)

假如公司某个项目需要在Kubernetes中部署一个主从模式的Redis,此时使用StatefulSet部署就极为合适,因为StatefulSet启动时,只有当前一个容器完全启动时,后一个容器才会被调度,并且每个容器的标识符是固定的,那么就可以通过标识符来断定当前Pod的角色
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
statefulset详解及为何结合headless service部署有状态应用-LMLPHP

1.1.2 StatefulSet注意事项

一般StatefulSet用于有以下一个或者多个需求的应用程序:

  1. 需要稳定的独一无二的网络标识符。
    
  2. 需要持久化数据。
    
  3. 需要有序的、优雅的部署和扩展。
    
  4. 需要有序的自动滚动更新。
    
    如果应用程序不需要任何稳定的标识符或者有序的部署、删除或者扩展,应该使用无状态的控制器部署应用程序,比如Deployment或者ReplicaSet。
    StatefulSet是Kubernetes 1.9版本之前的beta资源,在1.5版本之前的任何Kubernetes版本都没有。
    Pod所用的存储必须由PersistentVolume Provisioner(持久化卷配置器)根据请求配置StorageClass,或者由管理员预先配置,当然也可以不配置存储。
    为了确保数据安全,删除和缩放StatefulSet不会删除与StatefulSet关联的卷,可以手动选择性地删除PVC和PV)。
    StatefulSet目前使用Headless Service(无头服务)负责Pod的网络身份和通信,需要提前创建此服务。
    删除一个StatefulSet时,不保证对Pod的终止,要在StatefulSet中实现Pod的有序和正常终止,可以在删除之前将StatefulSet的副本缩减为0

为什么要用headless service+statefulSet部署有状态应用?

Headless Services介绍

Headless Services是一种特殊的service,其spec:clusterIP表示为None,这样在实际运行时就不会被分配ClusterIP。也被称为无头服务。

1、headless Service和普通Service的区别

headless不分配clusterIP

headless service可以通过解析service的DNS,返回所有Pod的地址和域名(statefulSet部署的Pod才有域名)

headless service会为关联的Pod分配一个域:
service-name.namespace-name.svc.cluster.local

普通的service,只能通过解析service的DNS返回service的ClusterIP

2、statefulSet和Deployment控制器的区别

statefulSet下的Pod有DNS地址,通过解析Pod的DNS可以返回Pod的IP

StatefulSet会为关联的Pod保持一个不变的Pod Name
statefulset中Pod的hostname格式为
statefulsetname-(pod序号)

而deployment下的Pod没有具体的域名,想访问Pod都是通过普通service来负载均衡到后端pod,无法指定访问具体哪个Pod

3、普通Service解析service的DNS结果

Service的ClusterIP工作原理:一个service可能对应一组endpoints(所有pod的地址+端口),client访问ClusterIP,通过iptables或者ipvs转发到Real Server(Pod)。

StatefulSet+headless service会为关联的每个Pod都分配一个具体的域名:
Pod-Name.service-name.namespace-name.svc.cluster.local

实操部分

1.1.3 定义一个StatefulSet资源文件

statefulset详解及为何结合headless service部署有状态应用-LMLPHP

statefulset详解及为何结合headless service部署有状态应用-LMLPHP

statefulset详解及为何结合headless service部署有状态应用-LMLPHP
创建个Busybox演示如何通过无头service名字来进行网络访问
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
通过nslookup来解析web-0.nginx(sts名称+无头service名称),可以得到这个Pod的ip地址:10.244.32.152
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
进入集群busybox容器对web-0.nginx进行Ping和wget发现都是通的
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
1.1.4 缩容扩容StatefulSet
查看sts lable标签
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
通过标签对指定sts进行监听
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
对sts进行扩容操作
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
可以看到sts启动的顺序是严格按照序号来进行启动的,同理缩容的话会严格按照pod的序号倒序进行删除
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
statefulset详解及为何结合headless service部署有状态应用-LMLPHP

1.1.4 StatefulSet更新策略

1. RollingUpdate 更新策略

  • 默认更新策略RollingUpdate
更新镜像版本

statefulset详解及为何结合headless service部署有状态应用-LMLPHP

statefulset详解及为何结合headless service部署有状态应用-LMLPHP

开启另一个窗口,观察Pod更新过程,可以看到他的更新顺序是倒序的
statefulset详解及为何结合headless service部署有状态应用-LMLPHP

2. Ondelete 更新策略 [适用于灰度发布]

更改更新策略为Ondelete

statefulset详解及为何结合headless service部署有状态应用-LMLPHP
更新镜像版本,并观察更新过程
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
只有进行delete pod删除操作的时候,pod才会被更新
statefulset详解及为何结合headless service部署有状态应用-LMLPHP
statefulset详解及为何结合headless service部署有状态应用-LMLPHP

02-20 10:55