在ACK中使用ossfs 2.0挂载动态OSS存储卷

对于需要持久化存储或在多Pod间共享数据的应用,可通过动态PVOSS Bucket挂载为 ossfs 2.0 存储卷。该方式通过  StorageClass 作为模板自动创建并绑定PV,不仅简化了存储管理,还让应用能像访问本地文件一样,通过标准的POSIX接口读写OSS数据。

相较于ossfs 1.0ossfs 2.0在顺序读写性能上表现优异,可以更好地利用OSS的高带宽优势。

ossfs 2.0的性能说明,请参见ossfs 2.0客户端压测性能

流程指引

ACK集群中挂载ossfs 2.0动态存储卷主要流程如下。

image
  1. 确定挂载存储卷时的鉴权方式(支持访问密钥(AccessKey)和RRSA)并准备访问凭证。

    展开查看鉴权方式对比

    • RRSA:安全级别更高,使用自动轮换的临时凭证,支持Pod级权限隔离,适用于生产、多租户等高安全要求的环境。

      选择RRSA时,需创建并授权一个专用于OSS访问的RAM角色。

    • AccessKey:配置简单,但使用静态长期密钥,存在泄露风险,推荐用于测试或开发环境。

      选择AccessKey时,需创建RAM用户,获取其AccessKey,并将其存储为Kubernetes Secret。

  2. 创建StorageClass:定义一个存储模板,其中包含OSS Bucket信息、挂载参数和鉴权配置。

  3. 创建PVC:"申请"使用OSS存储资源。PVC会根据指定的StorageClass,自动触发PV的创建和绑定。

  4. 在应用中挂载:将PVC作为存储卷挂载到容器的指定目录中。

注意事项

  • 读写场景:ossfs 2.0 主要适用于只读和顺序追加写场景。对于需要随机写或并发写的场景,无法保证数据一致性,建议使用 ossfs 1.0。

  • 数据安全:通过ossfs挂载后,在应用Pod或宿主机上对挂载目录内文件的修改或删除均会同步至源OSS Bucket。为防止数据误删,建议为Bucket开启版本控制

  • 应用健康检查:建议为使用OSS存储卷的Pod配置健康检查(Liveness Probe),例如检查挂载目录是否可用。当挂载异常时,可自动重启Pod以恢复。

  • 分片管理:当上传大文件(>10MB)时,ossfs会自动分片。若上传中断,产生的碎片文件会残留在Bucket中,可手动删除碎片通过生命周期规则删除碎片,以节省存储成本。

方式一:通过RRSA鉴权方式挂载

基于适用于服务账户的RAM角色(RAM Roles for Service Accounts,简称RRSA),可在集群内实现PV维度的OpenAPI权限隔离,从而实现云资源访问权限的细粒度隔离,降低安全风险。详情请参见通过RRSA配置ServiceAccountRAM权限实现Pod权限隔离

前提条件

步骤一:创建RAM角色

若集群已通过 RRSA 挂载过 OSS,可跳过此步。首次配置时请按以下步骤操作。

  1. 容器服务管理控制台启用RRSA功能,操作请参见启用RRSA功能

  2. OSS存储卷RRSA鉴权新建RAM角色,即使用RRSA功能扮演的指定角色,请参见创建OIDC身份提供商的RAM角色

    demo-role-for-rrsa为例,主要参数说明如下。

    配置项

    描述

    身份提供商类型

    OIDC

    身份提供商

    选择ack-rrsa-<cluster_id>。其中,<cluster_id>为您的集群ID。

    条件

    • oidc:iss:保持默认。

    • oidc:aud:保持默认。

    • oidc:sub:需手动添加该条件。

      • 条件键:选择oidc:sub

      • 运算符:选择StringEquals

      • 条件值:默认输入system:serviceaccount:ack-csi-fuse:csi-fuse-ossfs

        其中,ack-csi-fuseossfs客户端所在的命名空间,无法自定义。csi-fuse-ossfs为服务账户名称,可修改为指定的服务账户名称。

        关于如何修改服务账户名称,如何在RRSA鉴权方式中使用指定的ARNsServiceAccount?

    角色名称

    demo-role-for-rrsa。

