ossfs 1.0存储卷FAQ

本文介绍使用ossfs 1.0存储卷的常见问题和解决方法。

问题导航

类型

问题

挂载

使用

扩容

实际存储容量超出OSS存储卷的配置时,是否需要扩容存储卷

卸载

OSS静态卷卸载失败,Pod一直处于Terminating状态

挂载

OSS存储卷挂载时间延长

问题现象

OSS存储卷挂载时间延长。

问题原因

同时满足以下配置,kubelet在存储卷挂载过程中将执行chmodchown操作,导致挂载时间延长。

  • PVPVC中配置AccessModesReadWriteOnce

  • 应用模板中配置了securityContext.fsgroup

解决方案

  • ossfs挂载工具支持通过参数修改其挂载点下文件所属的UID、GID以及文件的mode。

    参数

    说明

    uid

    指定挂载目录下子目录及文件归属用户的用户UID。

    gid

    指定挂载目录下子目录及文件归属用户的用户GID。

    umask

    用于设定挂载目录下子目录及文件的权限掩码。使用方式与mp_umask类似,但无需依赖allow_other配置项。

    配置后,请删除securityContext下的fsgroup参数。

  • 对于1.20及之后版本的Kubernetes集群,除了上述解决方法外,也可将fsGroupChangePolicy配置为OnRootMismatch,实现仅在首次启动时才会执行chmodchown操作,后续挂载时间将恢复正常。关于fsGroupChangePolicy的更多信息,请参见Pod或容器配置安全性上下文

OSS存储挂载权限问题

当您在以下几种场景中进行操作时,出现错误提示Permission Denied

场景1:访问挂载目录时,出现错误提示Permission Denied

问题原因

OSS默认使用Linuxroot用户进行挂载,权限为700。当容器进程以非root用户运行时,权限不足。

解决方案

通过增加配置项修改挂载根目录的权限。

参数

说明

allow_other

设置挂载目录的权限为777。

mp_umask

用于设定挂载目录的权限掩码,只有当allow_other选项设置后,该选项才生效。默认值为000。例如:

  • 需设置挂载目录的权限为770,则增加-o allow_other -o mp_umask=007

  • 需设置挂载目录的权限为700,则增加-o allow_other -o mp_umask=077

场景2:访问通过ossutil、OSS控制台、SDK等其他方式上传的文件时,出现错误提示Permission Denied

问题原因

通过其他方式上传的文件在ossfs中默认权限为640。当容器进程以非root用户运行时,权限不足。

解决方案

root角色chmod修改目标文件的权限。或者通过以下配置项修改挂载目录下子目录及文件的权限。

参数

说明

umask

用于设定挂载目录下子目录及文件的权限掩码。使用方式与mp_umask类似,但无需依赖allow_other配置项。

umask只能修改当前ossfs中看到的文件的权限,再次挂载或对其他ossfs进程并不生效。例如:

  • 配置-o umask=022后,使用stat查看一个通过OSS控制台上传的文件,权限为755;取消-o umask=022配置项后再次挂载,权限仍为640。

  • 容器进程以root用户配置-o umask=133后,通过chmod配置某文件权限为777,stat该文件权限仍为644;取消-o umask=133后再次挂载,权限变更为777。

场景3:通过不同的容器进行读写操作时,读、写、运行其他容器创建的文件。

问题原因

ossfs中创建的普通文件默认权限为644。配置securityContext中的fsGroup字段,或创建后chmod、chown文件,都可能导致权限或所有者的变更。当另一个容器进程以其他用户操作文件时,可能会出现权限不足的问题。

解决方案

stat目标文件的权限,若权限不足,请以root用户使用chmod修改目标文件的权限。

以上三种场景的解决均通过增加目录或文件的权限,解决当前容器进程用户权限不足的问题,您也可以通过修改ossfs挂载目录下子目录及文件所属用户来解决。

容器镜像构建时指定运行用户,或部署时应用模板的securityContext.runAsUsersecurityContext.runAsGroup字段非空,都会使应用的容器进程以非root用户运行。

通过以下配置项修改ossfs挂载目录下子目录及文件的UIDGID,使其与容器进程用户一致。

参数

说明

uid

指定挂载目录下子目录及文件归属用户的用户UID。

gid

指定挂载目录下子目录及文件归属用户的用户GID。

例如,容器访问OSS的进程IDuid=1000(biodocker)gid=1001(biodocker)groups=1001(biodocker),则需配置-o uid=1000-o gid=1001

场景4:OSS挂载时使用Secret记录AccessKey信息,并在PV中通过nodePublishSecretRef字段指定Secret。因为AK轮转等原因撤销了原AK,SecretAccessKey信息修改后不生效

问题原因

OSS数据卷是使用ossfs文件进行挂载的FUSE文件系统,挂载成功后无法更新AccessKey信息,已经挂载了OSS存储卷的应用仍然使用原AKOSS Server端发送请求。

解决方案

切换Secret中新的AccessKey信息后重新挂载。非容器化版本或开启了独享挂载方式的容器化版本,您只需要重启应用Pod触发ossfs重启。具体操作,请参见共享挂载方式下,如何重启ossfs进程?

场景5:硬链接操作时,返回Operation not permitted

问题原因

OSS存储卷不支持硬链接操作。在早期的CSI版本中,硬链接操作返回的报错为Operation not permitted

解决方案

改造业务,使用OSS存储卷时,应避免硬链接操作。若您的业务必须使用硬链接操作,建议您更换存储。

场景6:使用subpathsubpathExpr方式挂载OSS存储卷,读写操作权限不足

问题原因

root用户运行的业务容器没有/path/subpath/in/oss/目录下文件的权限(默认为640)。subpath方式挂载OSS存储卷时,ossfsOSS服务端实际的挂载目录为PV中定义的path目录,即上述示例中的/path,而非/path/subpath/in/oss/。配置allow_othermp_umask挂载项仅对/path目录生效,/path/subpath/in/oss/目录作为子目录仍默认为640。

解决方案

通过umask配置项修改子目录默认权限,例如-o umask=000将默认权限修改为777。

OSS存储卷挂载失败

问题现象

OSS存储卷挂载失败,Pod无法启动,Event提示FailedMount。

