本文超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
使用 Kubernetes Pet Sets 和 FlexVolumes 以及 Datera Elastic Data Fabric 扩展状态应用程序
简介
随着客户从无状态工作负载转向运行有状态应用程序,Kubernetes 中的持久卷至关重要。虽然 Kubernetes 已经支持诸如 MySQL、Kafka、Cassandra 和 Couchbase 之类的有状态应用程序有一段时间了,但 Pet Sets 的引入显着改善了这种支持。特别是,排序配置和启动的程序、通过 Pet Sets 进行扩展和持久关联的能力,提供了自动扩展“Pets”(需要一致处理和持久放置的应用程序)的能力。
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 卷插件由从属节点上的 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,如果 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 插件安装在所有从属节点上。当 pod 落在具有绑定到先前配置的持久存储的有效声明的从属节点上时,Datera 插件会转发请求以在 Datera Data Fabric 上创建卷。PersistentVolume 清单中指定的所有选项在配置请求时都会发送到插件。
在 Datera Data Fabric 中配置卷后,卷将作为 iSCSI 块设备呈现给从属节点,并且 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
持久卷在从属节点(本例中为 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} 个 Pets。每个 Pet 都有一个确定的名称,PetSetName-Ordinal,以及一个唯一的身份。每个 Pet 最多有一个 pod,每个 PetSet 最多有一个具有给定身份的 Pet。PetSet 确保在任何给定时间运行指定数量的具有唯一身份的“pets”。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 从一个从属节点移动到另一个从属节点,卷会附加(挂载)到新的从属节点并从旧的从属节点分离(卸载),以保持对数据的持久访问。
结论
这演示了 Kubernetes 与 Pet Sets 协调有状态和无状态工作负载。虽然 Kubernetes 社区正在努力扩展 FlexVolume 框架的功能,但我们很高兴此解决方案使 Kubernetes 能够在数据中心中更广泛地运行。
加入并贡献:Kubernetes 存储 SIG。
- 下载 Kubernetes
- 在 GitHub 上参与 Kubernetes 项目
- 在 Stack Overflow 上发布问题(或回答问题)
- 在 k8s Slack 上与社区联系
- 在 Twitter 上关注我们 @Kubernetesio 获取最新更新