步骤二:为demo-role-for-rrsa角色授权

  1. 创建如下OSS访问的自定义权限策略。具体操作,请参见创建自定义权限策略

    以下只读和读写权限策略请根据使用需求选择,并替换mybucket为您实际创建的Bucket名称。

    • OSS只读权限策略

      展开查看OSS只读权限策略内容

      {
          "Statement": [
              {
                  "Action": [
                      "oss:Get*",
                      "oss:List*"
                  ],
                  "Effect": "Allow",
                  "Resource": [
                      "acs:oss:*:*:mybucket",
                      "acs:oss:*:*:mybucket/*"
                  ]
              }
          ],
          "Version": "1"
      }
    • OSS读写权限

      展开查看OSS读写权限策略内容

      {
          "Statement": [
              {
                  "Action": "oss:*",
                  "Effect": "Allow",
                  "Resource": [
                      "acs:oss:*:*:mybucket",
                      "acs:oss:*:*:mybucket/*"
                  ]
              }
          ],
          "Version": "1"
      }
  2. (可选)若您使用KMS托管的指定CMK ID加密OSS Object,还需要为该RAM用户配置KMS权限。具体操作,请参见加密操作

  3. demo-role-for-rrsa角色授权。具体操作,请参见RAM角色授权

    说明

    您也可以通过修改RAM角色信任策略的方式使用已有的授权了OSS权限的RAM角色。具体操作,请参见使用已存在的RAM角色并授权

步骤三:创建StorageClass

创建StorageClass,作为动态生成PV的模板。

  1. 修改以下YAML,保存为ossfs2-sc-rrsa.yaml

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: ossfs2-sc  # StorageClass名称
    parameters:
      bucket: cnfs-oss-test  # Bucket名称
      path: /subpath  # 待挂载的子目录,留空则挂载根目录
      url: oss-cn-hangzhou-internal.aliyuncs.com  # OSS Bucket所在地域的Endpoint
      authType: rrsa
      roleName: demo-role-for-rrsa  # 此前创建的RAM角色
      fuseType: ossfs2
      volumeAs: sharepath
      otherOpts: "-o close_to_open=false"
    provisioner: ossplugin.csi.alibabacloud.com  # 固定为此值
    reclaimPolicy: Retain  # 动态创建PV的回收策略,当前仅支持Retain,即删除PVC时,PVOSS Bucket中的数据不会被删除
    volumeBindingMode: Immediate  # 卷绑定模式。OSS存储卷无需考虑可用区间节点亲和,使用默认值Immediate即可

    parameters参数说明:

    参数

    是否必选

    说明

    bucket

    必选

    待挂载的OSS Bucket。

    path

    必选

    Bucket内的基础路径。当 volumeAs 配置为 sharepath 时,每个动态创建的PV都会在此路径下被分配一个唯一的子目录(例如 /ack/<pv-name>)。

    url

    必选

    待挂载OSS访问域名(Endpoint)。

    • 挂载节点和Bucket处于相同地域,或已打通VPC网络时,使用内网地址。

    • 挂载节点和Bucket不同地域时,使用外网地址。

    不同访问端口的常见填写格式如下:

    • 内网格式:http://oss-{{regionName}}-internal.aliyuncs.comhttps://oss-{{regionName}}-internal.aliyuncs.com

      内网访问端口格式vpc100-oss-{{regionName}}.aliyuncs.com已废弃,请及时切换。
    • 外网格式:http://oss-{{regionName}}.aliyuncs.comhttps://oss-{{regionName}}.aliyuncs.com

    fuseType

    必选

    使用ossfs 2.0客户端时,固定为ossfs2

    authType

    必选

    配置为rrsa,声明使用RRSA方式鉴权。

    roleName

    必选

    配置为此前创建或修改的RAM角色名称。

    如需为不同PV配置不同权限,可创建不同的RAM角色,并在PV中配置不同的roleName

    volumeAs

    可选

    定义PV的供应方式。sharepath表示每个PV都将在path指定的目录下创建一个独立的子目录。

    otherOpts

    可选

    OSS存储卷输入定制化参数,格式为-o *** -o ***,例如-o close_to_open=false

    close-to-open:默认为关闭。开启后,每次打开文件时,系统会主动向OSS发送GetObjectMeta请求,以获取文件在OSS中的最新元数据信息,从而确保元数据的实时性。但在需要大量读取小文件的场景下,频繁的元数据查询会显著增加访问延迟。

    更多可选参数,请参见ossfs 2.0挂载选项说明

  2. 创建StorageClass。

    kubectl create -f ossfs2-sc-rrsa.yaml
  3. 确认StorageClass状态。

    kubectl get sc ossfs2-sc

    预期输出:

    NAME        PROVISIONER                      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
    ossfs2-sc   ossplugin.csi.alibabacloud.com   Retain          Immediate                                  10s

