OSS存储卷FAQ

本文为您介绍OSS存储卷常见问题的处理方法。

类型

问题

挂载问题

使用问题

卸载问题

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

控制台检测失败问题

其他

OSS存储卷挂载时间延长

问题现象

OSS存储卷挂载时间延长。

问题原因

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

  • 在PV及PVC模板中配置的参数AccessModes值为ReadWriteOnce

  • 在应用模板中配置了securityContext.fsgroup参数。

解决方案

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

    参数

    说明

    uid

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

    gid

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

    umask

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

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

  • 对于1.20及之后版本的Kubernetes集群,除了上述解决方法外,也可通过将fsGroupChangePolicy配置为OnRootMismatch,这时只有在首次启动时才会执行chmodchown操作,导致存在挂载时间延长的问题,后续挂载OSS存储卷时挂载时间将恢复正常。关于fsGroupChangePolicy参数的更多信息,请参见为Pod或容器配置安全性上下文

OSS存储挂载权限问题

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

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

问题原因

OSS默认使用Linux的root用户进行挂载,权限为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挂载目录下子目录及文件的UID和GID,使其与容器进程用户一致。

参数

说明

uid

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

gid

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

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

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

问题原因

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

解决方案

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

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

问题原因

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

解决方案

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

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

问题原因

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

解决方案

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

OSS存储卷挂载失败

问题现象

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

问题原因

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

    重要

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

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

  • 原因3: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未正常拉起或被意外删除。

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

  • 原因5:若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、xml2等ossfs运行需要的动态库,或变更过OpenSSL的默认版本。

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

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

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

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

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

解决方案

  • 原因1解决方案:

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

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

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

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

  • 原因2解决方案:

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

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

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

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

      重要

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

  • 原因3解决方案:

    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 provisioner与CSI plugin均升级到1.30.4及以上后,重启业务Pod触发重新挂载,并确认OSSFS Pod有正常创建流程。

  • 原因4解决方案:

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

    2. 执行以下命令,尝试重启对应节点上的csi-plugin后,查看Pod是否能正常启动。以下代码中csi-plugin-****为节点所在csi-plugin的Pod名称。

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

      ls /etc/csi-tool

      部分预期输出:

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

        rpm -i /etc/csi-tool/ossfs_<ossfsVer>_<ossfsArch>_x86_64.rpm
      • 若输出中不存在OSSFS的RPM包,请提交工单处理。

  • 原因5解决方案:

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

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

      kubectl -n kube-system delete pod -l app=csi-plugin
    • 建议您升级CSI至1.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
  • 原因6解决方案:

    • 参考本问题原因1,确认子目录存在。

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

  • 原因7解决方案:

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

  • 原因8解决方案:

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

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

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

假设需要挂载的OSS中bucket:/subpath下的a.txt和b.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 # 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存储卷的基本使用说明请参考使用OSS静态存储卷

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

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

OSS存储卷访问Bucket过慢

问题现象

OSS存储卷访问Bucket过慢。

问题原因

  • 原因1:OSS对象存储本身没有文件数限制,但当文件数量大于1000时,会使OSS的FUSE访问元数据过多,导致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静态卷PV的otherOpts字段中增加-o listobjectsv2来解决。

原因3解决方案:

您需要修改存储类型或者解冻文件

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

问题现象

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

问题原因

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

解决方案

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

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

问题现象

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

问题原因

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

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

解决方案

原因1解决方案:

通过HeadObjectstat(查看Bucket和Object信息)获取目录对象元信息,目录对象需要以"/"结尾(例如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静态卷PV的otherOpts字段中增加-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的操作,进程PID为1636611。

    ---
    type=PROCTITLE msg=audit(2023年09月22日 15:09:26.244:291) : proctitle=updatedb
    type=PATH msg=audit(2023年09月22日 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(2023年09月22日 15:09:26.244:291) : cwd=/subdir1/subdir2
    type=SYSCALL msg=audit(2023年09月22日 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.6和1.28.1版本的组件对Content-Type配置存在兼容性问题。若使用了相关版本,请升级CSI至最新版本。更多信息,请参见【组件公告】关于1.26.6和1.28.1版本的csi-plugin和csi-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存储卷。

如何在RRSA鉴权方式中使用指定的ARNs或ServiceAccount?

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

此时,您只需要在PV中通过roleName配置项指定RAM角色名称,即可由CSI存储插件获取默认的Role ARN及OIDC 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-开头。

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

问题现象

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

问题原因

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

解决方案

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

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

问题现象

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

问题原因

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

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

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

解决方案

原因1解决方案

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

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

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

    预期输出:

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

  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. 在集群中执行以下命令,获取Pod的UID。

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

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

      预期输出:

      5fe0408b-e34a-497f-a302-f77049****
    2. 登录Terminating的Pod所在的节点,在节点上执行以下命令,查询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。

  4. 其他卸载失败问题,请提交工单咨询。

控制台检测长期卡住,或失败无信息透出,或显示unknown error

问题现象

检测长期卡住,或失败无信息透出,或显示unknown error。

问题原因

若检测长期卡在进行中状态,基本判断为网络原因。对于其他未知错误,您可以通过查询日志,或手动通过ossutil进行原因定位。

解决方案

您可以通过日志和ossutil工具定位具体问题。

通过日志定位具体问题

  1. 执行以下命令,找到执行检测任务的Pod。

    • osssecret-namespace:保密字典所在命名空间。

    • pv-name:PV的名称。

    kubectl -n <osssecret-namespace> get pod | grep <pv-name>-check

    预期输出:

    <pv-name>-check-xxxxx
  2. 执行以下命令,查询失败原因。

    kubectl -n <osssecret-namespace> logs -f <pv-name>-check-xxxxx

    预期输出:

    check ossutil
    endpoint: oss-<region-id>-internal.aliyuncs.com
    bucket: <bucket-name>
    path: <path>
    Error: oss: service returned error: StatusCode=403, ErrorCode=InvalidAccessKeyId, ErrorMessage="The OSS Access Key Id you provided does not exist in our records.", RequestId=65267325110A0C3130B7071C, Ec=0002-00000901, Bucket=<bucket-name>, Object=<path>

通过ossutil工具定位具体问题

如果您的相关Pod已被删除,您可以通过ossutil工具复现检测,定位具体问题。

OSS访问检测通过stat(查看Bucket和Object信息)实现,您可以在集群内任意节点上安装ossutil并执行以下指令复现。

ossutil -e "<endpoint>" -i "<accessKeyID>" -k "<accessKeySecret>" stat oss://"<bucket><path>"

参数

说明

endpoint

  • 若选择私有域名,取值为oss-<region-id>-internal.aliyuncs.com

  • 若选择公有域名,取值为oss-<region-id>.aliyuncs.com

accessKeyID

保密字典中的AccessKeyID。

accessKeySecret

保密字典中的AccessKeySecret。

bucket

Bucket ID。

path

路径。填写的路径需要以"/"结尾。

例如,如果您在创建如下的存储卷的配置信息,则您需要执行的命令如下。image.png

ossutil -e "oss-<region-id>-internal.aliyuncs.com" -i "<accessKeyID>" -k "<accessKeySecret>" stat oss://"cnfs-oss-xxx-xxx/xx/"

网络问题:connection timed out

问题现象

错误信息为connection timed out。

问题原因

访问OSS Bucket超时,可能的超时原因如下

  • 选择的Bucket与集群不在同一地域时,选择私有域名,导致访问不通。

  • 选择公有域名,但集群无公网访问能力,导致访问不通。

解决方案

  • 重建PV,并选择公有域名。

  • 若您的集群与Bucket在同一地域,可重建PV并选择私有域名。否则,您可以检查安全组、网络等相关配置,修复后再重建PV。

权限问题:错误码StatusCode=403

问题现象

错误信息为service returned error: StatusCode=403

问题原因

挂载OSS存储卷时,AccessKey至少需要Bucket的读权限,当前权限不足。

  • StatusCode=403, ErrorCode=AccessDenied, ErrorMessage="You do not have read acl permission on this object." ,提供的AccessKey权限不足。

  • StatusCode=403, ErrorCode=InvalidAccessKeyId, ErrorMessage="The OSS Access Key Id you provided does not exist in our records." ,提供的AccessKey不存在。

  • StatusCode=403, ErrorCode=SignatureDoesNotMatch, ErrorMessage="The request signature we calculated does not match the signature you provided. Check your key and signing method." ,提供的AccessKey可能存在拼写错误。

解决方案

确认AccessKey已存在、无拼写错误,且至少拥有对该Bucket的读权限。

Bucket或目录对象不存在:错误码StatusCode=404

问题现象

错误信息为service returned error: StatusCode=404

问题原因

OSS静态存储卷不支持挂载到不存在的Bucket或子目录中,需要预先手动创建Bucket。

  • StatusCode=404, ErrorCode=NoSuchBucket, ErrorMessage="The specified bucket does not exist.",选择的Bucket不存在。

  • StatusCode=404, ErrorCode=NoSuchKey, ErrorMessage="The specified key does not exist.",选择的子目录对象不存在。

    重要

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

解决方案

通过ossutil、SDK、OSS控制台等工具手动创建缺失的Bucket或子目录,然后重建PV。

其他OSS返回错误码

问题现象

错误信息为service returned error: StatusCode=xxx

问题原因

当访问OSS出现错误时,OSS会返回StatusCode、ErrorCode、ErrorMessage等信息,方便您定位并解决问题。

解决方案

当您遇到其他OSS的StatusCode或ErrorCode时,请参见HTTP错误码解决。

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独享挂载的需求,请提交工单

如果您期望恢复到容器化前的独享挂载,请在创建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

共享挂载方式下,如何重启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的记录

调用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错误码

使用subpath或subpathExpr方式挂载OSS存储卷异常

问题现象

使用subpath或subpathExpr方式挂载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时,一直处在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非root用户运行的业务容器没有/path/subpath/in/oss/目录下文件的权限(默认为640)。subpath方式挂载OSS存储卷时,ossfs在OSS服务端实际的挂载目录为PV中定义的path目录,即上述示例中的/path,而非/path/subpath/in/oss/。配置allow_other或mp_umask挂载项仅对/path目录生效,/path/subpath/in/oss/目录作为子目录仍默认为640。

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

解决方案

原因1解决方案

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

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

原因2解决方案通过umask配置项修改子目录默认权限,例如-o umask=000将默认权限修改为777。

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

OSS存储卷的容量配置是否生效?实际存储超出此配置时是否需要扩容存储卷?

OSS本身不限制Bucket或子路径的容量,也未提供容量限额功能。因此pv.spec.capacitypvc.spec.resources.requests.storage配置均不起作用。您只需保证需要绑定PV、PVC配置的容量相等即可。

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