這篇文章已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
使用 Kubernetes Pet Sets 和 Datera Elastic Data Fabric 的 FlexVolumes 擴展有狀態應用程式
簡介
Kubernetes 中的持久卷是基礎,因為客戶從無狀態工作負載轉向執行有狀態應用程式。雖然 Kubernetes 一直以來都支援 MySQL、Kafka、Cassandra 和 Couchbase 等有狀態應用程式,但 Pet Sets 的引入顯著改善了這種支援。特別是,排序佈建和啟動程序的步驟,以及透過 Pet Sets 擴展和持久關聯的能力,提供了自動擴展「寵物」(需要一致處理和持久放置的應用程式) 的能力。
Datera 是用於雲端部署的彈性區塊儲存,已透過 FlexVolume 框架與 Kubernetes 無縫整合。基於容器的首要原則,Datera 允許應用程式資源佈建與底層實體基礎架構解耦。這為有狀態應用程式帶來了清晰的契約(又名,不依賴或直接了解底層實體基礎架構)、宣告式格式,以及最終的可攜性。
雖然 Kubernetes 允許透過 yaml 組態高度彈性地定義底層應用程式基礎架構,但 Datera 允許將該組態傳遞到儲存基礎架構以提供持久性。透過 Datera AppTemplates 的概念,在 Kubernetes 環境中,有狀態應用程式可以自動擴展。
部署持久儲存
持久儲存是使用 Kubernetes PersistentVolume 子系統定義的。PersistentVolume 是卷外掛程式,用於定義獨立於使用它的 Pod 生命週期的卷。它們實作為 NFS、iSCSI 或雲端供應商特定的儲存系統。Datera 為 PersistentVolume 開發了一個卷外掛程式,可以在 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”
此 manifest 定義了一個 100 GB 的 PersistentVolume,如果 Pod 請求持久儲存,則在 Datera Data Fabric 中佈建。
[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 manifest 中指定的所有選項都會在佈建請求時傳送給外掛程式。
一旦在 Datera Data Fabric 中佈建卷,卷就會作為 iSCSI 區塊裝置呈現給 minion 節點,而 kubelet 會掛載此裝置,供容器(在 Pod 中)存取。
使用持久儲存
Kubernetes PersistentVolume 與使用 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 中執行的容器會看到此裝置掛載在 manifest 中指定的 /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 被視為無狀態單元,因此如果其中一個 Pod 不健康或被取代,Kubernetes 只會處置它。相反地,PetSet 是一組有狀態的 Pod,它具有更強烈的身分概念。PetSet 的目標是透過為應用程式的個別執行個體分配身分來解耦此依賴關係,這些身分不錨定於底層實體基礎架構。
PetSet 需要 {0..n-1} 個寵物 (Pets)。每個寵物都有一個確定的名稱 PetSetName-Ordinal 和一個唯一的身分。每個寵物最多有一個 Pod,每個 PetSet 最多有一個具有給定身分的寵物。PetSet 確保在任何給定時間都有指定數量的具有唯一身分的「寵物」正在執行。寵物的身分由以下組成
- 穩定的主機名稱,在 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 Storage SIG。
- 下載 Kubernetes
- 在 GitHub 上參與 Kubernetes 專案
- 在 Stack Overflow 上發布問題(或回答問題)
- 在 k8s Slack 上與社群聯繫
- 在 Twitter 上關注我們 @Kubernetesio 以取得最新更新