问题原因

  • 原因1:ossfs早期版本不支持挂载到Bucket中不存在的目录中,原挂载目录不存在导致挂载失败。

    重要

    OSS控制台中可见的子路径在Server端不一定真实存在,以ossutilOSS API的返回为准。例如,直接创建/a/b/c/目录,/a/b/c/为单独的目录对象,而/a//a/b/目录对象实际并不存在。同理,如上传/a/*文件,/a/b/a/c等为单独的文件对象,/a/目录对象不存在。

  • 原因2:AccessKeyRRSA使用的角色信息填写错误或权限不足导致挂载失败。

  • 原因3:Event的内容中包含failed to get secret secrets "xxx" is forbidden: User "serverless-xxx" cannot get resource "secrets" in API group "" in the namespace "xxx"。对于创建在虚拟节点(ACS Pod)上的应用,当PVC需要通过nodePublishSecretRef字段来指定鉴权信息时,Secret必须与PVC位于同一个命名空间。

  • 原因4:CSI版本在1.30.4及以上时,OSSFS所在的Pod运行在ack-csi-fuse命名空间中。挂载时CSI将先拉起OSSFS所在的Pod,再通过RPC请求实际启动Pod中的OSSFS进程。若Event的内容中包含FailedMount /run/fuse.ossfs/xxxxxx/mounter.sock: connect: no such file or directory,原因为OSSFS所在Pod未正常拉起或被意外删除。

  • 原因5:Event的内容中包含Failed to find executable /usr/local/bin/ossfs: No such file or directory,原因为OSSFS在节点上安装失败。

  • 原因6:Event的内容中包含error while loading shared libraries: xxxxx: cannot open shared object file: No such file or directory,挂载失败的原因为当前CSI版本ossfs直接运行在节点上,且操作系统缺乏部分ossfs运行所需的动态库。以下情况都可能导致该报错:

    • 手动在节点安装过其他版本的ossfs工具,且适配的操作系统与当前节点不一致。

    • 节点操作系统版本升级导致OpenSSL默认版本变更,例如Alibaba Cloud Linux 2升级至Alibaba Cloud Linux 3。

    • ossfs运行在节点上时,不支持CentOS、Alibaba Cloud Linux、ContainerOS和龙蜥以外的操作系统。

    • 在符合操作系统要求的节点上删除过默认的FUSE、cURL、xml2ossfs运行需要的动态库,或变更过OpenSSL的默认版本。

  • 原因7:挂载OSS Bucket的子目录时,AccessKeyRRSA使用的角色仅授权了子目录范围的权限,挂载失败。ossfs Pod日志中同时包含403 AccessDenied 404 NoSuchKey报错。

    ossfs在启动时将自动对OSS Bucket进行权限校验与连通性检测。挂载目标为OSS子目录时,1.91.5以下版本的ossfs将先尝试访问Bucket根目录;若访问失败,则重新尝试访问子目录。对Bucket有完整只读权限时,新版本ossfs允许挂载OSS Bucket中不存在的子目录。

    因此,对若AccessKeyRRSA使用的角色仅授权了子目录范围的权限,将在初次验证时报403 AccessDenied错误;若该子目录不存在,则继续报404 NoSuchKey错误并异常退出,导致挂载失败。

  • 原因8:Bucket配置了镜像回源,挂载目录未从源站同步。

  • 原因9:Bucket配置了静态网站托管,ossfs检查OSS端挂载目录时,请求转发到index.html等文件中。

