跳轉到

19章節:深入理解 StatefulSet(二):儲存狀態

前言與回顧

我們回顧下,上一篇的要點~ StatefulSet 觀念中有其二最為重要:

1. 拓樸狀態:這意味著同一個服務不同的 pod 之間,有相依性、順序性。
2. 儲存狀態:這意味著該 pod 目前所存取到的數據資料,過了 n 個時間點,或哪怕 pod 重啟了,仍然存取相同一份資料。

在先前關於 Pod 章節中,提到需要使用 Volume 並且在 pod 中定義了spec.volumes 來表達儲存空間需求。 在沒有相關 API 協助下,pod 應用服務開發者必須要很清楚儲存資源從何而來,甚至需要知道背後更多細節,這對開發者不甚友善。

何況,在大型服務的背後,需要有強而有力的儲存資源,這些更需要專業的管理者,而不是讓開發者分心與擔憂儲存的穩定性、可用性。

因此,在 K8s 環境下例如要整合 Ceph、EMC、NetApp 等各個形式儲存系統,提供了重要的 API 介面:

  • PersistentVolume(PV)
  • PersistentVolumeClaims(PVC)

關於 PersistentVolumeClaims(PVC)

使用 PVC 前

先來看下,尚未透過上述 API 對象引用 Volume 時,pod yaml 檔案必須自行定義複雜的volumes資訊 ; 範例:採用 Ceph 儲存系統

apiVersion: v1
kind: Pod
metadata:
  name: rbd
spec:
  containers:
    - image: kubernetes/pause
      name: rbd-rw
      volumeMounts:
      - name: rbdpd
        mountPath: /mnt/rbd
  volumes:
    - name: rbdpd
      rbd:
        monitors:
        - '10.2.3.1:6789'
        - '10.2.3.2:6789'
        - '10.2.3.3:6789'
        pool: kube
        image: foo
        fsType: ext4
        readOnly: true
        user: admin
        keyring: /etc/ceph/keyring
        imageformat: "2"
        imagefeatures: "layering"

上述 yaml 檔案呈現出兩個現象:

1. 必須懂 Ceph RBD 細節。
2. 資源暴露,相對有資訊管理的考量。

使用 PVC 後

下面 yaml 檔案內容,透過獨立的 PVC 說明資源需求,pod yaml 再引用 PVC 作為volumes來源即可。 如此作法,開發者只需專注於"儲存需求面"。

# PVC API 對象,表達出儲存資源需求
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pv-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

---
apiVersion: v1
kind: Pod
metadata:
  name: pv-pod
spec:
  containers:
    - name: pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: pv-storage
  volumes:
    - name: pv-storage
      persistentVolumeClaim:      # << 指定使用 PVC
        claimName: pv-claim

關於 PersistentVolume(PV)

講了 PVC 就不得不說說 PV~

PVC 就像是資源需求者,說明了需要多少儲存資源~

PV 就是資源提供者, 既是資源提供者,顧名思義 PV 肩負著 K8s 與各式儲存系統之間的通訊橋樑,後端各式的儲存系統可能是 Ceph、EMC、NetApp 或者是 NFS。

下列是 K8s 透過 PV 取得後端 Ceph 儲存系統資源的 yaml 定義檔案。

kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv-volume
  labels:
    type: local
spec:
  capacity:
    storage: 10Gi
  rbd:
    monitors:
    - '10.16.154.78:6789'
    - '10.16.154.82:6789'
    - '10.16.154.83:6789'
    pool: kube
    image: foo
    fsType: ext4
    readOnly: true
    user: admin
    keyring: /etc/ceph/keyring
    imageformat: "2"
    imagefeatures: "layering"

有無發現,上述 yaml 內容中的 spec.rbd 字段,與本文章第一個 pod yaml 內容 spec.volumes.rbd 一樣的。 原本複雜的資源提供者角色工作(儲存服務介接),透過 PV 來完成。

PV、PVC 優點

1. 資源提供者,透過 PV 來定義有哪些資源可用。
2. 資源需求者,透過 PVC 來表達需要多少空間與存取模式。
3. 經過 PV、PVC 兩個 API 介面,可以分責分權更加容易定位問題點,另可避免資訊管理的負擔。

PV、PVC 缺點

目前明確缺點是,需要先定義出 PV(確保資源可用),PVC 才可獲得必要資源。

StatefulSet 與 PV & PVC

StatefulSet 也是借重 PV & PVC 角色,對於完成「儲存狀態」目標變得很輕易完成。 看下 StatefulSet yaml 範例:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:     # << 使用 PVC Templates
  - metadata:
      name: www
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi

此範本使用 volumeClaimTemplates ,此作用會促使 StatefulSet 管理的 pod 皆會對應相同的 PVC 規格。

套用此 StatefulSet 後,會有幾個特色需要知道:

  1. PVC 名稱命名特徵:<pvc_name>-<pod_name>-<number>
  2. PVC 名稱編號,會與 Pod 名稱編號相同。
  3. 另外此 PVC 成功綁定 PV 後,會呈現 STATUS:Bound 狀態。
  4. 即使刪除了 pod ,並不會刪除 PVC,PVC 管理獨立於另一個 PVC 控制器。

    提醒:當然 PVC 要能夠成功綁定,需要先設定好 PV。

Pod、PVC 狀態如下

kubectl get pvc
# NAME     STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0  Bound    pvc-xxx-id   1Gi        RWO            standard       1d
www-web-1  Bound    pvc-xxx-id   1Gi        RWO            standard       1d

kubectl get pod
# NAME    READY   STATUS      RESTARTS   AGE
web-0     1/1     Running     0          1d
web-1     1/1     Running     0          1d

特別回顧下 StatefulSet 拓樸狀態特色,說明下當刪除 Pod web-0 之後的過程:

  1. StatefulSet 控制器會發現 Pod web-0 已經消失了,開始進行重建相同名稱的 Pod web-0
  2. 重建規範當然是上述 StatefulSet yaml 內容,故此 Pod web-0 所對應的 PVC 仍是 www-web-0
  3. 基於上述 StatefulSet yaml 內容,Pod web-0 會尋找、使用相對應的 PVC www-web-0
  4. 原本已經寫入 PVC www-web-0 儲存空間內之內容,即可被 Pod web-0 讀取。

這 Pod web-0 重建過程流程,呼應 StatefulSet 拓樸狀態的基本要求。 也是完成儲存狀態 一致性的要求。


StatefulSet 其他特色與回顧

  • StatefulSet 控制器直接管理對象是 Pod,相較於 Deployment 是透過 ReplicaSet 管理 Pod 有所不同。 區分方式就是 Pod 名稱裡的編號

  • StatefulSet 透過 Headless Service 為這些有編號的 Pod 帶有唯一的 DNS 紀錄。 <pod_name>.<service_name>.<namespace>.svc.cluster.local 其對應的 IP 記錄,會隨著 Pod_IP 變動跟著更新。

  • StatefulSet 藉由 拓樸狀態、儲存狀態 兩大設計功能,完成「有狀態服務性質」的應用程式,所需要的 狀態相依性、順序性、資料一致性 目標。