概述 StatefulSet 是 Pod 资源控制器的一种实现,用于部署和扩展有状态应用的 Pod 资源,确保他们的运行顺序及每个 Pod 资源的唯一性,StatefulSet 需要为每个 Pod 维持一个唯一且固定的标识符,为其创建专有的存储卷.StatefulSet 主要有如下特性
稳定且唯一的网络标识符
稳定且持久的存储
有序优雅的部署和扩展,删除和终止
有序而自动的滚动更新
一般来说,完整可用的 StatefulSet 通常由以下三个组件组成:
Headless Service
: 用于为资源标识符生成可解析的 DNS 资源记录
StatefulSet
: 用于管控 Pod 资源
VolumeClaimTemplates
: 基于静态或动态 PV 为 Pod 资源提供专有且稳定的存储
对于一个拥有 N 个副本的 StatefulSet 来说,其 Pod 对象会被有序的创建,顺序依次是 {0...N-1}
,删除则以相反的方式进行.Pod 资源的名称格式为 $(statefulset_name)-$(ordinal)
,其域名后缀由相关 Headless 类型的 Service 资源给出,格式为 $(service_name).$(namespace).svc.cluster.local
.
StatefulSet 控制器会为每个 VolumeClaim 模版创建一个专用的 PV,它会从模版中指定 StorageClass 中为每个 PVC 创建 PV,未指定 Storage 将使用默认的 StorageClass 资源.如果不支持 PV 的动态供给,就需要事先创建好满足需求的所有 PV.
StatefulSet 应用 资源清单 一个完整的 StatefulSet 控制器需要由 Headless Service, StatefulSet 和 volumeClaimTemplate 组成.一般来说定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 apiVersion: v1 kind: Service metadata: name: prometheus namespace: default labels: app: prometheus spec: clusterIP: None selector: app: prometheus ports: 9090 - port: prometheus --- apiVersion: apps/v1 kind: StatefulSet metadata: name: prometheus namespace: default lables: app: prometheus spec: podManagementPolicy: "Parallel" revisionHistoryLimit: 10 updateStrategy: type: "RollingUpdate" rollingUpdate: partition: serviceName: "prometheus" replicas: 1 selector: matchLabels: app: prometheus-pod template: metadata: labels: app: prometheus-pod spec: volumeClaimTemplates: - metadata: name: spec: storageClassName: accessModes: - ReadWriteOnce resources: requests: storage: "500Mi"
可以看出,StatefulSet 除了需要在 spec 字段中定义 serviceName
,volumeClaimTemplates
外,其它常用字段基本与 Deployment 相同
StatefulSet 中 Pod 资源的标识符 StatefulSet 控制器创建的 Pod 对象拥有固定且唯一的标识符,他们基于唯一索引,即相关 StatefulSet 名称而生成,名称格式为 <statefulset_name>-<ordinal_index>
(index 从 0 开始).
这些名称会由 StatefulSet 资源相关的 headless 资源创建为 DNS 资源记录,域名格式为 $(service_name).$(namespace).svc.cluster.local
.Pod 资源记录为 $(pod_name).$(service_name).$(namespace).svc.cluster.local
.
Headless Service 资源借助 SRV 记录来引用真正提供服务的后端 Pod 资源的主机名称,进行指向包含 Pod IP 地址的记录条目.StatefulSet 控制器管理的 Pod 在重建后 IP 可能会变化,但它的名称标识在重建后保持不变.
StatefulSet 中 Pod 资源的存储卷 StatefulSet 控制器通过 volumeClaimTemplates
为每个 Pod 副本自动创建并关联一个 PVC 对象,它们分别绑定了一个动态供给的 PV 对象.
删除 StatefulSet 控制器的 Pod 资源,其存储卷并不会被删除,除非用户或管理员手动删除.因此,经由 StatefulSet 重建后的 Pod,会自动关联之前的 PVC 存储卷,且之前数据依旧可用,实现数据持久化.
案例: etcd 集群
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 apiVerision: v1 kind: Service metadata: name: etcd annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" spec: clusterIP: None selector: app: etcd-member ports: - port: 2379 name: client - port: 2380 name: peer --- apiVersion: v1 kind: Service metadata: name: etcd-client spec: type: NodePort selector: app: etcd-member ports: - name: etcd-client port: 2379 protocol: TCP targetPort: 2379
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 apiVersion: apps/v1 kind: StatefulSet metadata: name: etcd labels: app: etcd spec: nameService: etcd replicas: 3 selector: app: etcd-member template: metadata: name: etcd labels: app: etcd-member spec: containers: - name: etcd image: "quay.io/coreos/etcd:v3.2.16" ports: - containerPort: 2379 name: client - containerPort: 2380 name: peer env: - name: CLUSTER_SIZE value: "3" - name: SET_NAME value: "etcd" volumeMounts: - name: data mountPath: /var/run/etcd command: - "/bin/sh" - "-ecx" - | IP=$(hostname -i) PEERS="" for i in $(seq 0 $((${CLUSTER_SIZE} -1 ))); do ... done exec etcd --name ${HOSTNAME} \ --listen-peer-urls http://${IP}:2380 \ --listen-client-urls http://${IP}:2379,http://127.0.0.1:2379 \ --advertise-client-urls http://${HOSTNAME}.${SET_NAME}:2379 \ --initial-advertise-peer-urls http://${HOSTNAME}.${SET_NAME}:2380 \ --initial-cluster-token etcd-cluster-1 \ --initial-cluster ${PEERS} \ --initial-cluster-state new \ --data-dir /var/run/etcd/default.etcd volumeClaimTemplates: - metadata: name: data spec: storageClassName: nfs-storageclass accessModes: - "ReadWriteOnce" resources: requests: storage: 1Gi