本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

使用 Kubernetes Pet Sets 和 FlexVolumes 以及 Datera Elastic Data Fabric 擴充套件有狀態應用程式

引言

隨著客戶從無狀態工作負載轉向執行有狀態應用程式,Kubernetes 中的持久卷是基礎。雖然 Kubernetes 已經支援 MySQL、Kafka、Cassandra 和 Couchbase 等有狀態應用程式一段時間,但 Pet Sets 的引入顯著改善了這種支援。特別是,透過 Pet Sets 實現的置備和啟動的排序過程、擴充套件和持久關聯的能力,使得自動化擴充套件“寵物”(需要一致處理和持久放置的應用程式)成為可能。

Datera 是一種用於雲部署的彈性塊儲存,透過 FlexVolume 框架與 Kubernetes 無縫整合。基於容器的第一原則,Datera 允許應用程式資源置備與底層物理基礎設施解耦。這帶來了清晰的契約(即,不依賴或直接瞭解底層物理基礎設施)、宣告性格式,並最終為有狀態應用程式帶來了可移植性。

雖然 Kubernetes 允許透過 yaml 配置靈活地定義底層應用程式基礎設施,但 Datera 允許將該配置傳遞給儲存基礎設施以提供永續性。透過 Datera AppTemplates 的概念,在 Kubernetes 環境中,有狀態應用程式可以實現自動化擴充套件。

部署持久儲存

持久儲存使用 Kubernetes PersistentVolume 子系統進行定義。PersistentVolumes 是卷外掛,定義了獨立於使用它的 Pod 生命週期存在的卷。它們以 NFS、iSCSI 或雲提供商特定的儲存系統實現。Datera 開發了一個用於 PersistentVolumes 的卷外掛,可以在 Datera Data Fabric 上為 Kubernetes Pod 置備 iSCSI 塊儲存。

Datera 卷外掛由 minion 節點上的 kubelet 呼叫,並透過其 REST API 將呼叫轉發到 Datera Data Fabric。下面是一個使用 Datera 外掛部署 PersistentVolume 的示例

 apiVersion: v1

 kind: PersistentVolume

 metadata:

   name: pv-datera-0

 spec:

   capacity:

     storage: 100Gi

   accessModes:

     - ReadWriteOnce

   persistentVolumeReclaimPolicy: Retain

   flexVolume:

     driver: "datera/iscsi"

     fsType: "xfs"

     options:

       volumeID: "kube-pv-datera-0"

       size: “100"

       replica: "3"

       backstoreServer: "[tlx170.tlx.daterainc.com](http://tlx170.tlx.daterainc.com/):7717”

此清單定義了一個 100 GB 的 PersistentVolume,用於在 Datera Data Fabric 中進行置備,以防 Pod 請求持久儲存。

[root@tlx241 /]# kubectl get pv

NAME          CAPACITY   ACCESSMODES   STATUS      CLAIM     REASON    AGE

pv-datera-0   100Gi        RWO         Available                       8s

pv-datera-1   100Gi        RWO         Available                       2s

pv-datera-2   100Gi        RWO         Available                       7s

pv-datera-3   100Gi        RWO         Available                       4s

配置

Datera PersistenceVolume 外掛安裝在所有 minion 節點上。當一個 Pod 落在 minion 節點上,並有一個繫結到先前置備的持久儲存的有效宣告時,Datera 外掛會將請求轉發到 Datera Data Fabric 上建立卷。PersistentVolume 清單中指定的所有選項都會在置備請求時傳送到外掛。

一旦在 Datera Data Fabric 中置備了卷,卷就會作為 iSCSI 塊裝置呈現給 minion 節點,並且 kubelet 會掛載此裝置以供容器(在 Pod 中)訪問。

使用持久儲存

Kubernetes PersistentVolumes 與使用 PersistentVolume Claims 的 Pod 一起使用。一旦定義了宣告,它就會繫結到符合宣告規範的 PersistentVolume。上面定義的 PersistentVolume 的典型宣告如下所示:

kind: PersistentVolumeClaim

apiVersion: v1

metadata:

 name: pv-claim-test-petset-0

spec:

 accessModes:

   - ReadWriteOnce

 resources:

   requests:

     storage: 100Gi

當定義此宣告並將其繫結到 PersistentVolume 後,資源可以在 Pod 規範中使用

[root@tlx241 /]# kubectl get pv

NAME          CAPACITY   ACCESSMODES   STATUS      CLAIM                            REASON    AGE

pv-datera-0   100Gi      RWO           Bound       default/pv-claim-test-petset-0             6m

pv-datera-1   100Gi      RWO           Bound       default/pv-claim-test-petset-1             6m

pv-datera-2   100Gi      RWO           Available                                              7s

pv-datera-3   100Gi      RWO           Available                                              4s


