StatefulSet,又称“有状态工作负载”。与Deployment不同,它会为Pod保存状态,因此适用于数据库、消息队列、分布式存储系统等场景。通过本文,您可了解StatefulSet的特点、通过控制台及kubectl创建StatefulSet的方法以及验证保持Pod状态的示例。
StatefulSet介绍
与Deployment相似,StatefulSet也会保证有既定数量的Pod在正常运行。但不同的是,StatefulSet会通过以下措施保留Pod的身份:
- 有序、固定的名称:StatefulSet的每个Pod会按顺序命名为 - <StatefulSet名称>-<序号>。例如,StatefulSet的名称为db-app,则Pod名称为db-app-0、db-app-1。删除并重建Pod时,新建Pod会继承原有的名称。
- 稳定的网络标识:StatefulSet通常需要关联一个Headless Service(通过 - spec.serviceName指定)。这个Headless Service并不像ClusterIP提供Pod的负载均衡,而仅用于为Pod提供固定的域名(对Headless Service进行DNS查询时,DNS会返回所有匹配的Pod的IP地址)。指定Headless Service后,Pod的域名格式为- <Pod名称>.<Headless Service名称>.<namespace>.svc.<ClusterDomain>,例如- db-app-01.db-app.default.svc.cluster.local。Pod重建后,域名会自动被解析到新Pod。
- 稳定的持久化存储:在StatefulSet中,可以指定PVC模板(通过 - spec.volumeClaimTemplates指定)。StatefulSet会根据此模板为每个Pod生成独立的PersistentVolumeClaim(PVC),PVC名称为- <PVC模板名称>-<Pod名称>。当Pod被删除时,PVC会被保留并自动关联到使用相同序号的新Pod。
以上的这些措施保证了StatefulSet的Pod在重建后能继承原有的网络和存储状态,使应用从持久化数据中恢复运行。关于StatefulSet的更多信息,请参见官方文档。
本文示例使用的镜像为公网镜像,拉取时集群或节点需具备公网访问能力:
- 为集群开启访问公网的能力(推荐):为集群所在的VPC创建公网NAT网关,集群中的所有资源均可访问公网。 
- 为节点分配固定公网IP:拥有公网IP的节点可拉取公网镜像,但需要为部署工作负载的每个节点都分配公网IP。 
创建StatefulSet
通过控制台创建
- 登录容器服务管理控制台,在左侧导航栏选择集群列表。 
- 在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择。 
- 在有状态页面,单击使用镜像创建。 
- 在应用基本信息配置向导页面,设置应用的基本信息。然后单击下一步,进入容器配置向导页面。 
- 在容器配置区域,完成容器的镜像名称和端口基本配置。其余设置均为可选设置,保持默认即可。然后单击下一步,进入高级配置向导页面。镜像地址如下所示。 重要- 拉取此镜像前,您需要为集群开启公网访问能力。如果您在创建集群时,为专有网络配置SNAT选择保持默认勾选,则集群已拥有公网访问能力。如果未选择,请参见为集群开启访问公网的能力。 - registry.cn-hangzhou.aliyuncs.com/acs-sample/nginx:latest 
- 在高级配置向导页面中设置访问、伸缩、调度和标签注解。在访问设置区域,创建一个虚拟集群IP(ClusterIP)类型的Service,并勾选实例间服务发现(Headless Service),单击确定。然后,单击最下方的创建。  
- 创建StatefulSet时,控制台上的配置项(应用基本信息、容器配置、高级配置)与Deployment完全相同。其余配置项的说明,请参见配置项说明。 
通过kubectl创建
- 创建工作负载前,请确保已通过kubectl连接到集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群。 
- 复制下方的YAML文件,并保存到statefulset.yaml中。下方的YAML中定义了: - 用于提供稳定域名的Headless Service - nginx。
- 为Pod关联了 - hostPath存储的StatefulSet。
- 用于对外暴露 - StatefulSet的LoadBalancer类型Service,在本示例中仅作为验证Nginx页面的一种方式。
 - apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: clusterIP: None # Headless Service selector: app: nginx ports: - port: 80 name: http --- apiVersion: apps/v1 kind: StatefulSet # 工作负载类型 metadata: name: nginx-test namespace: default # 根据需要更改命名空间 labels: app: nginx spec: serviceName: "nginx" # 选择前面创建的Headless Service replicas: 2 # 指定-Pod数量 selector: matchLabels: app: nginx template: # Pod配置 metadata: labels: # Pod标签 app: nginx spec: containers: - name: nginx # 容器名称 image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6 # 使用特定版本的 Nginx 镜像 ports: - containerPort: 80 # 容器暴露的端口 protocol: TCP # 指定协议为 TCP/UDP volumeMounts: - name: node-dir-volume # 卷名称,需与下方volumes名称相同 mountPath: /tmp # 容器内的挂载路径 volumes: - name: node-dir-volume hostPath: path: /local_storage # 节点本地的目录路径 type: DirectoryOrCreate # 如果目录不存在则自动创建 --- apiVersion: v1 kind: Service metadata: name: nginx-test-svc namespace: default # 根据需要更改命名空间 labels: app: nginx spec: selector: app: nginx # 匹配标签,确保服务指向正确的 Pods ports: - port: 80 # Service 在集群内提供的端口 targetPort: 80 # 指向容器内部应用程序监听的端口 (containerPort) protocol: TCP # 协议,默认是 TCP type: LoadBalancer # 服务类型,默认是 ClusterIP,内部访问
- 执行以下命令,创建StatefulSet及Service。 - kubectl apply -f statefulset.yaml- 预期输出: - service/nginx created statefulset.apps/nginx-test created service/nginx-test-svc created
- 执行以下命令,查看Service的公网IP地址。 - kubectl get svc- 预期输出: - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 172.16.**.*** <none> 443/TCP 4h47m nginx ClusterIP None <none> 80/TCP 1h10m nginx-test-svc LoadBalancer 172.16.**.*** 106.14.**.*** 80:31130/TCP 1h10m
- 在浏览器中输入nginx的公网IP( - 106.14.**.***),即可访问工作负载所属的Nginx容器。 
验证StatefulSet特性
- 执行以下命令,查看Pod状态。 - kubectl get pod nginx-test-0- 预期输出如下。 - NAME READY STATUS RESTARTS AGE nginx-test-0 1/1 Running 0 7m41s
- 执行以下命令删除Pod。 - kubectl delete pod nginx-test-0- 预期输出: - pod "nginx-test-0" deleted
- 执行以下命令,查看Pod状态。 - kubectl get pod nginx-test-0- 预期输出如下, - STATUS为- Running时,表示新Pod已正常运行,继承了原有名称。- NAME READY STATUS RESTARTS AGE nginx-test-0 1/1 Running 0 20s