返回文章列表

Kubernetes StatefulSet 佈署有狀態應用

本文介紹如何使用 Kubernetes 的 StatefulSet 佈署有狀態應用程式,以 MySQL 資料函式庫為例,詳細說明 YAML 設定檔的撰寫、無頭服務的建立與 DNS 解析,以及持久化儲存的組態和驗證。文章包含實際操作步驟和指令,並解釋了 StatefulSet 如何確保 Pod

容器技術 資料函式倉管理

在 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

內容解密:

  1. apiVersion 和 kind:指定了 Kubernetes 資源的版本和型別,這裡是 apps/v1 版本的 StatefulSet。
  2. metadata:提供了 StatefulSet 的後設資料,包括名稱、標籤和名稱空間。
  3. spec:定義了 StatefulSet 的規格,包括服務名稱、副本數量、選擇器和範本。
  4. serviceName:指定了管理 StatefulSet 的服務名稱,這裡是 mysql-headless
  5. replicas:定義了要執行的 Pod 副本數量,這裡是 3。
  6. selector:定義了用於選擇 Pod 的標籤選擇器。
  7. template:定義了用於建立 Pod 的範本,包括容器規格和環境變數。
  8. 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

內容解密:

  1. clusterIP: None:指定了這是一個無頭服務,不會分配一個叢集 IP。
  2. selector:定義了用於選擇 Pod 的標籤選擇器。
  3. ports:定義了服務的埠,這裡是 3306。

佈署 StatefulSet

現在,我們可以開始佈署我們的 StatefulSet!請按照以下步驟進行:

  1. 建立一個名為 mysql 的名稱空間。
  2. 建立一個 Secret 儲存 MySQL 環境變數。
  3. 建立無頭服務 mysql-headless
  4. 建立 StatefulSet 物件 mysql-stateful
  5. 使用 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佈署

  1. 使用 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的一個重要特性。
  1. 使用 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
  1. 檢視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 pvckubectl get pv 分別用於檢視PVC和PV的狀態。
  • 輸出結果顯示了每個PVC和PV的名稱、狀態、容量、存取模式等資訊。
  • 這裡可以看到,每個Pod都有其對應的PVC和PV,且狀態均為 Bound,表示儲存資源已正確繫結。

使用無頭服務(Headless Service)實作穩定的網路身份

在Kubernetes中,無頭服務是一種特殊的Service資源,它不具有Cluster IP,而是直接將請求導向後端的Pod。這種機制使得StatefulSet中的Pod能夠擁有穩定的網路身份。

DNS查詢實驗

  1. 登入到之前建立的 k8sutils Pod中。
  2. 使用 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 以釋放儲存資源。