[root@tlx241 /]# kubectl get pvc

NAME                     STATUS    VOLUME        CAPACITY   ACCESSMODES   AGE

pv-claim-test-petset-0   Bound     pv-datera-0   0                        3m

pv-claim-test-petset-1   Bound     pv-datera-1   0                        3m

Pod 可以像下面這樣使用 PersistentVolume Claim:

apiVersion: v1

kind: Pod

metadata:

 name: kube-pv-demo

spec:

 containers:

 - name: data-pv-demo

   image: nginx

   volumeMounts:

   - name: test-kube-pv1

     mountPath: /data

   ports:

   - containerPort: 80

 volumes:

 - name: test-kube-pv1

   persistentVolumeClaim:

     claimName: pv-claim-test-petset-0

結果是一個 Pod 使用 PersistentVolume Claim 作為卷。它反過來將請求傳送到 Datera 卷外掛,以在 Datera Data Fabric 中置備儲存。

[root@tlx241 /]# kubectl describe pods kube-pv-demo

Name:       kube-pv-demo

Namespace:  default

Node:       tlx243/172.19.1.243

Start Time: Sun, 14 Aug 2016 19:17:31 -0700

Labels:     \<none\>

Status:     Running

IP:         10.40.0.3

Controllers: \<none\>

Containers:

 data-pv-demo:

   Container ID: [docker://ae2a50c25e03143d0dd721cafdcc6543fac85a301531110e938a8e0433f74447](about:blank)

   Image:   nginx

   Image ID: [docker://sha256:0d409d33b27e47423b049f7f863faa08655a8c901749c2b25b93ca67d01a470d](about:blank)

   Port:    80/TCP

   State:   Running

     Started:  Sun, 14 Aug 2016 19:17:34 -0700

   Ready:   True

   Restart Count:  0

   Environment Variables:  \<none\>

Conditions:

 Type           Status

 Initialized    True

 Ready          True

 PodScheduled   True

Volumes:

 test-kube-pv1:

   Type:  PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)

   ClaimName:   pv-claim-test-petset-0

   ReadOnly:    false

 default-token-q3eva:

   Type:        Secret (a volume populated by a Secret)

   SecretName:  default-token-q3eva

   QoS Tier:  BestEffort

Events:

 FirstSeen LastSeen Count From SubobjectPath Type Reason Message

 --------- -------- ----- ---- ------------- -------- ------ -------

 43s 43s 1 {default-scheduler } Normal Scheduled Successfully assigned kube-pv-demo to tlx243

 42s 42s 1 {kubelet tlx243} spec.containers{data-pv-demo} Normal Pulling pulling image "nginx"

 40s 40s 1 {kubelet tlx243} spec.containers{data-pv-demo} Normal Pulled Successfully pulled image "nginx"

 40s 40s 1 {kubelet tlx243} spec.containers{data-pv-demo} Normal Created Created container with docker id ae2a50c25e03

 40s 40s 1 {kubelet tlx243} spec.containers{data-pv-demo} Normal Started Started container with docker id ae2a50c25e03

持久卷在 minion 節點(本例中為 tlx243)上顯示為 iSCSI 裝置

[root@tlx243 ~]# lsscsi

[0:2:0:0]    disk    SMC      SMC2208          3.24  /dev/sda

[11:0:0:0]   disk    DATERA   IBLOCK           4.0   /dev/sdb


[root@tlx243 datera~iscsi]# mount  ``` grep sdb

/dev/sdb on /var/lib/kubelet/pods/6b99bd2a-628e-11e6-8463-0cc47ab41442/volumes/datera~iscsi/pv-datera-0 type xfs (rw,relatime,attr2,inode64,noquota)

Pod 中執行的容器將此裝置掛載到清單中指定的 /data

[root@tlx241 /]# kubectl exec kube-pv-demo -c data-pv-demo -it bash

root@kube-pv-demo:/# mount  ``` grep data

/dev/sdb on /data type xfs (rw,relatime,attr2,inode64,noquota)

使用 Pet Sets

通常,Pod 被視為無狀態單元,因此如果其中一個不健康或被取代,Kubernetes 會直接將其處置。相比之下,PetSet 是一組有狀態的 Pod,它具有更強的身份概念。PetSet 的目標是透過為應用程式的單個例項分配不依賴於底層物理基礎設施的身份來解耦這種依賴關係。

PetSet 需要 {0..n-1} 個 Pet。每個 Pet 都有一個確定性名稱,PetSetName-Ordinal,和一個唯一的身份。每個 Pet 最多有一個 Pod,每個 PetSet 最多有一個具有給定身份的 Pet。PetSet 確保在任何給定時間都有指定數量的具有唯一身份的“寵物”在執行。Pet 的身份包括:

  • 穩定的主機名,可在 DNS 中訪問
  • 序數索引
  • 穩定儲存:連結到序數和主機名

使用 PersistentVolume Claim 的典型 PetSet 定義如下所示:

# A headless service to create DNS records

apiVersion: v1

kind: Service

metadata:

 name: test-service

 labels:

   app: nginx

spec:

 ports:

 - port: 80

   name: web

 clusterIP: None

 selector:

   app: nginx

---

apiVersion: apps/v1alpha1

kind: PetSet

metadata:

 name: test-petset

spec:

 serviceName: "test-service"

 replicas: 2

 template:

   metadata:

     labels:

       app: nginx

     annotations:

       [pod.alpha.kubernetes.io/initialized:](http://pod.alpha.kubernetes.io/initialized:) "true"

   spec:

     terminationGracePeriodSeconds: 0

     containers:

     - name: nginx

       image: [gcr.io/google\_containers/nginx-slim:0.8](http://gcr.io/google_containers/nginx-slim:0.8)

       ports:

       - containerPort: 80

         name: web

       volumeMounts:

       - name: pv-claim

         mountPath: /data

 volumeClaimTemplates:

 - metadata:

     name: pv-claim

     annotations:

       [volume.alpha.kubernetes.io/storage-class:](http://volume.alpha.kubernetes.io/storage-class:) anything

   spec:

     accessModes: ["ReadWriteOnce"]

     resources:

       requests:

         storage: 100Gi

我們有以下可用的 PersistentVolume Claims:

[root@tlx241 /]# kubectl get pvc

NAME                     STATUS    VOLUME        CAPACITY   ACCESSMODES   AGE

pv-claim-test-petset-0   Bound     pv-datera-0   0                        41m

pv-claim-test-petset-1   Bound     pv-datera-1   0                        41m

pv-claim-test-petset-2   Bound     pv-datera-2   0                        5s

pv-claim-test-petset-3   Bound     pv-datera-3   0                        2s

當置備此 PetSet 時,將例項化兩個 Pod:

[root@tlx241 /]# kubectl get pods

NAMESPACE     NAME                        READY     STATUS    RESTARTS   AGE

default       test-petset-0               1/1       Running   0          7s

default       test-petset-1               1/1       Running   0          3s

下面是前面例項化的 PetSet test-petset 的樣子:

[root@tlx241 /]# kubectl describe petset test-petset

Name: test-petset

Namespace: default

Image(s): [gcr.io/google\_containers/nginx-slim:0.8](http://gcr.io/google_containers/nginx-slim:0.8)

Selector: app=nginx

Labels: app=nginx

Replicas: 2 current / 2 desired

Annotations: \<none\>

CreationTimestamp: Sun, 14 Aug 2016 19:46:30 -0700

Pods Status: 2 Running / 0 Waiting / 0 Succeeded / 0 Failed

No volumes.

No events.

一旦例項化了一個 PetSet(如下面的 test-petset),當增加副本數量(即使用該 PetSet 啟動的 Pod 數量)時,會例項化更多的 Pod,並且更多的 PersistentVolume Claims 會繫結到新的 Pod:

[root@tlx241 /]# kubectl patch petset test-petset -p'{"spec":{"replicas":"3"}}'

"test-petset” patched


[root@tlx241 /]# kubectl describe petset test-petset

Name: test-petset

Namespace: default

Image(s): [gcr.io/google\_containers/nginx-slim:0.8](http://gcr.io/google_containers/nginx-slim:0.8)

Selector: app=nginx

Labels: app=nginx

Replicas: 3 current / 3 desired

Annotations: \<none\>

CreationTimestamp: Sun, 14 Aug 2016 19:46:30 -0700

Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed

No volumes.

No events.


[root@tlx241 /]# kubectl get pods

NAME                        READY     STATUS    RESTARTS   AGE

test-petset-0               1/1       Running   0          29m

test-petset-1               1/1       Running   0          28m

test-petset-2               1/1       Running   0          9s

打補丁後,PetSet 現在執行 3 個 Pod。

當上述 PetSet 定義被修補以增加一個副本時,它會在系統中引入一個額外的 Pod。這反過來又會在 Datera Data Fabric 上置備一個額外的卷。因此,當 PetSet 擴充套件時,卷會動態置備並附加到 Pod。

為了支援永續性和一致性的概念,如果 Pod 從一個 minion 移動到另一個 minion,卷會附加(掛載)到新的 minion 節點,並從舊的 minion 分離(解除安裝),以保持對資料的持久訪問。

結論

這演示了 Kubernetes 如何使用 Pet Sets 編排有狀態和無狀態工作負載。雖然 Kubernetes 社群正在努力擴充套件 FlexVolume 框架的功能,但我們很高興這個解決方案使得 Kubernetes 能夠在資料中心中更廣泛地執行。

加入並貢獻:Kubernetes 儲存 SIG