步骤四:创建PVC

创建PVC,从StorageClass申请存储资源。此操作将触发底层PV的自动创建。

  1. 修改以下YAML,保存为ossfs2-pvc-dynamic.yaml。

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: pvc-ossfs2 # PVC名称
      namespace: default
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 20Gi
      storageClassName: ossfs2-sc   # 此前创建的StorageClass
  2. 创建PVC。

    kubectl create -f ossfs2-pvc-dynamic.yaml
  3. 确认PVCPV状态。

    kubectl get pvc pvc-ossfs2

    预期输出中,PVC的状态为Bound,表明已成功绑定到自动创建的PV。

    NAME        STATUS   VOLUME                   CAPACITY   ACCESS MODES   STORAGECLASS     AGE
    pvc-ossfs2  Bound    d-bp17y03tpy2b8x******   20Gi       RWX            ossfs2-sc        25s

步骤五:创建应用并挂载存储卷

PVC创建后,可将其绑定的存储资源挂载到应用中。

  1. 使用以下YAML,创建ossfs2-test.yaml

    以下YAML示例创建包含1PodStatefulSet,Pod通过名为pvc-ossfs2PVC申请存储资源,挂载路径为/data

    展开查看YAML

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: ossfs2-test
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ossfs2-test
      template:
        metadata:
          labels:
            app: ossfs2-test
        spec:
          containers:
          - name: nginx
            image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
            ports:
            - containerPort: 80
            volumeMounts:
            - name: pvc-ossfs2
              mountPath: /data
          volumes:
            - name: pvc-ossfs2
              persistentVolumeClaim:
                claimName: pvc-ossfs2
  2. 创建StatefulSet并挂载存储卷。

    kubectl create -f ossfs2-test.yaml
  3. 查看Pod部署情况。

    kubectl get pod -l app=ossfs2-test

    预期输出:

    NAME            READY   STATUS    RESTARTS   AGE
    ossfs2-test-0   1/1     Running   0          2m
  4. 验证应用是否能正常访问OSS数据。

    # 向挂载点写入一个测试文件
    kubectl exec -it ossfs2-test-0 -- touch /data/test.txt
    # 查看挂载点内容
    kubectl exec -it ossfs2-test-0 -- ls /data

    预期输出中,可以看到刚刚创建的test.txt文件,表明挂载成功且具备写权限。

方式二:通过RAM用户AccessKey鉴权方式挂载

ACK也支持通过创建包含静态AccessKeySecret,来为应用挂载OSS存储卷进行授权。此方式适用于为特定应用授予长期、固定OSS访问权限的业务场景。

  • 如果PV所引用的AccessKey被撤销或权限变更,正在使用该存储卷的应用将失去访问权限并报权限错误。恢复访问时,需先更新Secret中的凭证,然后重启应用Pod来强制重新挂载。此过程将导致业务服务短暂中断,请在维护窗口操作。

  • 为避免由于AccessKey轮转导致业务中断,建议通过RRSA鉴权方式挂载

前提条件

步骤一:创建具有OSS访问权限的RAM用户并获取AccessKey