解决方案

  • 原因1解决方案:

    检查子路径在OSS Server端是否存在。

    假设PV的挂载路径为sub/path/,您可以使用stat(查看BucketObject信息)查询objectnamesub/path/的对象,或使用openapi HeadObject查询keysub/path/的对象。若返回为404,确认Server端不存在该子路径。

    • 您可以通过ossutil、SDK、OSS控制台等工具手动创建缺失的Bucket或子目录,然后重新挂载。

    • ossfs1.91+版本不强制要求挂载目录存在,您也可以通过升级ossfs版本解决该问题。更多信息,请参见ossfs 1.0新版本功能介绍及性能压测。若升级后挂载仍出现问题,请参见本问题原因6

  • 原因2解决方案:

    • 确认挂载使用的RAM用户或RAM角色的策略权限包括步骤二:为demo-role-for-rrsa角色授权中列举的权限。

    • 确认挂载点根路径及subpath路径的文件系统权限,详情请参考OSS存储挂载权限问题中的场景1和场景6。

    • 对于通过RAM用户AccessKey鉴权方式挂载的存储卷,确认挂载时使用的AccessKey是否被禁用或已轮转,详情请参考OSS存储挂载权限问题中的场景4.

    • 对于通过RRSA鉴权方式挂载的存储卷,确认是否为RAM角色配置正确的信任策略。信任策略的配置请参考步骤一:创建RAM角色。默认情况下,信任的ServiceAccountack-csi-fuse命名空间下的csi-fuse-ossfs,而非业务使用的ServiceAccount。

      重要

      RRSA鉴权方式挂载仅支持1.26及以上版本的集群,且集群使用的CSI组件为1.30.4及以上版本。若您在1.30.4之前的版本中使用了RRSA功能,请及时参见【产品变更】CSI ossfs版本升级与挂载流程优化增加RAM角色授权配置。

  • 原因3解决方案:

    请在PVC所在的命名空间下创建所需的Secret,新建PV时,将nodePublishSecretRef指向该Secret。具体操作,请参见通过RAM用户AccessKey鉴权方式挂载

  • 原因4解决方案:

    1. 执行以下命令,确认OSSFS所在Pod存在。其中PV_NAME为挂载的OSS PV名称,NODE_NAME为需挂载存储卷的业务Pod所在的节点名称。

      kubectl -n ack-csi-fuse get pod -l csi.alibabacloud.com/volume-id=<PV_NAME> -owide | grep <NODE_NAME>

      Pod存在且状态异常,请排查Pod的异常原因,确保Pod正常Running后重启业务Pod触发重新挂载。若Pod不存在,请按后续步骤继续排查。

    2. (可选)通过查询审计日志等方式确认Pod是否被意外删除,常见的意外删除原因包括业务脚本清理、节点排水、节点自愈等。建议您做相关调整,避免问题重现。

    3. 确认CSI provisionerCSI plugin均升级到1.30.4及以上后:

      1. 执行以下步骤,确认是否残留VolumeAttachment资源

        kubectl get volumeattachment | grep <PV_NAME> | grep <NODE_NAME>

        若有,请删除该VolumeAttachment资源。

      2. 重启业务Pod触发重新挂载,并确认OSSFS Pod有正常创建流程。

  • 原因5解决方案:

    1. 建议您将csi-plugin版本升级到v1.26.2或以上版本,该版本修复了刚扩容出的节点初始化时,ossfs安装失败的问题。

    2. 执行以下命令,尝试重启对应节点上的csi-plugin后,查看Pod是否能正常启动。

      以下代码中csi-plugin-****为节点所在csi-pluginPod名称。

      kubectl -n kube-system delete pod csi-plugin-****
    3. 若升级或重启组件后,问题仍无法解决,请登录节点,执行以下命令。

      ls /etc/csi-tool

      部分预期输出:

      ... ossfs_<ossfsVer>_<ossfsArch>_x86_64.rpm ...
      • 若输出中存在OSSFSRPM包,则执行以下命令,查看Pod是否能正常启动。

        rpm -i /etc/csi-tool/ossfs_<ossfsVer>_<ossfsArch>_x86_64.rpm
      • 若输出中不存在OSSFSRPM包,请参见安装ossfs 1.0下载最新版本。

  • 原因6解决方案:

    • 若您手动安装过ossfs工具,请检查适配的操作系统与节点是否一致。

    • 若您升级过集群的节点操作系统,可以执行以下指令重启csi-plugin,更新ossfs版本后再尝试挂载。

      kubectl -n kube-system delete pod -l app=csi-plugin
    • 建议您升级CSI1.28或以上版本,挂载OSS存储卷时ossfs以容器的方式运行在集群中,对节点操作系统无要求。

    • 若您的集群无法升级CSI版本,可以切换至符合要求的OS或手动安装缺少的动态库,以Ubuntu节点为例:

      • 使用which指令,查询当前ossfs的安装位置(默认安装路径为/usr/local/bin/ossfs)。

        which ossfs
      • 使用ldd指令,查询ossfs缺失的动态库文件。

        ldd /usr/local/bin/ossfs
      • 使用apt-file指令,查询缺失的动态库文件(如libcrypto.so.10)所属的Package。

        apt-get install apt-file
        apt-file update
        apt-file search libcrypto.so.10
      • 使用apt-get指令安装对应Package(如libssl.1.0.0)。

        apt-get install libssl1.0.0
  • 原因7解决方案:

    • 推荐方案:升级CSI版本至v1.32.1-35c87ee-aliyun以上。

    • 其他方案1:参考本问题原因1,确认子目录是否存在。

    • 其他方案2:若业务长期需要挂载子目录,建议将权限范围扩大到整个Bucket。

  • 原因8解决方案:

    您需要同步源站数据后,再进行挂载。更多信息,请参见回源配置概述

  • 原因9解决方案:

    您需要关闭或调整静态网站托管的配置,再进行挂载。更多信息,请参见静态网站托管概述

如何通过OSS存储卷仅挂载OSS中的某个文件

OSS存储卷通过ossfs工具将OSS的某个路径以文件系统的形式挂载到Pod中,ossfs本身并不支持挂载文件。若您希望在Pod中仅能看到OSS中的某个文件,可通过subPath的方式实现:

假设需要挂载的OSSbucket:/subpath下的a.txtb.txt文件到两个不同的Pod中,在Pod中的存放路径分别为/path/to/file/,可参考以下YAML创建对应的PV:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-oss
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: ossplugin.csi.alibabacloud.com
    volumeHandle: pv-oss 
    volumeAttributes:
      bucket: bucket
      path: subpath #subpath为a.txt与b.txt的父路径
      url: "oss-cn-hangzhou.aliyuncs.com"

创建对应的PVC后,Pod中挂载PVC相应的VolumeMounts配置为:

  volumeMounts:
    - mountPath: /path/to/file/a.txt # bucket:/subpath对应Pod中的挂载路径
      name: oss-pvc # 与Volumes中的名称一致
      subPath: a.txt # 或者b.txt,bucket:/subpath中文件的相对路径

挂载后,Pod中访问a.txt的完整路径为/path/to/file/a.txt,实际访问的是bucket:/subpath/a.txt。

OSS存储卷的基本使用说明请参考使用ossfs 1.0静态存储卷

说明
  • 以上示例中,ossfs在节点上的挂载点对应的实际OSS路径为bucket:/subpath,对于节点上的文件扫描等进程,或以非subPath形式挂载的Pod而言,可见的内容仍为bucket:/subpath。

  • 对于非root用户运行的容器需要注意subPath的权限配置,详情请参考使用subpathsubpathExpr方式挂载OSS存储卷异常

如何在RRSA鉴权方式中使用指定的ARNsServiceAccount?

通过RRSA方式的OSS存储卷鉴权时,无法满足例如使用第三方OIDC身份提供商、使用非默认ServiceAccount等需求。

此时,您只需要在PV中通过roleName配置项指定RAM角色名称,即可由CSI存储插件获取默认的Role ARNOIDC Provider ARN。若您需要实现定制化的RRSA鉴权,则需要更改PV的配置信息如下:

说明

其中,roleArnoidcProviderArn需要一起配置,配置后无需再配置roleName

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-oss
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: ossplugin.csi.alibabacloud.com
    volumeHandle: pv-oss # 需要和PV名字一致。
    volumeAttributes:
      bucket: "oss"
      url: "oss-cn-hangzhou.aliyuncs.com"
      otherOpts: "-o umask=022 -o max_stat_cache_size=0 -o allow_other"
      authType: "rrsa"
      oidcProviderArn: "<oidc-provider-arn>"
      roleArn: "<role-arn>"
      #roleName: "<role-name>" #配置roleArn和oidcProviderArn后,roleName失效。
      serviceAccountName: "csi-fuse-<service-account-name>" 

参数

说明

oidcProviderArn

OidcProviderArn需要在创建OIDC身份提供商后获取。更多信息,请参见管理OIDC身份提供商

