Kubernetes 在 StatefulSet 和 3 个 PersistentVolumes 方面的问题

Kubernetes trouble with StatefulSet and 3 PersistentVolumes

我正在创建一个有 3 个副本的 StatefulSet based on this yaml。我希望 3 个 pods 中的每一个都连接到不同的 PersistentVolume。

对于持久卷,我使用了 3 个如下所示的对象,只是更改了名称 (pvvolume, pvvolume2, pvvolume3):

kind: PersistentVolume
apiVersion: v1
metadata:
  name: pvvolume
  labels:
    type: local
spec:
  storageClassName: standard
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/nfs"
  claimRef:
    kind: PersistentVolumeClaim
    namespace: default
    name: mongo-persistent-storage-mongo-0

StatefulSet 中的 3 个 pods 中的第一个似乎可以毫无问题地创建。

第二次失败,错误为 pod has unbound PersistentVolumeClaims Back-off restarting failed container

然而,如果我转到显示 PersistentVolumeClaims 的选项卡,则创建的第二个似乎已成功。

如果成功了,为什么 pod 认为它失败了?

I want each of the 3 pods to connect to a different PersistentVolume.

  • 要使其正常工作,您需要:

    • provisioner(在您发布的 link 中有示例如何在 aws、azure、googlecloud 和 minicube 上设置 provisioner)或
    • 可以多次挂载的卷(例如 nfs 卷)。但是请注意,在这种情况下,您所有的 pods read/write 都放在同一个文件夹中,当它们不打算同时 lock/write 相同的数据时,这可能会导致问题。通常的用例是 pods 保存到的上传文件夹,稍后用于只读和此类用例。 SQL 另一方面,数据库(例如 mysql)并不意味着写入此类共享文件夹。
  • 您正在使用 hostPath(指向 /nfs)并将其设置为 ReadWriteOnce(只有一个人可以使用),而不是声明清单中提到的任一要求。您还使用 'standard' 作为存储 class 并且在 url 中您给出了快速和慢速的存储,因此您可能也创建了存储 class。

The second fails with the error pod has unbound PersistentVolumeClaims Back-off restarting failed container

  • 这是因为第一个 pod 已经取得了它的声明(读写一次,主机路径),如果没有设置适当的配置器或访问,第二个 pod 不能重复使用相同的声明。

If it was successful why does the pod think it failed?

  • 所有 PVC 都已成功绑定到随附的 PV。但是你永远不会将第二个和第三个 PVC 绑定到第二个或第三个 pods。您正在重试第二个 pod 的第一个声明,并且第一个声明已经在 ReadWriteOnce 模式下绑定(到第一个 pod)并且不能绑定到第二个 pod 并且您收到错误...

建议的方法

由于您引用 /nfs 作为您的主机路径,可以安全地假设您正在使用某种 NFS 支持的文件系统,因此这里有一个替代设置,可以让您将动态配置的持久卷挂载到nfs 到有状态集中的任意数量 pods

备注:

  • 这仅回答了假设 nfs 共享 pods 跨状态复制挂载持久卷的原始问题。
  • 对于数据库等动态数据,NFS 并不是真正可取的。通常的用例是上传文件夹或中等 logging/backing 上传文件夹。数据库(sql 或没有 sql)通常是 nfs 的禁忌。
  • 对于 mission/time 关键应用程序,您可能需要 time/stresstest 在生产中采用这种方法之前仔细考虑,因为 k8s 和外部 pv 都在中间添加了一些 layers/latency 。尽管对于某些应用程序这可能就足够了,但请注意。
  • 您对动态创建的 pv 名称的控制有限(k8s 为新创建的 pv 添加后缀,并在被告知这样做时重用可用的旧名称),但 k8s 将在 pod 终止并首先分配后保留它们可用于新 pod,因此您不会松动 state/data。不过,这是您可以通过政策控制的事情。

步骤:

  • 要使其正常工作,您首先需要从此处安装 nfs provisioner:

  • 存储class清单:

    kind: StorageClass
    apiVersion: storage.k8s.io/v1beta1
    metadata:
      name: sc-nfs-persistent-volume
    # if you changed this during provisioner installation, update also here
    provisioner: example.com/nfs 
    
  • 状态集(仅重要摘录):

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: ss-my-app
    spec:
      replicas: 3
      ...
      selector:
        matchLabels:
          app: my-app
          tier: my-mongo-db
      ...
      template:
        metadata:
          labels:
            app: my-app
            tier: my-mongo-db
        spec:
          ...
          containers:
            - image: ...
              ...
              volumeMounts:
                - name: persistent-storage-mount
                  mountPath: /wherever/on/container/you/want/it/mounted
          ...
      ...
      volumeClaimTemplates:
      - metadata:
          name: persistent-storage-mount
      spec:
        storageClassName: sc-nfs-persistent-volume
        accessModes: [ ReadWriteOnce ]
        resources:
          requests:
            storage: 10Gi
      ...