使用带有Datera Elastic Data Fabric的Kubernetes 宠物套装和FlexVolumes扩展有状态应用程序

编者注:今天的嘉宾帖子是Datera Inc.的软件架构师Shailesh Mittal和高级产品总监Ashok Rajagopalan,谈到Kubernetes在Datera Elastic Data Fabric上的有状态应用程序配置。

介绍

随着客户超越无状态工作负载运行有状态应用程序,Kubernetes中的持久卷是基础。尽管Kubernetes一段时间以来一直支持有状态的应用程序,例如MySQL,Kafka,Cassandra和Couchbase,但Pet Sets的引入极大地改善了这种支持。特别是,对供应和启动进行排序的过程,通过以下方式持久地扩展和关联的能力 宠物套装 提供了自动缩放“宠物”(需要一致处理和持久放置的应用程序)的功能。

Datera是用于云部署的弹性块存储,具有 与Kubernetes无缝集成 通过 FlexVolume 框架。基于容器的首要原则,Datera允许将应用程序资源供应与底层物理基础架构分离。这带来了干净的合同(又称,没有对基础物理基础结构的依赖性或直接知识),声明性格式,并最终将其移植到有状态的应用程序。

虽然Kubernetes允许通过yaml配置来定义基础应用程序基础结构,但它具有极大的灵活性,但Datera允许将该配置传递给存储基础结构以提供持久性。通过Datera AppTemplates的概念,在Kubernetes环境中,有状态的应用程序可以自动扩展。

部署永久性存储

持久存储是使用Kubernetes定义的 持续量 子系统。 持续量是卷插件,用于定义独立于使用它的Pod生命周期生存的卷。它们被实现为NFS,iSCSI或云提供商特定的存储系统。 Datera开发了用于PersistentVolumes的卷插件,可以在Datera数据结构上为Kubernetes容器配置iSCSI块存储。

Datera卷插件由小仆节点上的kubelet调用,并通过其REST API将调用中继到Datera数据结构。以下是带有Datera插件的PersistentVolume的部署示例:

 apiVersion: v1

 kind: 持续量

 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”

如果Pod请求持久存储,则此清单定义在Datera数据结构中预配置的100 GB 持续量。

[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节点上。当吊舱降落在具有有效声明的小仆节点上时,该声明绑定到先前设置的持久性存储,则Datera插件会转发请求以在Datera数据结构上创建卷。根据配置请求,PersistentVolume清单中指定的所有选项都将发送到插件。

在Datera数据结构中配置卷后,会将卷作为iSCSI块设备显示给minion节点,并且kubelet将该设备安装在容器中(容器中)以访问它。

使用永久性存储

Kubernetes 持续量s与使用PersistentVolume Claims的Pod一起使用。定义声明后,它将绑定到与声明规范匹配的PersistentVolume。上面定义的PersistentVolume的典型声明如下所示:

kind: 持续量Claim

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

吊舱可以使用PersistentVolume声明,如下所示:

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

结果是使用PersistentVolume Claim作为体积的容器。依次将请求发送到Datera卷插件以在Datera数据结构中置备存储。

[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:  持续量Claim (a reference to a 持续量Claim 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)

使用宠物套装

通常,吊舱被视为无状态单元,因此,如果其中之一不健康或被取代,Kubernetes会将其丢弃。相反,PetSet是一组有状态的Pod,具有更强的身份概念。 PetSet的目标是通过将标识分配给未锚定在基础物理基础结构上的应用程序的各个实例来消除这种依赖性。

PetSet需要{0..n-1}个Pet。每个Pet都有一个确定性名称PetSetName-Ordinal和一个唯一标识。每个宠物最多具有一个吊舱,每个宠物集最多具有一个具有给定身份的宠物。 PetSet确保在任何给定时间运行指定数量的具有唯一标识的“ pet”。宠物的身份包括:

  • 一个稳定的主机名,可在DNS中使用
  • 序数索引
  • 稳定的存储:链接到序数和主机名

使用PersistentVolume声明的典型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.sjzrbxc.cn/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.sjzrbxc.cn/storage-class:) anything

   spec:

     accessModes: ["ReadWriteOnce"]

     resources:

       requests:

         storage: 100Gi

我们提供以下PersistentVolume声明:

[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测试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数据结构上配置了更多的卷。因此,在PetSet扩大规模时,将动态配置卷并将其附加到Pod。

为了支持持久性和一致性的概念,如果Pod从一个Minion移到另一个Mind,则卷确实会附加(安装)到新Minion节点,并从旧Minion分离(卸载)以保持对数据的持久访问。

结论

这演示了带有Pet Sets的Kubernetes编排有状态和无状态工作负载。当Kubernetes社区正在努力扩展FlexVolume框架的功能时,我们很高兴该解决方案使Kubernetes能够在数据中心中更广泛地运行。

加入并贡献:Kubernetes 储存SIG.