在 Kubernetes 環境中,佈署有狀態應用程式需要確保 Pod 擁有穩定的網路識別和持久化儲存。StatefulSet 正是為瞭解決這個問題而設計的控制器。不同於 Deployment,StatefulSet 能夠為每個 Pod 分配唯一的序號和 DNS 名稱,方便 Pod 間的通訊和管理。同時,StatefulSet 支援 Persistent Volume Claim,可以將資料持久化儲存,即使 Pod 重新啟動或重建,資料也不會丟失。本文以 MySQL 資料函式庫為例,逐步演示如何使用 StatefulSet 進行佈署,並驗證其功能。首先,我們需要準備 StatefulSet 的 YAML 檔案,其中包含 Pod 的規格、容器映像、服務名稱、副本數量等資訊。接著,建立一個無頭服務,以便 Kubernetes 為每個 Pod 分配唯一的 DNS 名稱。最後,組態持久化儲存,確保資料的永續性。
StatefulSet:佈署有狀態應用程式
在 Kubernetes 中,StatefulSet 用於佈署和管理有狀態應用程式。本章節將詳細介紹如何建立 StatefulSet 並將其應用於叢集。
建立 StatefulSet
首先,我們來看一下用於建立 StatefulSet 的 YAML 清單檔案,名為 mysql-statefulset.yaml:
# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-stateful
labels:
app: mysql
namespace: mysql
spec:
serviceName: mysql-headless
replicas: 3
selector:
matchLabels:
app: mysql
environment: test
template:
metadata:
labels:
app: mysql
environment: test
spec:
containers:
- name: mysql
image: mysql:8.2.0
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_ROOT_PASSWORD
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_USER
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_PASSWORD
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: 1Gi
內容解密:
- apiVersion 和 kind:指定了 Kubernetes 資源的版本和型別,這裡是
apps/v1版本的 StatefulSet。 - metadata:提供了 StatefulSet 的後設資料,包括名稱、標籤和名稱空間。
- spec:定義了 StatefulSet 的規格,包括服務名稱、副本數量、選擇器和範本。
- serviceName:指定了管理 StatefulSet 的服務名稱,這裡是
mysql-headless。 - replicas:定義了要執行的 Pod 副本數量,這裡是 3。
- selector:定義了用於選擇 Pod 的標籤選擇器。
- template:定義了用於建立 Pod 的範本,包括容器規格和環境變數。
- volumeClaimTemplates:定義了用於建立持久性儲存區宣告(PVC)的範本。
無頭服務(Headless Service)
接下來,我們來建立一個無頭服務,名為 mysql-headless:
# mysql-headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
namespace: mysql
spec:
selector:
app: mysql
environment: test
clusterIP: None
ports:
- port: 3306
內容解密:
- clusterIP: None:指定了這是一個無頭服務,不會分配一個叢集 IP。
- selector:定義了用於選擇 Pod 的標籤選擇器。
- ports:定義了服務的埠,這裡是 3306。
佈署 StatefulSet
現在,我們可以開始佈署我們的 StatefulSet!請按照以下步驟進行:
- 建立一個名為
mysql的名稱空間。 - 建立一個 Secret 儲存 MySQL 環境變數。
- 建立無頭服務
mysql-headless。 - 建立 StatefulSet 物件
mysql-stateful。 - 使用
kubectl describe命令觀察 StatefulSet 物件的建立。
$ kubectl apply -f mysql-ns.yaml
namespace/mysql created
$ kubectl create secret generic mysql-secret \
--from-literal=MYSQL_ROOT_PASSWORD='mysqlroot' \
--from-literal=MYSQL_USER='mysqluser' \
--from-literal=MYSQL_PASSWORD='mysqlpassword' \
-n mysql
secret/mysql-secret created
$ kubectl apply -f mysql-headless-service.yaml
service/mysql-headless created
$ kubectl apply -f mysql-statefulset.yaml
statefulset.apps/mysql-stateful created
$ kubectl describe statefulset mysql-stateful -n mysql
$ kubectl get sts -n mysql
NAME READY AGE
mysql-stateful 3/3 2m3s
StatefulSet 提供了一個穩定的網路身份和持久儲存,使得有狀態應用程式可以被可靠地佈署和管理。透過使用無頭服務和持久性儲存區宣告,我們可以實作有狀態應用程式的高用性和可擴充套件性。
StatefulSet:佈署具狀態應用程式
使用StatefulSet佈署MySQL資料函式庫
本章節將探討如何使用Kubernetes的StatefulSet資源佈署具狀態的應用程式,例如MySQL資料函式庫。首先,我們需要了解StatefulSet的基本概念及其與Deployment資源的差異。
驗證StatefulSet佈署
- 使用
kubectl get pods命令檢視已建立的三個Pod副本。由於需要為每個Pod提供持久化儲存(Persistent Volume, PV),因此這個過程可能需要一些時間。
$ kubectl get pod -n mysql
NAME READY STATUS RESTARTS AGE
mysql-stateful-0 1/1 Running 0 2m32s
mysql-stateful-1 1/1 Running 0 2m29s
mysql-stateful-2 1/1 Running 0 2m25s
內容解密:
kubectl get pod -n mysql用於檢視mysql名稱空間下的所有Pod。- 輸出結果顯示三個Pod的名稱、狀態、重啟次數和執行時間。
- Pod名稱字尾的數字(例如
mysql-stateful-0)表示其在StatefulSet中的序號,這是StatefulSet的一個重要特性。
- 使用
kubectl describe pod命令檢視某個Pod的詳細資訊,包括其關聯的PV和PVC(Persistent Volume Claim)。
$ kubectl -n mysql describe pod mysql-stateful-0
Name: mysql-stateful-0
Namespace: mysql
...
Volumes:
mysql-data:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: mysql-data-mysql-stateful-0
ReadOnly: false
內容解密:
kubectl describe pod命令提供Pod的詳細組態和狀態資訊。Volumes部分顯示了Pod使用的儲存卷,其中mysql-data是透過PVC請求的持久化儲存。ClaimName欄位顯示了該Pod使用的PVC名稱,這裡是mysql-data-mysql-stateful-0。
- 檢視PVC和PV的狀態,以確認儲存資源是否正確組態。
$ kubectl get pvc -n mysql
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
mysql-data-mysql-stateful-0 Bound pvc-453dbfee-6076-48b9-8878-e7ac6f79d271 1Gi RWO standard <unset> 8m38s
mysql-data-mysql-stateful-1 Bound pvc-36494153-3829-42aa-be6d-4dc63163ea38 1Gi RWO standard <unset> 8m35s
mysql-data-mysql-stateful-2 Bound pvc-6730af33-f0b6-445d-841b-4fbad5732cde 1Gi RWO standard <unset> 8m31s
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-36494153-3829-42aa-be6d-4dc63163ea38 1Gi RWO Delete Bound mysql/mysql-data-mysql-stateful-1 standard <unset> 11m
pvc-453dbfee-6076-48b9-8878-e7ac6f79d271 1Gi RWO Delete Bound mysql/mysql-data-mysql-stateful-0 standard <unset> 11m
pvc-6730af33-f0b6-445d-841b-4fbad5732cde 1Gi RWO Delete Bound mysql/mysql-data-mysql-stateful-2 standard <unset> 11m
內容解密:
kubectl get pvc和kubectl get pv分別用於檢視PVC和PV的狀態。- 輸出結果顯示了每個PVC和PV的名稱、狀態、容量、存取模式等資訊。
- 這裡可以看到,每個Pod都有其對應的PVC和PV,且狀態均為
Bound,表示儲存資源已正確繫結。
使用無頭服務(Headless Service)實作穩定的網路身份
在Kubernetes中,無頭服務是一種特殊的Service資源,它不具有Cluster IP,而是直接將請求導向後端的Pod。這種機制使得StatefulSet中的Pod能夠擁有穩定的網路身份。
DNS查詢實驗
- 登入到之前建立的
k8sutilsPod中。 - 使用
nslookup命令查詢無頭服務mysql-headless的DNS記錄。
root@k8sutils:/# nslookup mysql-headless
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: mysql-headless.mysql.svc.cluster.local
Address: 10.244.0.14
Name: mysql-headless.mysql.svc.cluster.local
Address: 10.244.0.15
Name: mysql-headless.mysql.svc.cluster.local
Address: 10.244.0.16
內容解密:
nslookup命令用於查詢DNS記錄。- 這裡查詢的是無頭服務
mysql-headless的DNS記錄。 - 輸出結果顯示了該服務對應的三個IP地址,分別對應到StatefulSet中的三個Pod。
StatefulSet – 佈署有狀態應用程式
在 Kubernetes 中,StatefulSet 是一種用於管理有狀態應用程式的控制器。它與 Deployment 不同,StatefulSet 能夠為 Pod 提供穩定的網路身份和持久化儲存。
Headless Service 與穩定的網路身份
當我們建立一個 Headless Service 時,Kubernetes 會為每個 Pod 生成一個 DNS 記錄。這些記錄的形式為 <podName>-<ordinal-number>.<headless-serviceName>.<namespace>.svc.cluster.local>。這樣,我們就可以透過穩定的 DNS 名稱來存取特定的 Pod。
例項驗證
讓我們嘗試使用 MySQL 客戶端連線到 mysql-stateful-0 Pod:
root@k8sutils:/# mysql -u root -p -h mysql-stateful-0.mysql-headless
連線成功後,我們建立了一個名為 ststest 的資料函式庫:
MySQL [(none)]> create database ststest;
Query OK, 1 row affected (0.002 sec)
然後,我們強制重新啟動 mysql-stateful-0 Pod:
$ kubectl delete po -n mysql mysql-stateful-0
重新啟動後,我們再次連線到 mysql-stateful-0 Pod,並檢查資料函式庫內容:
MySQL [(none)]> show databases;
+
---
-
---
-
---
-
---
-
---
-+
| Database |
+
---
-
---
-
---
-
---
-
---
-+
| information_schema |
| mysql |
| performance_schema |
| ststest |
| sys |
+
---
-
---
-
---
-
---
-
---
-+
5 rows in set (0.003 sec)
結果表明,資料函式庫 ststest 仍然存在,這意味著資料是持久化的。
穩定 DNS 名稱的重要性
穩定的 DNS 名稱對於 StatefulSet 中的 Pod 至關重要。它使得我們可以在不猜測 Pod IP 地址或名稱的情況下,直接向特定的 Pod 傳送請求。這對於佈署叢集式資料函式庫(如 etcd 或 MongoDB)非常有用。
使用案例
- 佈署叢集式資料函式庫時,需要指定其他節點的網路地址。穩定的 DNS 名稱可以幫助我們實作這一點。
- 當實作自己的儲存解決方案時,需要將邏輯分片對映到物理 Pod 副本。穩定的 DNS 名稱可以用於此對映,確保查詢能夠正確地路由到對應的 Pod。
狀態持久化
StatefulSet 中的 Pod 可以透過 Persistent Volume(PV)實作狀態持久化。當 Pod 被重新建立時,PV 會重新繫結到新的 Pod 上,從而保留資料。
例項驗證
我們刪除了所有 StatefulSet 中的 Pod:
$ kubectl delete po -n mysql mysql-stateful-0 mysql-stateful-1 mysql-stateful-2
Kubernetes 重新建立了這些 Pod,並將 PV 繫結到新的 Pod 上:
$ kubectl get pod -n mysql
NAME READY STATUS RESTARTS AGE
k8sutils 1/1 Running 0 47m
mysql-stateful-0 1/1 Running 0 44s
mysql-stateful-1 1/1 Running 0 43s
mysql-stateful-2 1/1 Running 0 41s
透過 kubectl describe 命令,我們可以驗證 PV 是否正確地繫結到新的 Pod 上:
$ kubectl describe pod -n mysql -l app=mysql | egrep 'ClaimName|Name:'
Name: mysql-stateful-0
ClaimName: mysql-data-mysql-stateful-0
ConfigMapName: kube-root-ca.crt
Name: mysql-stateful-1
ClaimName: mysql-data-mysql-stateful-1
ConfigMapName: kube-root-ca.crt
Name: mysql-stateful-2
ClaimName: mysql-data-mysql-stateful-2
ConfigMapName: kube-root-ca.crt
需要注意的是,當刪除 StatefulSet 時,PV 不會被自動刪除。需要手動清理 PV 以釋放儲存資源。