创建RAM用户并授权

  1. 创建RAM用户,如已创建可跳过。具体操作,请参见创建RAM用户

  2. 创建如下OSS访问的自定义权限策略。具体操作,请参见创建自定义权限策略

    以下只读和读写权限策略请根据使用需求选择,并替换mybucket为您实际创建的Bucket名称。

    • OSS只读权限策略

      展开查看OSS只读权限策略内容

      {
          "Statement": [
              {
                  "Action": [
                      "oss:Get*",
                      "oss:List*"
                  ],
                  "Effect": "Allow",
                  "Resource": [
                      "acs:oss:*:*:mybucket",
                      "acs:oss:*:*:mybucket/*"
                  ]
              }
          ],
          "Version": "1"
      }
    • OSS读写权限

      展开查看OSS读写权限策略内容

      {
          "Statement": [
              {
                  "Action": "oss:*",
                  "Effect": "Allow",
                  "Resource": [
                      "acs:oss:*:*:mybucket",
                      "acs:oss:*:*:mybucket/*"
                  ]
              }
          ],
          "Version": "1"
      }
  3. (可选)若您使用KMS托管的指定CMK ID加密OSS Object,还需要为该RAM用户配置KMS权限。具体操作,请参见加密操作

  4. RAM用户添加OSS权限。具体操作,请参见RAM用户授权

  5. RAM用户创建AccessKey。具体操作,请参见获取AccessKey

使用 AccessKey 创建 Secret

使用以下命令创建用于 OSS 鉴权的 Secret。将 akIdakSecret 替换为真实凭证。

kubectl create -n default secret generic oss-secret --from-literal='akId=xxxxxx' --from-literal='akSecret=xxxxxx'

步骤二:创建StorageClass

  1. 修改以下YAML,保存为ossfs2-sc.yaml。

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: ossfs2-sc
    parameters:
      # 使用准备工作中创建的Secret。
      csi.storage.k8s.io/node-publish-secret-name: oss-secret  
      csi.storage.k8s.io/node-publish-secret-namespace: default
      fuseType: ossfs2
      bucket: cnfs-oss-test # Bucket名称
      path: /subpath  # 待挂载的子目录,留空则挂载根目录
      url: oss-cn-hangzhou-internal.aliyuncs.com  # OSS Bucket所在地域的Endpoint
      otherOpts: "-o close_to_open=false"
    provisioner: ossplugin.csi.alibabacloud.com  # 固定为此值
    reclaimPolicy: Retain  # 动态创建PV的回收策略,当前仅支持Retain,即删除PVC时,PVOSS Bucket中的数据不会被删除
    volumeBindingMode: Immediate  # 卷绑定模式。OSS存储卷无需考虑可用区间节点亲和,使用默认值Immediate即可

    parameters参数说明:

    • 配置Secret

      参数

      是否必选

      说明

      csi.storage.k8s.io/node-publish-secret-name

      必选

      存储AccessKey信息的Secret名称。

      csi.storage.k8s.io/node-publish-secret-namespace

      必选

      存储AccessKey信息的Secret所在的命名空间。

    • 配置存储卷

      参数

      是否必选

      说明

      fuseType

      必选

      使用ossfs 2.0客户端时,固定为ossfs2

      bucket

      必选

      需要挂载的OSS Bucket。

      path

      可选

      OSS Bucket挂载路径表示挂载时相对Bucket根文件的目录结构。

      url

      必选

      挂载OSSEndpoint,EndpointOSS控制台Bucket概览页为准。

      • 挂载节点和Bucket相同地域,或已打通VPC网络时,请使用内网地址。

      • 挂载节点和Bucket不同地域时,请使用外网地址。

      不同访问端口的常见填写格式如下:

      • 内网格式:http://oss-{{regionName}}-internal.aliyuncs.comhttps://oss-{{regionName}}-internal.aliyuncs.com

      • 外网格式:http://oss-{{regionName}}.aliyuncs.comhttps://oss-{{regionName}}.aliyuncs.com

      重要

      vpc100-oss-{{regionName}}.aliyuncs.com的内网访问端口格式已废弃,请及时切换。

      otherOpts

      可选

      OSS存储卷输入定制化参数,格式为-o *** -o ***,例如-o close_to_open=false

      close-to-open:默认为关闭。开启后,每次打开文件时,系统会主动向OSS发送GetObjectMeta请求,以获取文件在OSS中的最新元数据信息,从而确保元数据的实时性。但在需要大量读取小文件的场景下,频繁的元数据查询会显著增加访问延迟。

      更多可选参数,请参见ossfs 2.0挂载选项说明

  2. 创建StorageClass。

    kubectl create -f ossfs2-sc.yaml

步骤三:创建PVC

