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 Gateway,叢集中的所有資源均可訪問公網。
為節點分配固定公網IP:擁有公網IP的節點可拉取公網鏡像,但需要為部署工作負載的每個節點都分配公網IP。
建立StatefulSet
通過控制台建立
登入Container Service管理主控台,在左側導覽列選擇叢集列表。
在叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇。
在有狀態頁面,單擊使用鏡像建立。
在應用基本資料設定精靈頁面,設定應用的基本資料。然後單擊下一步,進入容器配置嚮導頁面。
在容器配置地區,完成容器的鏡像名稱和連接埠基本配置。其餘設定均為可選設定,保持預設即可。然後單擊下一步,進入進階配置嚮導頁面。鏡像地址如下所示。
重要拉取此鏡像前,您需要為叢集開啟公網訪問能力。如果您在建立叢集時,為專用網路配置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