本文超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。

使用 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