roleArn

RoleArn需要在创建可信实体为上述OIDC身份提供商的RAM角色后获取。更多信息,请参见使用OIDC进行角色SSO的示例

serviceAccountName

可选,ossfs容器所在的Pod使用ServiceAccount名称,需要预先创建。

配置为空时,使用CSI维护的默认ServiceAccount。

重要

ServiceAccount名称必须以csi-fuse-开头。

如何跨账号挂载OSS Bucket?

建议通过RRSA鉴权方式跨账号挂载OSS Bucket。

请确认集群和CSI组件版本满足RRSA鉴权要求的版本。

以下操作以在账号A(集群所在账号)中,挂载账号B(OSS Bucket所在账号)的Bucket为例。需完成RAM授权相关准备工作后,再正常创建通过RRSA鉴权方式挂载的存储卷。

  1. 在账号B中的操作:

    1. 在账号B中创建可信实体为账号ARAM角色roleB,详情请参见创建可信实体为阿里云账号的RAM角色

    2. roleB授权需要挂载的OSS Bucket权限。

    3. RAM控制台,访问roleB的角色详情页,复制其ARN,如acs:ram::130xxxxxxxx:role/roleB

  2. 在账号A中的操作:

    1. 为应用创建一个用于 RRSA 鉴权的 RAM 角色roleA,信任主体类型为OIDC身份提供商。

    2. 为 roleA 授予代入 roleB 的权限。具体操作请参见通过RRSA鉴权方式挂载(静态卷)或通过RRSA鉴权方式挂载(动态卷)。

      roleA无需再授权OSS相关权限策略,但需要授权包含sts:AssumeRoleAPI的权限策略,如系统策略AliyunSTSAssumeRoleAccess

  3. 在集群中配置存储卷:

    在创建存储卷时,将 roleB的 ARN 配置到 assumeRoleArn参数中:

    • 静态卷 (PV):在 volumeAttributes中添加:

      assumeRoleArn: <roleBARN>
    • 动态卷 (StorageClass):在 parameters中添加:

      assumeRoleArn: <roleBARN>

ossfs容器化后如何开启独享挂载模式?

问题现象

同一节点上挂载了相同OSS存储卷的多个Pod共享挂载点。

问题原因

ossfs容器化前,默认使用独享方式挂载,即每个挂载OSS存储卷的Pod,都将在对应节点上为该存储卷拉起ossfs进程。不同ossfs进程对应的挂载点之间完全独立,即对于挂载了同一OSS存储卷的不同Pod在读写时互不影响。

ossfs容器化后,ossfs进程将以容器的方式运行在Pod中,具体为kube-systemack-csi-fuse命名空间下名为csi-fuse-ossfs-*的 Pod。在多挂载场景下,独享方式挂载将在集群中拉起大量Pod,进而导致弹性网卡不足等问题。因此,容器化后将默认使用共享方式挂载,即同一节点上挂载了相同OSS存储卷的多个Pod共享挂载点,均对应同一个csi-fuse-ossfs-* Pod,实际由同一ossfs进程实现挂载。

解决方案

重要

1.30.4及以上版本CSI不再支持开启独享挂载模式,如果您需要重启或变更ossfs的相关配置,可以参考共享挂载方式下,如何重启ossfs进程?如有其他ossfs独享挂载的需求,请加入钉群(钉群号:33936810)联系我们。

如果您期望恢复到容器化前的独享挂载,请在创建OSS存储卷时增加useSharedPath配置项,并将其设为"false"。示例如下:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: oss-pv
spec:
  accessModes:
  - ReadOnlyMany
  capacity:
    storage: 5Gi
  csi:
    driver: ossplugin.csi.alibabacloud.com
    nodePublishSecretRef:
      name: oss-secret
      namespace: default
    volumeAttributes:
      bucket: bucket-name
      otherOpts: -o max_stat_cache_size=0 -o allow_other
      url: oss-cn-zhangjiakou.aliyuncs.com
      useSharedPath: "false" 
    volumeHandle: oss-pv
  persistentVolumeReclaimPolicy: Delete
  volumeMode: Filesystem

使用subpathsubpathExpr方式挂载OSS存储卷异常

问题现象

使用subpathsubpathExpr方式挂载OSS存储卷时,出现以下异常:

  • 挂载失败:挂载OSS存储卷的Pod创建后,一直处于CreateContainerConfigError状态,并且出现如下类似Event。

    Warning  Failed          10s (x8 over 97s)  kubelet            Error: failed to create subPath directory for volumeMount "pvc-oss" of container "nginx"
  • 读写异常:挂载OSS存储卷进行OSS读写操作时,出现权限不足的报错提示Operation not permittedPermission denied

  • 卸载失败:删除挂载了OSS存储卷的Pod时,Pod一直处于Terminating状态。

问题原因

为方便阐述原因及解决方案,假设PV的相关配置为:

...
    volumeAttributes:
      bucket: bucket-name
      path: /path
      ...

Pod的相关配置为:

...
       volumeMounts:
      - mountPath: /path/in/container
        name: oss-pvc
        subPath: subpath/in/oss
      ...

OSS服务端subpath挂载目录为Bucket中的/path/subpath/in/oss/

  • 挂载失败原因

    • 原因1:OSS服务端不存在挂载目录/path/subpath/in/oss/,且OSS存储卷使用的用户或角色未被授权PutObject权限(例如只读场景中仅配置了OSS ReadOnly权限)。

      kubelet尝试在OSS服务端创建/path/subpath/in/oss/目录时因权限不足失败。

    • 原因2:OSS服务端的挂载目录/path/subpath/in/oss/中某一层的目录对象(以"/"结尾的key,如path/path/subpath/等)在文件系统中被解析为文件,导致Kubelet无法正常确认subpath路径状态。

  • 读写异常原因root用户运行的业务容器没有/path/subpath/in/oss/目录下文件的权限(默认为640)。subpath方式挂载OSS存储卷时,ossfsOSS服务端实际的挂载目录为PV中定义的path目录,即上述示例中的/path,而非/path/subpath/in/oss/。配置allow_othermp_umask挂载项仅对/path目录生效,/path/subpath/in/oss/目录作为子目录仍默认为640。

  • 卸载失败原因:OSS服务端中/path/subpath/in/oss/挂载目录被删除,阻塞kubelet回收subpath路径,导致卸载失败。

