如何共享库伯内特豆荚之间的存储?

我正在评估 Kubernetes 作为我们新应用程序的平台。现在看来,一切都非常令人兴奋!然而,我遇到了一个问题: 我正在 GCE 上托管我的集群,我需要一些机制来在两个 pods 之间共享存储——持续集成服务器和我的应用服务器。对付库伯内氏病最好的方法是什么?似乎没有一种卷类型适合我的需要,因为如果一个 pod 需要写入磁盘,则不能共享 GCE 磁盘。NFS 将是完美的,但似乎需要特殊的库伯内特集群构建选项?

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

编辑2: 例如,这一页描述了如何建立一个 Elasticsearch 集群,但是将其与持久存储连接起来是不可能的(正如这里所描述的) ,这使得它变得毫无意义: (

121153 次浏览

Update: The best choice is probably Cloud Filestore, a managed NFS system. This gives you full random read/write access to files, unlike GCS which only supports upload/download. See docs here.

Original: Have you tried Google Cloud Storage? You might even be able to use the FUSE adapter to map it like a network disk.

If it is logs that you are looking to write to disk, I suggest you look at logspout https://github.com/gliderlabs/logspout. This will collect each pod's logging and then you can use google cloud platforms' fairly new logging service that uses fluentd. That way all logs from each pod are collected into a single place.

If it is data that would normally write to a database or something of that nature, I recommend having a separate server outside of the kubernetes cluster that runs the database.

EDIT

For sharing files amongst pods, I recommend mounting a google cloud storage drive to each node in your kubernetes cluster, then setting that up as a volume into each pod that mounts to that mounted directory on the node and not directly to the drive. Having it mount to each node is good because pods do not run on designated nodes, so it's best to centralize it in that case.

NFS is a built-in volume plugin and supports multiple pod writers. There are no special build options to get NFS working in Kube.

I work at Red Hat on Kubernetes, focused mainly on storage.

@Marco - in regards to the Maven related question my advice would be to stop looking at this as a centralized storage problem and perhaps think of it as a service issue.

I've run Maven repositories under HTTP in the past (read-only). I would simply create a Maven repo and expose it over Apache/Nginx in its own pod (docker container) with what ever dedicated storage you need for just that pod and then use service discovery to link it to your application and build systems.

Firstly, do you really need multiple readers / writers?

From my experience of Kubernetes / micro-service architecture (MSA), the issue is often more related to your design pattern. One of the fundamental design patterns with MSA is the proper encapsulation of services, and this includes the data owned by each service.

In much the same way as OOP, your service should look after the data that is related to its area of concern and should allow access to this data to other services via an interface. This interface could be an API, messages handled directly or via a brokage service, or using protocol buffers and gRPC. Generally, multi-service access to data is an anti-pattern akin to global variables in OOP and most programming languages.

As an example, if you where looking to write logs, you should have a log service which each service can call with the relevant data it needs to log. Writing directly to a shared disk means that you'd need to update every container if you change your log directory structure, or decided to add extra functionality like sending emails on certain types of errors.

In the major percentage of cases, you should be using some form of minimal interface before resorting to using a file system, avoiding the unintended side-effects of Hyrum's law that you are exposed to when using a file system. Without proper interfaces / contracts between your services, you heavily reduce your ability to build maintainable and resilient services.

Ok, your situation is best solved using a file system. There are a number of options...

There are obviously times when a file system that can handle multiple concurrent writers provides a superior solution over a more 'traditional' MSA forms of communication. Kubernetes supports a large number of volume types which can be found here. While this list is quite long, many of these volume types don't support multiple writers (also known as ReadWriteMany in Kubernetes).

Those volume types that do support ReadWriteMany can be found in this table and at the time of writing this is AzureFile, CephFS, Glusterfs, Quobyte, NFS and PortworxVolume.

There are also operators such as the popular rook.io which are powerful and provide some great features, but the learning curve for such systems can be a difficult climb when you just want a simple solution and keep moving forward.

The simplest approach.

In my experience, the best initial option is NFS. This is a great way to learn the basic ideas around ReadWriteMany Kubernetes storage, will serve most use cases and is the easiest to implement. After you've built a working knowledge of multi-service persistence, you can then make more informed decisions to use more feature rich offerings which will often require more work to implement.

The specifics for setting up NFS differ based on how and where your cluster is running and the specifics of your NFS service and I've previously written two articles on how to set up NFS for on-prem clusters and using AWS NFS equivalent EFS on EKS clusters. These two articles give a good contrast for just how different implementations can be given your particular situation.

For a bare minimum example, you will firstly need an NFS service. If you're looking to do a quick test or you have low SLO requirements, following this DO article is a great quick primer for setting up NFS on Ubuntu. If you have an existing NAS which provides NFS and is accessible from your cluster, this will also work as well.

Once you have an NFS service, you can create a persistent volume similar to the following:

---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-name
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
nfs:
server: 255.0.255.0 # IP address of your NFS service
path: "/desired/path/in/nfs"

A caveat here is that your nodes will need binaries installed to use NFS, and I've discussed this more in my on-prem cluster article. This is also the reason you need to use EFS when running on EKS as your nodes don't have the ability to connect to NFS.

Once you have the persistent volume set up, it is a simple case of using it like you would any other volume.

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-name
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: p-name
volumeMounts:
- mountPath: /data
name: v-name
volumes:
- name: v-name
persistentVolumeClaim:
claimName: pvc-name

Have you looked at kubernetes Volumes ? You are probably looking at creating a gcePersistentDisk

A gcePersistentDisk volume mounts a Google Compute Engine (GCE) Persistent Disk into your pod. Unlike emptyDir, which is erased when a Pod is removed, the contents of a PD are preserved and the volume is merely unmounted. This means that a PD can be pre-populated with data, and that data can be “handed off” between pods. Important: You must create a PD using gcloud or the GCE API or UI before you can use it There are some restrictions when using a gcePersistentDisk: the nodes on which pods are running must be GCE VMs those VMs need to be in the same GCE project and zone as the PD A feature of PD is that they can be mounted as read-only by multiple consumers simultaneously. This means that you can pre-populate a PD with your dataset and then serve it in parallel from as many pods as you need. Unfortunately, PDs can only be mounted by a single consumer in read-write mode - no simultaneous writers allowed. Using a PD on a pod controlled by a ReplicationController will fail unless the PD is read-only or the replica count is 0 or 1.

To support multiple writes from various pods you will probably need to create one beefy pod which exposes a thrift or socket types service which exposes readFromDisk and WriteToDisk methods.

Google recently released cloud filestore, with a tutorial here: https://cloud.google.com/filestore/docs/accessing-fileshares

Might be a good alternative to cloud storage/buckets for some scenarios.

First of all. Kubernetes doesn't have integrated functionality to share storage between hosts. There are several options below. But first how to share storage if you already have some volumes set up.

To share a volume between multiple pods you'd need to create a PVC with access mode ReadWriteMany

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

After that you can mount it to multiple pods:

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'

Of course, persistent volume must be accessible via network. Otherwise you'd need to make sure that all the pods are scheduled to the node with that volume.

There are several volume types that are suitable for that and not tied to any cloud provider:

  • NFS
  • RBD (Ceph Block Device)
  • CephFS
  • Glusterfs
  • Portworx Volumes

Of course, to use a volume you need to have it first. That is, if you want to consume NFS you need to setup NFS on all nodes in K8s cluster. If you want to consume Ceph, you need to setup Ceph cluster and so on.

The only volume type that supports Kubernetes out of the box is Portworks. There are instruction on how to set it up in GKE.

To setup Ceph cluster in K8s there's a project in development called Rook.

But this is all overkill if you just want a folder from one node to be available in another node. In this case just setup NFS server. It wouldn't be harder than provisioning other volume types and will consume much less cpu/memory/disk resources.

Helm: if you use helm to deploy

If you have a PVC that only supports RWO and you want many pods to be able to read from the same PVC and share that storage, then you can install the helm chart stable/nfs-server-provisioner if your cloud provider does not support RWX access mode.

This chart provisions "out-of-tree" storage PVCs with RWX access mode that access the underlying PVC from a cloud provider that only supports RWO, like Digital Ocean.

In your pods, you mount the PVC provisioned by the nfs server and you can scale them while they read and write from the same PVC.

Important!

You have to modify the values file to add configuration suited to your deployment like your storage class.

For more information on the chart: https://github.com/helm/charts/tree/master/stable/nfs-server-provisioner

I just achieve this with an application made with 3 containerized micro-services, I have one of this that is responsible to store and share files, so the application is storing files and retrieving them on a folder, this folder is passed via application property. There is a secured rest entry point that is allowing submission and retrieving of files (basically at every submission it is creating a unique id that is returned and can be used to scan the folder for a file). Passing this application from docker-compose to kubernetes I had your same problem : I need a global disk so I can have multiple replica of the container, so when the other micro-services will send a request to one of the replica, they will always be able to send any submitted file, not only the replica file managed at submission. I solved by creating a persistent volume, associated to an persistent volume claim, this volume claim is associated to a deployment (note: not a Statefulset, that it will create a disk for every pod), at this point you have to associate the mounted volume path with the container storing folder path.

So what is important is just the persistent volume claim name and the fact that PV has more available memory of PVC, and obviously the matching with the deployment with the right labels. Then in the deployment you can pass in the spec:

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

into the container settings:

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

and in env. block:

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

So, from volume, you bind the pvc to the deployment, then from volume mounts, you bind the disk to a directory, then via environment variable you are able to pass the persistent disk directory. It is fundamental that your declare both PVC and PV, without PV it will work like any pods has its own folder.