网络存储卷

如前面所述,K8S拥有众多类型的用于适配专用存储系统的网络存储卷。这类存储卷包括传统的NAS或SAN设备(如NFS、iSCSI、fc)、分布式存储(如GlusterFS、RBD)、云端存储(如gceOersistenDisk、azureDisk、cinder和awsElasticBlockStore)以及建构在各类存储系统之上的抽象管理层(如flocker、portworxVolume和vsphereVolume)等

NFS存储卷

NFS即网络文件系统(Network File System),它是一种分布式文件系统协议,其功能主要是允许客户端主机可以像访问本地存储一样通过网络访问服务端文件。作为一种由内核原生支持的网络文件系统,具有Linux系统使用经验的人大多数都应该对NFS有一档的使用经验

K8S的NFS存储卷用于将某事先存在的NFS服务器上导出(export)的存储空间挂载到Pod中以供容器使用。与exmptyDir不同的是,NFS存储卷在Pod对象终止后仅是被卸载而非删除。另外,NFS是文件系统级共享服务,它支持同时存在的多路挂载请求。在使用NFS存储卷之前,必须提前运行自己的NFS服务器,并且需要将事先存在的存储空间导出备用。定义NFS存储卷时,常用到以下字段

  • .spec.volumes.nfs.path <string>:NFS服务器导出的文件系统路径,必须字段
  • .spec.volumes.nfs.server <string>:NFS服务器的IP地址或主机名,必选字段
  • .spec.volumes.nfs.readOnly <boolean>:是否以只读方式挂载,默认为false

以redis为例,Redis是一个著名的高性能k/v存储系统,应用非常广发,将其部署运行于K8S系统之上时,需要持久化存储卷的支持。下面是简单使用redis的一个示例

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: redis
  5. spec:
  6. replicas: 2
  7. selector:
  8. matchLabels:
  9. app: redis-nfs
  10. template:
  11. metadata:
  12. labels:
  13. app: redis-nfs
  14. spec:
  15. containers:
  16. - name: redis
  17. image: docker.io/redis:6.0.5-alpine
  18. ports:
  19. - containerPort: 6379
  20. name: redisport
  21. volumeMounts:
  22. - name: redisdata
  23. mountPath: /data
  24. volumes:
  25. - name: redisdata
  26. nfs:
  27. server: nfs.ilinux.io
  28. path: /data/redis
  29. readOnly: false

上面的示例中,Pod资源拥有一个关联至NFS服务器nfs.ilinux.io的存储卷,存储卷名称为redisdata,redis容器将其挂载于/data目录上,它是运行于容器中的redis-server数据的持久保存位置

提示:这里应该确保实现要存在一个名为nfs.ilinux.io的NFS服务器,并且输出了/data/redis目录,并且授权给了K8S集群中的节点访问。主机名和目录都可以按需进行调整。并且Pod中的容器需要能够访问到该NFS服务端

上述信息都完成后,便可使用kubectl apply创建Pod资源

  1. [root@k8s-master01 emptydir]# kubectl apply -f redis-nfs.yaml
  2. deployment.apps/redis created
  3. [root@k8s-master01 emptydir]#

资源创建完成后,可通过其命令客户端redis-cli创建测试数据,并手动出发其同步于存储系统中

  1. [root@k8s-master01 emptydir]# kubectl get pods -l "app=redis-nfs"
  2. NAME READY STATUS RESTARTS AGE
  3. redis-6489cd7b44-7qgn2 1/1 Running 0 3m56s
  4. [root@k8s-master01 emptydir]# kubectl exec -ti redis-6489cd7b44-7qgn2 redis-cli
  5. 127.0.0.1:6379> get key
  6. (nil)
  7. 127.0.0.1:6379>
  8. 127.0.0.1:6379> set mykey "hello nfs.ilinux.io"
  9. OK
  10. 127.0.0.1:6379>
  11. 127.0.0.1:6379> get mykey
  12. "hello nfs.ilinux.io"
  13. 127.0.0.1:6379>
  14. 127.0.0.1:6379> BGSAVE
  15. Background saving started
  16. 127.0.0.1:6379> exit
  17. [root@k8s-master01 emptydir]#

为了测试其数据持久化效果,我们将该redis的Pod资源删除,并再次进行重建,然后查看数据是否有效

  1. [root@k8s-master01 emptydir]# kubectl delete -f redis-nfs.yaml
  2. deployment.apps "redis" deleted
  3. [root@k8s-master01 emptydir]#
  4. [root@k8s-master01 emptydir]# kubectl get pods -l "app=redis-nfs"
  5. No resources found in default namespace.
  6. [root@k8s-master01 emptydir]#
  7. [root@k8s-master01 emptydir]# kubectl apply -f redis-nfs.yaml
  8. deployment.apps/redis created
  9. [root@k8s-master01 emptydir]#
  10. [root@k8s-master01 emptydir]# kubectl get pods -l "app=redis-nfs"
  11. NAME READY STATUS RESTARTS AGE
  12. redis-6489cd7b44-d5s5p 1/1 Running 0 16s
  13. [root@k8s-master01 emptydir]#
  14. [root@k8s-master01 emptydir]# kubectl exec -ti redis-6489cd7b44-d5s5p redis-cli
  15. 127.0.0.1:6379> get mykey
  16. "hello nfs.ilinux.io"
  17. 127.0.0.1:6379>

从上面的命令结果中可以看出,此前创建的mykey及其数据在Pod资源重建后依然存在,这表明在删除Pod资源时,其关联的外部存储卷并不会被一并删除。并且NFS存储卷可以被预先填充数据,并且这些数据可以在Pod之间传递。如果需要清楚此类的数据,需要用户通过存储系统的管理接口手动进行

RBD存储卷

Ceph是一个专注于分布式的、弹性可扩展的、高可靠的、性能优异的分布式存储系统平台,同时支持提供块设备、文件系统和REST三种存储接口。它是一个高度可配置的系统,并提供了一个命令行界面用于监视和控制其存储集群。Ceph还包含鉴证和授权功能,可兼容多种存储网关接口,如openstack swift和Amazon S3。K8S也支持通过RBD类型的存储卷使用ceph存储系统为Pod提供存储卷。要配置Pod资源使用RBD存储,需要实现满足如下几个前提条件

  • 存在某可用的Ceph RBD存储集群,如果没有则需要创建一个
  • 在Ceph RBD集群中创建一个能满足Pod资源数据存储需要的存储映像(image)
  • 在K8S集群内的各节点上按照Ceph客户端程序包(ceph-common)

在配置RBD类型的存储卷时,需要指定要连接的目标服务器和认证信息等,这一点通常使用如下嵌套字段进行定义

  • .spec.volumes.rbd.monitors <[]string>: Ceph存储监视器,逗号分隔的字符串列表,必选字段
  • .spec.volumes.rbd.image <string>: rados image的名称,必选字段
  • .spec.volumes.rbd.poll <string>: rados存储池名称,默认为RBD
  • .spec.volumes.rbd.user <string>: rados用户名,默认为admin
  • .spec.volumes.rbd.keyring <string>: RBD用户认证时使用的keyring文件路径,默认为/etc/ceph/keyring
  • .spec.volumes.rbd.secretRef <Object>:RBD用户认证时使用的保存有相应认证信息的Secret对象,会覆盖由keyring字段提供的密钥信息
  • .spec.volumes.rbd.readOnly <boolean>: 是否以只读的方式进行访问
  • .spec.volumes.rbd.fstype: 要挂载的存储卷的文件系统类型,至少应该是节点操作系统支持的文件系统类型,如ext4、ext3、xfs、ntfs,默认为ext4

RDB类型的存储卷不会像emptyDir类型的存储卷那样在Pod被删除的同时也会被删除,RDB存储卷的内容在Pod删除后依旧会被保存,只是存储卷被卸载了。并且rdb存储卷可以预先填充数据,这些数据可以在各个Pod之间共享,当然,前提条件是各个Pod所挂载的是同一个路径的存储卷

下面是一个定义在vol-rdb.yaml配置文件中私用RDB类型的存储卷的示例

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: vol-rbd
  5. spec:
  6. replicas: 2
  7. selector:
  8. matchLabels:
  9. app: redis-rbd
  10. template:
  11. metadata:
  12. labels:
  13. app: redis-rbd
  14. spec:
  15. dnsPolicy: ClusterFirstWithHostNet
  16. containers:
  17. #定义第一个容器为redis
  18. - name: redis-rbd
  19. image: docker.io/redis:6.0.5-alpine
  20. ports:
  21. - containerPort: 80
  22. name: redisport
  23. volumeMounts:
  24. - name: redis-rdb
  25. mounPath: /data
  26. volumes:
  27. - name: redis-rdb
  28. rdb:
  29. monitors:
  30. - '172.18.15.116:6789'
  31. - '172.18.15.114:6789'
  32. - '172.18.15.113:6789'
  33. pool: kube
  34. imgae: redis
  35. fsType: ext4
  36. readOnly: false
  37. user: admin
  38. secretRef:
  39. name: ceph-secret

此示例需要依赖于事先存在的一个ceph存储集群,这里假设其监视器的地址为172.18.15.116、172.18.15.114、172.18.15.113这三台主机,并且集群上的存储池kube中也存在创建好的映像redis,此映像拥有ext4文件系统。Ceph客户端访问集群时需要事先完成认证之后才能进行后续的访问操作,此示例上,其认证信息保存于名为ceph-secret的Secret资源对象中。示例所事先的逻辑架构图如下 存储卷与数据持久化(三)之网络存储卷 - 图1

小提示: 此配置示例依赖于一个可用的ceph集群,且上述配置示例中的部分参数需要参照实际环境进行修改

注意:RDB的一个特点是它可以同时被多个用户以只读方式挂载,这意味着我们可以先用数据集预先填充存储卷,然后根据需要从尽可能多的Pod中并行的提供存储卷。不幸的是,RDB存储卷只能由单个使用者以读写模式按照,不允许同时写入。所以如果存在Ceph存储集群推荐还是直接使用cephFS类型的存储卷

GlusterFS存储卷

GlusterFS(Gluster File System)是一个开源的分布式文件系统,是水平扩展存储解决方案Gluster的核心,具有强大的横向扩展能力,GlusterFS通过扩展能够支持数PB存储容量和处理数千客户端。GlusterFS借助TCP/IP或InfiniBand RDMA网络将物理分布的存储资源聚集在一起,使用单一全局命名空间来管理数据。另外GlusterFS基于可堆叠的用户空间设计,可为各种不同的数据负载提供优异的性能,是另一种流行的分布式存储解决方案。

要配置Pod资源使用GlusterFS存储卷,需要事先满足以下条件

  • 存在某可用的GlusterFS存储集群,否则就要创建一个
  • 在GlustrFS集群中创建一个能满足Pod资源数据存储需要的卷
  • 在K8S集群内的各节点上按照GlusterFS客户端程序包(glusterfs和glusterfs-fuse)
    另外,若要基于GlusterFS使用存储卷的动态供给机制,还需要事先部署heketi,它用于为GlusterFS集群提供RESTful风格的管理接口。关于GlusterFS和heketi的部署后面会写

定义Pod资源使用GlusterFS类型的存储卷时,常用的配置字段包含如下几个

  • .spec.volumes.glusterfs.endpoints <string>: endpoints资源的名称,此资源需要事先存在,用于提供Gluster集群的部分节点信息作为其访问入口。必选字段
  • .spec.volumes.glusterfs.path <string>:用到的GlusterFS存储集群的卷路径,如kube-redis,必选字段
  • .spec.volumes.glusterfs.readOnly <boolean>:是否为只读卷

用于访问Gluster集群的相关节点信息需要事先保存于某特定的Endpoints资源中。此类的Endponits资源可由用户根据实际需求手动创建。例如,下面的保存于gluserfs-endpoints.yaml文件中的资源示例中定义了三个接入相关的Gluster存储集群的节点gfs01.ilinux.io、gfs02.ilinux.io和gfs03.ilinux.io,其中的端口信息仅为满足endpoints资源的必须字段的要求,因此其值可随意填写

  1. apiVersion: v1
  2. kind: Endpoints
  3. metadata:
  4. name: glusterfs-endpoints
  5. subsets:
  6. - addresses:
  7. - ip: gfs01.ilinux.io
  8. ports:
  9. - port: 6789
  10. name: glusterd
  11. - addresses:
  12. - ip: gfs02.ilinux.io
  13. potrs:
  14. - port: 6789
  15. name: glusterd
  16. - addresses:
  17. - ip: gfs03.ilinux.io
  18. ports:
  19. - port: 6789
  20. name: glusterd

下面是一个定义在vol-redis-glusterfs.yaml配置文件中的Pod资源示例,它使用了GlusterFS存储卷持久保存应用数据。它通过glusterfs-endpoints资源中定义的GlusterFS集群信息接入集群,并以kube-redis卷作为Pod资源的存储卷。glusterfs-endpoints资源需要在kK8S集群中事先创建,而kube-redis则需要事先创建于GlusterFS集群

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: vol-redis-glusterfs
  5. spec:
  6. replicas: 1
  7. selector:
  8. matchLabels:
  9. app: redis-gluster
  10. template:
  11. metadata:
  12. labels:
  13. app: redis-gluster
  14. spec:
  15. dnsPolicy: ClusterFirstWithHostNet
  16. containers:
  17. #定义第一个容器为redis
  18. - name: redis-gluster
  19. image: docker.io/redis:6.0.5-alpine
  20. ports:
  21. - containerPort: 80
  22. name: redisport
  23. volumeMounts:
  24. - name: redis-gluster
  25. mounPath: /data
  26. volumes:
  27. - name: redis-glusterfs
  28. glusterfs:
  29. endpoints: glusterfs-endpoints
  30. path: kube-redis
  31. readOnly: false

执行步骤就是首先需要创建endpoints资源gluserfs-endpoints.yaml,而后再创建Pod资源vol-redis-glusterfs.yaml GlusterFS可以被同时写入

Cinder存储卷

Cinder是Openstack Block Storage的项目名称,用来为虚拟机(VM)实例提供持久块存储。Cinder通过驱动器架构支持多种后端(back-end)存储方式,包括LVM,NFS,Ceph和其他诸如EMC,IBM等商业存储产品和方案,其提供了调用度来调度卷创建的请求,能合理优化存储资源的分配,而且还拥有REST API。将K8S集群部署于Openstack构建的IAAS环境中时,cinder的块存储功能可为Pod资源提供外部持久存储的有效方式

在Pod资源上定义使用Cinder存储卷时,其可用的嵌套字段包含如下几个

  • .spec.volumes.cinder.volumeID <string>:用于标识Cinder中的存储卷的卷标识符,必选字段
  • .spec.volumes.cinder.secretRef <Object>:用户认证时使用的保存有相应认证信息的Secret对象
  • .spec.volumes.cinder.readOnly <boolean>:是否以只读方式访问
  • .spec.volumes.cinder.fsType <string>:要挂载的存储卷的文件系统类型,至少应该是节点操作系统支持的文件系统,如ext4、xfs、ntfs等,默认为ext4
    下面的资源清单是定义在vol-cinder.yaml文件中的使用示例,假设在openstack环境中有创建好的cinder卷”xxxxx-xxxx-xxxxx-xxxxx-xxxxxx”可用
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: vol-redis-cinder
  5. spec:
  6. replicas: 1
  7. selector:
  8. matchLabels:
  9. app: redis-cinder
  10. template:
  11. metadata:
  12. labels:
  13. app: redis-cinder
  14. spec:
  15. dnsPolicy: ClusterFirstWithHostNet
  16. containers:
  17. #定义第一个容器为redis
  18. - name: redis-cinder
  19. image: docker.io/redis:6.0.5-alpine
  20. ports:
  21. - containerPort: 80
  22. name: redisport
  23. volumeMounts:
  24. - name: redis-cinder
  25. mounPath: /data
  26. volumes:
  27. - name: redis-cinder
  28. cinder:
  29. volumeID: xxxxx-xxxx-xxxxx-xxxxx-xxxxxx
  30. fsType: ext4

配置可用的系统环境和存储资源时,将其匹配于资源清单文件中即可完成Pod资源创建。另外K8S所支持的各类持久存储卷其配置使用方式各不相同。这里不再一一举例