前面介绍的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目录: