如何在Kubernetes pod之间共享存储空间?

时间:2015-07-29 07:08:31

标签: docker google-cloud-platform kubernetes

我正在评估Kubernetes作为我们新应用程序的平台。现在,它看起来非常令人兴奋!但是,我遇到了一个问题:我在GCE上托管我的集群,我需要一些机制来在两个pod之间共享存储 - 连续集成服务器和我的应用服务器。使用kubernetes这样做的最佳方法是什么?没有任何卷类型似乎符合我的需要,因为如果一个pod需要写入磁盘,则无法共享GCE磁盘。 NFS会很完美,但似乎需要为kubernetes集群提供特殊的构建选项吗?

编辑:共享存储似乎是我现在使用Kubernetes多次遇到的问题。有多个用例,我只想拥有一个卷并将其连接到多个pod(具有写访问权限)。我只能假设这是一个常见的用例,不是吗?

EDIT2:例如,this page描述了如何设置Elasticsearch集群,但是使用持久存储将其连接起来是不可能的(as described here),这使得它毫无意义:(

10 个答案:

答案 0 :(得分:25)

回答这个问题有点迟,但根据我迄今为止Kubernetes / MSA的经验,这里的问题更多的是你的设计模式。在MSA中经常出现的基本设计模式之一是适当封装您的服务,其中还包括其数据。

您的服务应该关注与其关注领域相关的数据,并且与OOP非常相似,应允许通过接口(API,PUBSUB消息等)访问此数据到其他服务。对数据的多服务访问是一种类似于OOP中的全局变量的反模式。

我认为Google也有同样的观点,这就是Kubernetes以这种方式建立的原因。

例如,如果您希望编写日志,那么您应该拥有一个日志服务,每个服务都可以使用它需要记录的相关数据来调用。直接写入共享磁盘意味着如果您更改了日志目录结构等,或者决定在错误上添加电子邮件等额外功能,则需要更新每个容器。

答案 1 :(得分:21)

NFS是一个内置的卷插件,支持多个pod编写器。没有特殊的构建选项可以让NFS在Kube中运行。

我在Kubernetes的Red Hat工作,主要专注于存储。

答案 2 :(得分:4)

要在多个Pod之间共享卷,您需要创建具有访问模式ReadWriteMany的PVC

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
    name: my-pvc
spec:
    accessModes:
      - ReadWriteMany
    storageClassName: myvolume
    resources:
        requests:
            storage: 1Gi

之后,您可以将其安装到多个Pod:

apiVersion: v1
kind: Pod
metadata:
  name: myapp1
spec:
  containers:
...
      volumeMounts:
        - mountPath: /data
          name: data
          subPath: app1
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: 'my-pvc'
---
apiVersion: v1
kind: Pod
metadata:
  name: myapp2
spec:
  containers:
...
      volumeMounts:
        - mountPath: /data
          name: data
          subPath: app2
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: 'my-pvc'

当然,持久卷必须可以通过网络访问。否则,您需要确保将所有Pod调度到具有该卷的节点。

有几种适合于此的卷类型,它们与任何云提供商无关:

  • NFS
  • RBD(Ceph块设备)
  • CephFS
  • Glusterfs
  • Portworx卷

当然,要使用一个卷,您需要首先拥有它。也就是说,如果要使用NFS,则需要在K8s群集中的所有节点上设置NFS。如果要使用Ceph,则需要设置Ceph集群等等。

开箱即用的唯一支持Kubernetes的卷类型是Portworks。 how to set it up in GKE上有说明。

要在K8s中设置Ceph集群,有一个名为Rook的开发项目。

但是,如果您只想使一个节点中的文件夹在另一个节点中可用,那么这太过分了。在这种情况下,只需设置NFS服务器。这不会比配置其他卷类型更难,并且将消耗更少的cpu /内存/磁盘资源。

答案 3 :(得分:3)

更新:最佳选择可能是Cloud Filestore,一个托管NFS系统。这使您可以对文件进行完全随机的读/写访问,这与仅支持上载/下载的GCS不同。请参阅文档here

原件: 你试过Google Cloud Storage吗?您甚至可以使用FUSE adapter将其映射为网络磁盘。

答案 4 :(得分:3)

如果是您要写入磁盘的日志,我建议您查看logspout https://github.com/gliderlabs/logspout。这将收集每个pod的日志记录,然后您可以使用谷歌云平台的相当新的使用流利的日志服务。这样,每个pod的所有日志都会收集到一个地方。

如果是通常写入数据库的数据或具有此类性质的数据,我建议在运行数据库的kubernetes集群之外使用单独的服务器。

修改

为了在pod之间共享文件,我建议将一个google云存储驱动器安装到kubernetes群集中的每个节点,然后将其设置为一个卷,将其设置到安装到节点上上的每个pod中而不是直接驱动器。将它安装到每个节点是好的,因为pod不在指定的节点上运行,所以最好在这种情况下集中它。

答案 5 :(得分:2)

你看过kubernetes Volumes了吗?您可能正在考虑创建一个gcePersistentDisk

  

gcePersistentDisk卷安装Google Compute Engine(GCE)   永久磁盘进入您的pod。与emptyDir不同,当被删除时   移除Pod,保留PD的内容并且音量为   只是没有安装。这意味着PD可以预先填充数据,   并且该数据可以在pod之间“切换”。重要提示:你必须   使用gcloud或GCE API或UI创建PD,然后才能使用它   使用gcePersistentDisk时存在一些限制:节点   正在运行哪个pod必须是那些VM需要在其中的GCE VM   与PD相同的GCE项目和区域PD的特征是它们可以   由多个消费者同时以只读方式安装。这个   意味着您可以使用数据集预填充PD,然后提供服务   它可以根据您的需要与多个豆荚平行。不幸的是,PD可以   只能由一个消费者以读写模式安装 - 没有   允许同时作家。在由a控制的pod上使用PD   除非PD是只读的,否则ReplicationController将失败   副本计数为0或1。

为了支持来自各种pod的多次写入,您可能需要创建一个强大的pod,它暴露了一个thrift或socket类型的服务,它暴露了readFromDisk和WriteToDisk方法。

答案 6 :(得分:2)

Google最近发布了云文件存储,其教程在此处:https://cloud.google.com/filestore/docs/accessing-fileshares

在某些情况下,它可能是云存储/存储桶的不错选择。

答案 7 :(得分:1)

头盔: 如果您使用头盔进行部署

如果您有一个仅支持RWO的PVC,并且希望许多Pod能够从同一PVC读取并共享该存储,那么如果您的云提供商不支持,则可以安装Helm Chart stable/nfs-server-provisioner RWX访问模式。

此图表提供了具有RWX访问模式的“树外”存储PVC,该存储PVC从仅支持RWO的云提供商(例如Digital Ocean)访问基础PVC。

在您的Pod中,您可以挂载nfs服务器配置的PVC,并且可以在它们从同一PVC读写时对其进行缩放。

重要!

您必须修改values文件以添加适合您的部署的配置,例如storage class

有关图表的更多信息: https://github.com/helm/charts/tree/master/stable/nfs-server-provisioner

答案 8 :(得分:0)

@Marco - 关于Maven相关问题,我的建议是停止将其视为集中存储问题,并将其视为服务问题。

我过去在HTTP下运行Maven存储库(只读)。我只需创建一个Maven仓库,然后通过Apache / Nginx在自己的pod(docker容器)中展示它,只需要那个pod所需的专用存储,然后使用服务发现将它链接到您的应用程序和构建系统。

答案 9 :(得分:0)

我只是用一个由3个容器化微服务组成的应用程序实现了这一点,我其中一个负责存储和共享文件,因此该应用程序将文件存储并检索到一个文件夹中,该文件夹通过应用程序属性。有一个安全的休息入口点,它允许提交和检索文件(基本上在每次提交时,它都会创建一个唯一的ID,该ID将返回并可以用来扫描文件夹中的文件)。 将这个应用程序从docker-compose传递到kubernetes时,我遇到了同样的问题:我需要一个全局磁盘,以便可以有多个容器副本,因此当其他微服务将请求发送到其中一个副本时,它们将始终能够发送任何提交的文件,而不仅仅是发送时管理的副本文件。 我通过创建与持续批量声明相关联的持久卷解决了该问题,该批量声明与部署相关联(注意:不是Statefulset ,它将为每个Pod创建一个磁盘),此时,您必须将已安装的卷路径与容器存储文件夹路径相关联。

因此重要的是永久卷声明名称以及PV具有更多可用PVC内存的事实,并且显然与具有正确标签的部署相匹配。 然后在部署中,您可以传递规范:

volumes:
      - name: store-folder
        persistentVolumeClaim:
          claimName: [pvc_name]

进入容器设置:

volumeMounts:
        - name: store-folder
          mountPath: "/stored-files"

和在env。阻止:

containers:
....
      - env:
        - name: any-property-used-inside-the-application-for-saving-files
          value: /stored-files

因此,从卷上将pvc绑定到部署,从卷上安装,将磁盘绑定到目录,然后通过环境变量,您可以传递持久磁盘目录。 声明PVC和PV都是很基本的,没有PV的话,它将像任何具有自己的文件夹的吊舱一样工作。