解决方案

  • 挂载失败解决方案

    • 原因1:

      1. OSS服务端预先创建/path/subpath/in/oss/目录,提供kubelet挂载subpath路径。

      2. 若需要创建的目录较多(例如通过subpathExpr方式挂载OSS存储卷),无法全部预先创建时,可为OSS存储卷使用的用户或角色增加putObject权限授权。

    • 原因2:

      1. 参考问题文件目录挂载后,显示为文件对象的原因1解决方案,确认OSS服务端中各目录对象(keypath/path/subpath/等,查询时请勿以"/"开头)是否存在,及content-typecontent-length字段。符合以下条件时,该目录对象将在文件系统同被异常识别为文件:

        目录对象存在(API返回码为20X,否则content-typecontent-length字段无意义)且目录对象的content-typeplain、octet-streamx-directory(如json、tar等)、content-length长度非0.

      2. 如符合以上条件,参考问题文件目录挂载后,显示为文件对象的原因1解决方案清除异常的目录对象。

  • 读写异常解决方案通过umask配置项修改子目录默认权限,例如-o umask=000将默认权限修改为777。

  • 卸载失败解决方案:请参见OSS静态卷卸载失败,Pod一直处于Terminating状态中的原因2解决方案。

使用

OSS存储卷访问Bucket过慢

问题现象

OSS存储卷访问Bucket过慢。

问题原因

  • 原因1:OSS本身没有文件数限制,但当文件数量大于1000时,OSSFUSE访问元数据过多,导致Bucket访问过慢。

  • 原因2:OSS开启版本控制后,当Bucket中存在大量删除标记时,listObjectsV1性能下降。

  • 原因3:OSS服务端设置存储类型为标准存储(Standard)以外的存储,其他存储类型将不同程度地降低数据访问的性能。

解决方案

  • 原因1解决方案:建议以只读形式访问OSS Bucket,针对大量平铺对象,可采用OSS SDK方式或CLI方式等非文件系统挂载方式,访问Bucket的数据。更多信息,请参见SDK示例简介

  • 原因2解决方案:

    1. 升级CSI plugin组件至v1.26.6,ossfs支持通过listObjectsV2访问Bucket。

    2. OSS静态卷PVotherOpts字段中增加-o listobjectsv2来解决。

  • 原因3解决方案:修改存储类型或者解冻文件

OSS控制台看到文件大小为0

问题现象

容器内挂载OSS数据卷时,在文件中写入数据,但在OSS控制台看到文件大小为0。

问题原因

容器使用ossfs挂载OSS,即基于FUSE方式挂载OSS Bucket,只有在文件执行close或者flush时,文件内容才会上传至OSS服务端。

解决方案

使用lsof+文件名称的方式,查看文件是否被其他进程占用,关闭相应进程,释放文件fd。更多信息,请参见lsof

业务访问挂载点报错"Transport endpoint is not connected"

问题现象

容器内挂载OSS数据卷后,突然访问挂载点失败,报错:Transport endpoint is not connected。

问题原因

容器使用ossfs挂载OSS,业务访问OSS数据期间,ossfs进程异常退出,导致挂载点处于断联状态。

其中,ossfs进程异常退出的原因主要有:

  • 资源不足退出,如OOM Killed。

  • ossfs在访问数据期间因段错误退出。

解决方案

  1. 确认ossfs进程异常退出原因。

    重要

    若您的线上业务因挂载点断联受损,且该异常为偶发现象,您可以先通过重新部署业务容器重新挂载OSS存储卷进行修复。

    重新挂载OSS存储卷将导致下述排查流程中所需的部分信息丢失,相关步骤已注明。

    1. 确认是否因资源不足退出。

      1. Pod维度资源不足:若CSI版本在1.28及以上,确认ossfs所在Pod是否有重启次数,且上一次异常退出的原因是否为OOM Killed等原因。获取ossfs所在Pod的方式请参考ossfs 1.0异常问题排查

      2. 节点维度资源不足:若异常Pod已因重新挂载被删除,或CSI版本在1.28以下,可通过ACKECS监控大盘中确认在挂载存储卷期间节点是否处于资源高水位状态。

    2. 确认是否因段错误退出。

      1. CSI版本在1.28以下,ossfs以进程方式运行在节点上,需登录节点查询系统日志。查询是否有与段错误退出相关的信息。

        journalctl -u ossfs | grep segfault
      2. CSI版本在1.28及以上,直接查询ossfs所在Pod的日志,确认是否有"signal: segmentation fault"等与段错误退出相关的信息。

        说明

        以下情况会导致无法获取相关日志,若已确认ossfs进程非资源不足原因退出,建议您可以先按段错误退出进行进一步排查。

        • 若段错误发生时间较久,节点或Pod的日志均可能已因轮转而丢失。

        • 若已重新挂载业务容器,日志因被Pod删除而丢失。

  2. ossfs因资源不足退出,请适当调整ossfs所在Pod的资源限制,或将挂载OSS存储卷的业务Pod调度到资源更充裕的节点中。

    若确认是ossfs自身占用较多内存,其原因可能是业务或三方扫描软件对挂载点的readdir操作触发ossfsOSS服务端发送大量的HeadObject请求,您可以考虑开启readdir优化功能,具体请参考新增readdir优化功能

  3. 绝大部分低版本ossfs的段错误问题均已在1.91及以上版本中修复,若ossfs因段错误退出,应优先考虑将ossfs的版本升级至1.91及以上,即升级CSI版本至1.30.4及以上。ossfs版本详情请参考ossfs 1.0版本说明

    若您的CSI版本已满足,请根据以下步骤进一步收集段错误coredump文件并提交工单

    • 若节点操作系统为Alibaba Cloud Linux 3,节点默认已配置好吐核参数,ossfs段错误发生后可登录节点后在/var/lib/systemd/coredump/路径下找到打包的coredump文件core.ossfs.xxx.lz4

    • 对操作系统非Alibaba Cloud Linux 3的节点,需要确认节点允许进程生成coredump文件。如对于Alibaba Cloud Linux 2节点,可登录节点并执行以下操作:

      echo "|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e" > /proc/sys/kernel/core_pattern

      配置后,与Alibaba Cloud Linux 3操作系统类似,ossfs段错误发生后可登录节点后在/var/lib/systemd/coredump/路径下找到打包的coredump文件core.ossfs.xxx.xz

业务访问挂载点报错"Input/output error"

问题现象

业务访问挂载点报错"Input/output error"

问题原因

  • 原因1:OSS挂载路径下的对象名称包含特殊字符,导致服务端的返回无法解析。

  • 原因2:FUSE文件系统不支持对根挂载点进行chmod \ chown等操作。

  • 原因3:RAM权限策略的Resource为单个Bucket或其中某目录权限时,授权不完整。

解决方案

  • 原因1解决方案:

    参考ossfs 1.0异常问题排查,获取ossfs客户端日志,包含类似如下的错误日志:

    parser error : xmlParseCharRef: invalid xmlChar value 16
        <Prefix>xxx&#16;xxxx/</Prefix>

    其中,&#16;表示某无法解析的Unicode字符;xxx&#16;xxxx/表示该对象的完整名称(示例为目录对象)。通过API、控制台等方式确认该对象在OSS服务端存在。OSS控制台该字符可能显示为空格。

    参考重命名文件,重命名OSS服务端的对象。若该对象为目录,建议参考常用操作,使用ossbrowser 2.0的方式重命名整个目录。

  • 原因2解决方案:

    使用-o allow_other-o mp_umask挂载蚕食对挂载路径实现类似chmod的效果:

    参数

    说明

    allow_other

    设置挂载目录的权限为777。

    mp_umask

    用于设定挂载目录的权限掩码,只有当allow_other选项设置后,该选项才生效。默认值为000。例如:

    • 需设置挂载目录的权限为770,则增加-o allow_other -o mp_umask=007

    • 需设置挂载目录的权限为700,则增加-o allow_other -o mp_umask=077

    使用-o gid-o uid挂载参数对挂载路径实现类似chown的效果:

    参数

    说明

    uid

    指定挂载目录下子目录及文件归属用户的用户UID。

    gid

    指定挂载目录下子目录及文件归属用户的用户GID。

  • 原因3解决方案:

    若需要仅为某个BucketBucket中的某个路径授权,请参考步骤二:为demo-role-for-rrsa角色授权中的授权策略,需要同时为mybucketmybucket/*(授权某Bucket),或mybucket/subpathmybucket/subpath/*授权(授权某路径)。

文件目录挂载后,显示为文件对象

问题现象

容器内挂载OSS数据卷时,文件原本是目录,挂载后显示为文件对象。

问题原因

  • 原因1:目录对象在OSS服务端content-type类型是非默认的application/octet-stream类型(例如text/html、image/jpeg等),或目录对象的大小非0,ossfs根据其元信息将其视为文件对象。

  • 原因2:非原因1的情况,但目录对象缺少元信息x-oss-meta-mode

解决方案

  • 原因1解决方案:

    通过HeadObjectstat(查看BucketObject信息)获取目录对象元信息,目录对象需要以"/"结尾(例如a/b/),以API返回为例。

    {
      "server": "AliyunOSS",
      "date": "Wed, 06 Mar 2024 02:48:16 GMT",
      "content-type": "application/octet-stream",
      "content-length": "0",
      "connection": "keep-alive",
      "x-oss-request-id": "65E7D970946A0030334xxxxx",
      "accept-ranges": "bytes",
      "etag": "\"D41D8CD98F00B204E9800998ECFxxxxx\"",
      "last-modified": "Wed, 06 Mar 2024 02:39:19 GMT",
      "x-oss-object-type": "Normal",
      "x-oss-hash-crc6xxxxx": "0",
      "x-oss-storage-class": "Standard",
      "content-md5": "1B2M2Y8AsgTpgAmY7Phxxxxx",
      "x-oss-server-time": "17"
    }

    以上返回示例中:

    • content-type:为application/octet-stream,即目录对象为application/octet-stream类型。

    • content-length:为0,即目录对象大小为0。

    若不满足以上条件,您可以通过以下方式修复:

    1. 通过GetObject命令行工具ossutil快速入门获取该对象,确认数据是否有用。若数据有用或不能确定,建议对其进行备份,例如变更名称(对xx/目录对象,请勿使用xx作为新的名称)后上传至OSS。

    2. 通过DeleteObjectrm(删除)删除有问题的目录对象,然后确认ossfs是否正常显示目录。

  • 原因2解决方案:

    若通过原因1的解决方案未修复问题,您可以在容器内挂载OSS数据卷时,在OSS静态卷PVotherOpts字段中增加-o complement_stat来解决。

    说明

    CSI plugin组件版本为v1.26.6及以上版本时,配置项已默认开启,您可以将存储组件升级至v1.26.6或以上版本,重启业务Pod并重新挂载OSS静态卷解决问题。

OSS服务端监控到大量异常请求流量

问题现象

容器内挂载OSS数据卷时,OSS服务端监控到请求数量远超预期。

问题原因

ossfs挂载OSS对象存储时,将在节点上产生挂载路径,ECS上的其他进程对挂载点的扫描也会转换为向OSS的请求。请求次数过多会产生费用。

解决方案

通过审计追踪请求进程并修复。您可以在节点上进行如下操作。

  1. 安装auditd并启动。

    sudo yum install auditd
    sudo service auditd start
  2. ossfs挂载路径设为监测目录。

    • 如需添加所有挂载路径,请执行以下命令。

      for i in $(mount | grep -i ossfs | awk '{print $3}');do auditctl -w ${i};done
    • 如需添加某个PV的挂载路径,请执行以下命令。

      <pv-name>为指定的PV名称。

      for i in $(mount | grep -i ossfs | grep -i <pv-name> | awk '{print $3}');do auditctl -w ${i};done
  3. auditlog中查看哪些进程访问了OSS Bucket中的路径。

    ausearch -i 

    审计日志分析示例如下。以下示例中,---分隔符间的审计日志为一组,记录对监控挂载点的单次操作。该示例表示updatedb进程对挂载点中的子目录进行了open的操作,进程PID1636611。

    ---
    type=PROCTITLE msg=audit(20230922日 15:09:26.244:291) : proctitle=updatedb
    type=PATH msg=audit(20230922日 15:09:26.244:291) : item=0 name=. inode=14 dev=00:153 mode=dir,755 ouid=root ogid=root rdev=00:00 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0
    type=CWD msg=audit(20230922日 15:09:26.244:291) : cwd=/subdir1/subdir2
    type=SYSCALL msg=audit(20230922日 15:09:26.244:291) : arch=x86_64 syscall=open success=yes exit=9 a0=0x55f9f59da74e a1=O_RDONLY|O_DIRECTORY|O_NOATIME a2=0x7fff78c34f40 a3=0x0 items=1 ppid=1581119 pid=1636611 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts1 ses=1355 comm=updatedb exe=/usr/bin/updatedb key=(null)
    ---
  4. 借助日志进一步确认是否存在非业务的进程调用,并进行修复。

    例如,通过auditlog查到updatedb扫描了所挂载的目录,可以通过修改/etc/updatedb.conf让它跳过。具体操作如下。

    1. RUNEFS =后面加上fuse.ossfs

    2. PRUNEPATHS =后面加上挂载的目录。

通过OSS存储卷写入的文件对象的元数据Content-Type全为application/octet-stream类型

问题现象

通过OSS存储卷写入的文件对象的元数据Content-Type全为application/octet-stream类型,导致浏览器或其他客户端未能够正确识别和处理这些文件。

问题原因

  • 未指定Content-Type类型,ossfs默认将文件对象视为二进制流文件。

  • 通过/etc/mime.types配置文件指定Content-Type类型,但未生效。

解决方案

  1. 确认CSI组件版本,1.26.61.28.1版本的组件对Content-Type配置存在兼容性问题。若使用了相关版本,请升级CSI至最新版本。更多信息,请参见【组件公告】关于1.26.61.28.1版本的csi-plugincsi-provisioner组件兼容性问题

  2. 若您已经通过使用mailcapmime-support在节点上生成/etc/mime.types的方式指定Content-Type类型,升级CSI版本后,重新挂载对应OSS存储卷即可。

  3. 若您未指定Content-Type类型,可通过以下两种方式指定:

    • 节点级别配置:在节点上生成/etc/mime.types配置文件,对所有新挂载到该节点上的OSS存储卷生效。更多信息,请参见常见问题

    • 集群级别配置:该方式对集群所有新挂载的OSS存储卷生效,/etc/mime.types内容与mailcap默认生成的内容一致。

      1. 检查csi-plugin配置文件是否存在。

        kubectl -n kube-system get cm csi-plugin

        若不存在,使用以下内容创建csi-plugin同名ConfigMap;若不存在,则需要在原ConfigMap中增加data.fuse-ossfs中的内容mime-support="true"

        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: csi-plugin
          namespace: kube-system
        data:
          fuse-ossfs: |
            mime-support=true
      2. 重启csi-plugin,使配置生效。

        重启csi-plugin不会影响当前已经成功挂载的存储卷的使用。

        kubectl -n kube-system delete pod -l app=csi-plugin
  4. 重新挂载对应的OSS存储卷。

创建硬链接时返回错误Operation not supportedOperation not permitted

问题现象

创建硬链接时返回错误Operation not supportedOperation not permitted。

问题原因

OSS存储卷不支持硬链接操作,将返回Operation not supported错误。在早期的CSI版本中,硬链接操作返回的报错为Operation not permitted

解决方案

改造业务,在使用OSS存储卷时,应避免硬链接操作。若您的业务必须使用硬链接操作,建议您更换存储。

如何查看通过OSS存储卷访问OSS的记录?

您可以在OSS管理控制台查看OSS的操作记录。请确保已开通实时日志查询

  1. 登录OSS管理控制台

  2. 单击Bucket 列表,然后单击目标Bucket名称。

  3. 在左侧导航栏,选择日志管理 > 实时查询

  4. 实时查询页签下,根据查询语法分析语法,输入查询和分析语句,对OSS日志进行分析。您可以通过user_agentclient_ip字段定位日志是否来源于ACK。

    1. 定位由ACK发送的OSS操作请求时,您需要选择user_agent字段,展开后看到user_agent里包含ossfs的都可以选择。

      重要
      • user-agent字段的值与ossfs版本有关,ossfs版本不同,user-agent字段的值也不一样,但均以aliyun-sdk-http/1.0()/ossfs开头。

      • 如果您在ECS上也通过ossfs挂载,相关日志也会被耦合到这里。

    2. 如需定位到某个ECS实例或集群,您可以选择client_ip字段,然后选择对应的IP。

    结合以上两个字段选择,查询到的日志示例如下图所示。image

    日志查询部分字段说明

    字段

    说明

    operation

    OSS操作的类型。例如GetObject、GetBucketStat等。更多信息,请参见API概览

    object

    对象名称,OSS中的目录、文件。

    request_id

    请求的唯一标识,如果有请求ID,您可以精确查询某个请求。

    http_status、error_code

    针对请求结果的查询。更多信息,请参见HTTP错误码

共享挂载方式下,如何重启ossfs进程?

问题现象

修改鉴权信息或ossfs版本后,已经在运行的ossfs进程无法自动变更。

问题原因

  • ossfs运行后无法变更鉴权信息等配置,变更配置后,需要重启ossfs进程(容器化版本后,即为kube-systemack-csi-fuse命名空间下的csi-fuse-ossfs-* Pod)与对应的应用Pod,造成业务中断。因此,默认情况下CSI不会对已经运行的ossfs进行变更。

  • 正常使用流程中,ossfs的部署与删除均由CSI完成。手动删除ossfs进程所在的Pod,无法触发CSI的部署流程。

解决方案

重要

重启ossfs进程的流程中需要重启挂载对应OSS存储卷的业务Pod,请谨慎操作。

若您使用的是非容器化的CSI版本,或开启了独享挂载,可以直接重启对应的应用Pod。容器化版本后,默认使用共享挂载方式,即每个节点上挂载同一OSS存储卷的所有应用Pod共用ossfs进程实现挂载。

  1. 确认当前FUSE Pod被哪些应用Pod使用。

    1. 执行以下命令,确认需要变更的csi-fuse-ossfs-* Pod。

      其中<pv-name>PV名称,<node-name>为节点名称。

      CSI版本小于1.30.4时,执行以下操作:

      kubectl -n kube-system get pod -lcsi.alibabacloud.com/volume-id=<pv-name> -owide | grep <node-name>

      CSI版本大于等于1.30.4时,执行以下操作

      kubectl -n ack-csi-fuse get pod -lcsi.alibabacloud.com/volume-id=<pv-name> -owide | grep <node-name>

      预期输出:

      csi-fuse-ossfs-xxxx   1/1     Running   0          10d     192.168.128.244   cn-beijing.192.168.XX.XX   <none>           <none>
    2. 执行以下命令,确认正在挂载该OSS存储卷的所有Pod。

      其中<ns>为命名空间名称,<pvc-name>PVC名称。

    3. kubectl -n <ns> describe pvc <pvc-name>

      预期输出(包含User By):

      Used By:       oss-static-94849f647-4****
                     oss-static-94849f647-6****
                     oss-static-94849f647-h****
                     oss-static-94849f647-v****
                     oss-static-94849f647-x****
    4. 执行以下命令,获取通过csi-fuse-ossfs-xxxx挂载的Pod,即与csi-fuse-ossfs-xxxx运行在同一节点的Pod。

      kubectl -n <ns> get pod -owide | grep cn-beijing.192.168.XX.XX 

      预期输出:

      NAME                         READY   STATUS    RESTARTS   AGE     IP               NODE                         NOMINATED NODE   READINESS GATES
      oss-static-94849f647-4****   1/1     Running   0          10d     192.168.100.11   cn-beijing.192.168.100.3     <none>           <none>
      oss-static-94849f647-6****   1/1     Running   0          7m36s   192.168.100.18   cn-beijing.192.168.100.3     <none>           <none>
  2. 重启业务与ossfs进程。

    将应用Pod(上述示例中为oss-static-94849f647-4****和oss-static-94849f647-6****)通过kubectl scale等方式同时删除。在无应用Pod挂载时,csi-fuse-ossfs-xxxx Pod将自动被回收;恢复副本数后,将使用PV的新配置重新挂载,由CSI创建新的csi-fuse-ossfs-yyyy Pod。

    如果无法保证这些Pod能同时被删除(如删除Deployment, StatefulSet, DaemonSet管理的Pod均会立即触发重启),或Pod能容忍OSS读写失败:

    • CSI版本小于1.30.4时,您可以直接删除csi-fuse-ossfs-xxxx Pod,此时应用Pod内读写OSS将返回disconnected error

    • CSI版本大于等于1.30.4时,您可以执行以下操作:

      kubectl get volumeattachment | grep <pv-name> | grep cn-beijing.192.168.XX.XX 

      预期输出:

      csi-bd463c719189f858c2394608da7feb5af8f181704b77a46bbc219b**********   ossplugin.csi.alibabacloud.com    <pv-name>                   cn-beijing.192.168.XX.XX    true       12m

      直接删除该VolumeAttachment,此时应用Pod内读写OSS将返回disconnected error

    然后,逐个重启业务Pod,重启后的Pod将通过CSI新建的csi-fuse-ossfs-yyyy Pod恢复OSS读写。

扩容

实际存储容量超出OSS存储卷的配置时,是否需要扩容存储卷

OSS不限制Bucket或子路径的容量,且不提供容量配额功能,因此PV.spec.capacity字段和PVC.spec.resources.requests.storage字段的配置将被忽略,不会生效,您只需确保互相绑定的PVPVC的容量配置值保持一致即可。

实际存储容量超出配置时,不影响正常使用,您无需扩容存储卷。

卸载

OSS静态卷卸载失败,Pod一直处于Terminating状态

问题现象

OSS静态卷卸载失败,Pod一直处于Terminating状态。

问题原因

Pod删除时卡在Terminating的原因较多,可先借助kubelet日志定位。导致OSS存储卷卸载失败的常见原因如下:

  • 原因1:对应挂载点在节点上被占用,CSI存储插件无法正常unmount挂载点。

  • 原因2:PV中指定的OSS bucket或目录(path)被删除,无法判断当前挂载点状态。

解决方案

  • 原因1解决方案

    1. 在集群中执行以下命令,获取PodUID。

      替换以下<ns-name>和<pod-name>为您的业务实际值。

      kubectl -n <ns-name> get pod <pod-name> -ogo-template --template='{{.metadata.uid}}'

      预期输出:

      5fe0408b-e34a-497f-a302-f77049****
    2. 登录TerminatingPod所在的节点。

    3. 在节点上执行以下命令,查询当前是否有进程占用挂载点。

      lsof /var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~csi/<pv-name>/mount/

      若有输出,请确认并清理相关进程。

  • 原因2解决方案

    1. 登录OSS管理控制台

    2. 查询Bucket或目录是否被删除,若您使用了subpath方式挂载OSS存储卷,还需要确认subpath挂载目录是否被删除。

    3. 确认上由于删除目录导致的卸载失败,请参考以下操作处理。

      1. 在集群中执行以下命令,获取PodUID。

        替换以下<ns-name>和<pod-name>为您的业务实际值。

        kubectl -n <ns-name> get pod <pod-name> -ogo-template --template='{{.metadata.uid}}'

        预期输出:

        5fe0408b-e34a-497f-a302-f77049****
      2. 登录TerminatingPod所在的节点,在节点上执行以下命令,查询Pod相关的挂载点。

        mount | grep <pod-uid> | grep fuse.ossfs

        预期输出:

        ossfs on /var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~csi/<pv-name>/mount type fuse.ossfs (ro,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other)
        ossfs on /var/lib/kubelet/pods/<pod-uid>/volume-subpaths/<pv-name>/<container-name>/0 type fuse.ossfs (ro,relatime,user_id=0,group_id=0,allow_other)

        其中ossfs ontype之间路径为节点上的实际挂载点。

      3. 手动umount挂载点。

        umount /var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~csi/<pv-name>/mount
        umount /var/lib/kubelet/pods/<pod-uid>/volume-subpaths/<pv-name>/<container-name>/0
      4. 等待kubelet重试时正常回收,或者直接通过--force删除Pod。