创建PVC,从StorageClass申请存储资源。此操作将触发底层PV的自动创建。

  1. 修改以下YAML,保存为ossfs2-pvc-dynamic.yaml。

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: pvc-ossfs2 # PVC名称
      namespace: default
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 20Gi
      storageClassName: ossfs2-sc   # 此前创建的StorageClass
  2. 创建PVC。

    kubectl create -f ossfs2-pvc-dynamic.yaml
  3. 确认PVCPV状态。

    kubectl get pvc pvc-ossfs2

    预期输出中,PVC的状态为Bound,表明已成功绑定到自动创建的PV。

    NAME        STATUS   VOLUME                   CAPACITY   ACCESS MODES   STORAGECLASS     AGE
    pvc-ossfs2  Bound    d-bp17y03tpy2b8x******   20Gi       RWX            ossfs2-sc        25s

步骤四:创建应用并挂载存储卷

PVC创建后,可将其绑定的存储资源挂载到应用中。

  1. 使用以下YAML,创建ossfs2-test.yaml

    以下YAML示例创建包含1PodStatefulSet,Pod通过名为pvc-ossfs2PVC申请存储资源,挂载路径为/data

    展开查看YAML

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: ossfs2-test
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ossfs2-test
      template:
        metadata:
          labels:
            app: ossfs2-test
        spec:
          containers:
          - name: nginx
            image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
            ports:
            - containerPort: 80
            volumeMounts:
            - name: pvc-ossfs2
              mountPath: /data
          volumes:
            - name: pvc-ossfs2
              persistentVolumeClaim:
                claimName: pvc-ossfs2
  2. 创建StatefulSet并挂载存储卷。

    kubectl create -f ossfs2-test.yaml
  3. 查看Pod部署情况。

    kubectl get pod -l app=ossfs2-test

    预期输出:

    NAME            READY   STATUS    RESTARTS   AGE
    ossfs2-test-0   1/1     Running   0          2m
  4. 验证应用是否能正常访问OSS数据。

    # 向挂载点写入一个测试文件
    kubectl exec -it ossfs2-test-0 -- touch /data/test.txt
    # 查看挂载点内容
    kubectl exec -it ossfs2-test-0 -- ls /data

    预期输出中,可以看到刚刚创建的test.txt文件,表明挂载成功且具备写权限。

生产环境使用建议

维度

说明

安全与权限管理

  • 优先使用RRSA鉴权:在生产环境中,推荐使用RRSA进行鉴权。RRSA通过OIDC和临时安全令牌(STS)为Pod提供访问凭证,降低凭证泄露风险,还可实现Pod级别的精细化权限隔离。

  • 遵循最小权限原则:为RAM角色或为RAM用户授予权限时,应严格遵循最小权限原则。

性能与成本优化

  • 合理配置挂载参数 (otherOpts):

    • 元数据缓存 (-o close_to_open=false):默认行为,适用于大量读取小文件的场景,可缓存文件元数据,从而降低延迟和API请求费用。

    • 实时元数据 (-o close_to_open=true):当OSS文件会被其他系统频繁更新,且Pod需要立即感知时,可开启。但会增加API调用次数和访问延迟,请谨慎使用。

    • 根据业务场景,参见ossfs 2.0挂载选项说明进行更精细的性能调优。

  • 评估工作负载:

    • ossfs 2.0适用于AI 训练、推理、大数据处理及自动驾驶等新型计算密集型负载场景,以顺序和随机读取、仅追加(Append-only)写入为主要特征,且不依赖完整 POSIX 语义的应用场景。

    • 由于不支持随机写入,ossfs 2.0 不适用于需要频繁修改文件内容的场景,如数据库、在线编辑等。

  • 管理分片生命周期:对于写密集型应用,如果上传大文件时频繁中断,会产生大量未合并分片。建议在OSS Bucket上配置生命周期规则,定期自动清理碎片,节省存储成本。

  • 使用内网Endpoint:当集群与OSS Bucket位于同一地域时,请使用内网Endpoint,以避免公网带宽费用,并获得更低的网络延迟。

运维管理

  • 配置健康检查:为应用Pod配置存活探针(Liveness Probe)。当挂载点因网络抖动、CSI组件异常等原因失效时,健康检查会失败,ACK会自动重启Pod,触发存储卷的重新挂载。

  • 监控与告警:利用容器存储监控配置告警,及时发现容量或性能瓶颈。

常见问题