前面介绍的Pod管理对象,如RC/RS、Deployment、DaemonSet等都是面向无状态服务的,而对于有状态的应用,比如MySQL集群,MongoDB集群等,则可以使用StatefulSet来完成。有状态的应用集群通常有以下这些特点:
- 每个节点都有固定的身份ID,通过这个ID,集群中的成员可以相互发现并通信;
- 集群的规模是比较固定的,集群规模不能随意变动;
- 集群中的每个节点都是有状态的,通常会持久化数据到永久存储中。
StatefulSet特性
通过StatefulSet搭建的集群通常有以下这些特性:
- StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。假设StatefulSet的名称为nginx,那么第1个Pod叫nginx-0,第2个叫nginx-1,以此类推;
- StatefulSet控制的Pod副本的启停顺序是受控的,操作第n个Pod时,前n-1个Pod已经是运行且准备好的状态。
- StatefulSet里的Pod采用稳定的持久化存储卷,通过PV或PVC来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数据的安全);
- 配合Headless Service使用,用于发现和控制Pod实例数量。
StatefulSet实践
下面使用StatefulSet搭建个Nginx集群,持久化存储使用上一节搭建的名称为managed-nfs-storage的StorageClass。
创建nginx-headless-service.yml配置文件:
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
name: nginx
spec:
ports:
- port: 80
targetPort: 80
clusterIP: None # 表明为Headleass Service
selector:
role: web-app
创建该Headless Service:
kubectl create -f nginx-headless-service.yml
接着创建nginx-statefulset.yml配置文件:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-sc
spec:
serviceName: "nginx" # 对应刚刚创建的Headless Service名称
replicas: 3
selector:
matchLabels:
role: web-app
template:
metadata:
labels:
role: web-app
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html
name: nginx-persistent-storage # 和下面的pvc名称对应
volumeClaimTemplates: # pvc模板
- metadata:
name: nginx-persistent-storage # pvc名称
spec:
storageClassName: managed-nfs-storage # 指定StorageClass名称
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 100Mi
创建该StatefulSet,观察pod的创建过程:

可以看到,pod的创建是严格one by one的,因为我们定义的StatefulSet的名称位nginx-sc,所以Pod的名称分别位nginx-sc-0、nginx-sc-1和nginx-sc-2。
查看对应的PVC和PV:

状态为Bound。
删除Pod,再次观察Pod的创建过程:

可以看到顺序性是严格保证的。
进入到Pod内部,查看其hostname:

hostname和pod名称一致。
到192.168.33.13的/nfs目录下可以看到挂载了三个nginx目录:
