在 AWS 上设置 EFS 存储#

ElasticFileSystem 是一个分布式文件系统,它使用 NFS 协议。据说它是在 AWS 幕后使用 GlusterFS 的一个分支。

缺点

  • 在 Kubernetes 规范中,持久卷的权限设置尚未确定。这会带来一些我们将在后面讨论的复杂情况。

  • 一个狡猾的用户可能能够直接联系 EFS 服务器并读取其他用户的文件,具体取决于系统的设置方式。

步骤

  1. 设置 EFS 卷

    在 AWS 中使用 EFS 设置向导(将来这部分可能会被脚本化)。新的 EFS 卷必须与您的集群位于同一个 VPC 中。这可以在创建后在 AWS 设置中更改。

    接下来,为 NFS 流量创建一个新的安全组(目标是该组中的其他实例)。在节点安全组和主安全组中添加一个用于传入 NFS 流量的规则。更改 EFS 卷以使用该安全组。

    要验证您的 EFS 卷是否正常工作,请 ssh 登录到其中一个主节点并 su 到 root。接下来,按照 EFS 控制台页面上的步骤挂载您的 NFS 卷。DNS 条目可能需要几分钟才能显示。

    挂载成功后,将其卸载并断开与管理节点的连接。

  2. 配置 Kubernetes 以了解您的 EFS 卷

    创建 test_efs.yaml

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: efs-persist
    spec:
      capacity:
        storage: 123Gi
      accessModes:
        - ReadWriteMany
      nfs:
        server: fs-${EFS_ID}.efs.us-east-1.amazonaws.com
        path: "/"
    

    创建 test_efs_claim.yaml

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: efs-persist
    spec:
      storageClassName: ""
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 11Gi
    

    这些文件中的大小是误导性的。EFS 没有强制执行配额。将来,我们希望将 efs 持久卷大小设置为一个非常大的数字,例如 8EiB,并将持久卷声明设置为 10GB。据我们目前所知,这些大小并不重要。

    持久卷定义了一个服务,该服务可以在容器内部执行挂载。持久卷声明是预留持久卷的一部分并可能锁定对其访问的一种方式。

    storageClassName 设置看起来很不起眼,但它非常关键。集群中唯一没有存储类别的 PV 是我们上面定义的 PV。将来,我们应该标记不同的 PV,并在 PVC 中使用标签过滤器,而不是依赖于“”。

    我们将配置 jupyterhub 以在所有容器之间使用相同的“静态”声明。这意味着我们所有用户都将使用相同的 EFS 共享,该共享应该能够根据我们的需要进行扩展。

    这部分与标准指南略有不同。我们需要在我们的应用程序将要所在的命名空间中创建这些 PV 和 PVC。选择一个命名空间(这将与您稍后在 helm install 步骤中使用的命名空间相同)

    运行以下命令来设置您的命名空间和存储

    kubectl create namespace <your namespace>
    kubectl --namespace=<your namespace> apply -f test_efs.yaml
    kubectl --namespace=<your namespace> apply -f test_efs_claim.yaml
    

    我不知道 PV 是否需要在命名空间中,但参数似乎没有造成任何伤害。PVC 必须在命名空间中,否则会以奇怪的方式出错。

  3. 配置您的应用程序以使用 EFS 作为其后端存储

    现在,我们将以下内容添加到 config.yaml 中

    singleuser:
      image:
        name: jupyter/base-notebook
        tag: latest
      storage:
        type: "static"
        static:
          pvcName: "efs-persist"
          subPath: "home/{username}"
      extraEnv:
        CHOWN_HOME: "yes"
      uid: 0
      fsGid: 0
      cmd: "start-singleuser.sh"
    

    image 设置覆盖了默认的固定 jh 基础镜像,因为它尚未更新以包含 CHOWN_HOME 设置。

    type static 告诉 jh 不要使用存储类别,而是使用下面定义的 PVC。

    pvcName 与我们之前指定的声明名称匹配

    subPath 指示挂载点应该位于提供的存储中的哪个位置。在这种情况下,它将是“$EFS_ROOT/home/{username}”

    事实证明,jupyterhub 中存在一个错误,导致默认的 subPath 无法正常工作,并将 subPath 设置为“{username}”也会以相同的方式出错。

    extraEnv 部分在尝试在用户的容器内启动 jupyterhub 之前设置环境变量。CHOWN_HOME 是强制更改主目录的所有权所需的。

    Kubernetes 仍然存在争议,关于是否应该传递 uid 和 gid 来改变目录在容器内的挂载方式。目前,我们在 JupyterHub 启动之前自动更改目录的所有权。

    UID/fsGID 是必要的,以强制容器以 root 身份运行 start-singleuser.sh。一旦 start-singleuser.sh 正确地更改了目录的所有权,它就会切换到 jupyterhub 用户。