为了满足Sandbox内大规模代码编译、高频读写海量小文件或运行I/O密集型数据分析任务等特定需求,函数计算引入阿里云自研的PolarFS分布式文件系统。PolarFS基于RDMA、NVMe以及用户态I/O栈等核心技术,突破传统存储架构的内核瓶颈,实现了微秒级访问延迟,为这类负载提供更优的I/O路径。
使用说明
挂载PolarFS文件系统功能目前处于内测阶段,如需试用请联系我们。
挂载PolarFS文件系统功能目前仅支持在中国香港地域下使用。
目前仅支持挂载基础版 PolarFS。
函数计算在同一地域下的同一个函数最多支持配置5个PolarFS文件系统。
前提条件
挂载PolarFS文件系统
登录函数计算控制台,在左侧导航栏,选择 。
在顶部菜单栏,选择地域,然后在函数列表页面,单击目标函数。
在函数详情页面,选择配置页签,单击高级配置右侧的编辑,在高级配置面板,找到存储选项,启用挂载PolarFS文件系统开关,按照以下操作配置完成后单击部署。
配置项名称
说明
示例
用户、用户组
设置文件的拥有者和相应的组,取值范围为[0, 65534],如果不填写,默认值均为0,即分别表示root用户和root用户组。
用户:10002
用户组:10002
PolarFS 文件系统
选择已创建的PolarFS文件系统,如需创建新的PolarFS文件系统,单击下方的创建新的文件系统,前往PolarFS控制台创建。
挂载PolarFS文件系统的本质是创建一个从函数计算实例的本地目录到PolarFS远端目录的映射关系。请按照下方说明设置远端目录和函数本地目录。
PolarFS实例
选择已有PolarFS实例。只能选择与函数网络配置中同一VPC网络和交换机绑定的PolarFS实例。
pfs-j6c160gg****
远端目录
远端目录是指位于PolarFS文件系统中的目录,若您配置的目录在远端NAS中不存在,函数计算将会为您自动创建该目录。目录所有者为上述配置的用户和用户组,权限等级为
777
。PolarFS 文件系统一:
/
/mnt/root
PolarFS 文件系统二:
/non_root_python
/polarfs
函数本地目录
函数本地目录是指函数实例中的目录,建议使用/home/ 、/mnt/ 或 /data/ 的子目录。不能使用通用的Linux和Unix系统目录及其子目录,例如/bin、/opt、/var或/dev等。
验证结果
1.准备访问PolarFS的函数代码
在函数详情页面,单击代码页签,在代码编辑器中编写代码,然后单击部署代码。
# -*- coding: utf-8 -*-
import logging
import json
import subprocess
import os
import stat
import pwd
def handler(event, context):
# evt = json.loads(event)
logger = logging.getLogger()
logger.info('hello world')
# 1. 使用 ls -l 命令列出 /mnt/root 下的目录
logger.info('=== 步骤1: 列出 /mnt/root 下的目录 ===')
try:
result = subprocess.run(['ls', '-l', '/mnt/root'], capture_output=True, text=True)
if result.returncode == 0:
logger.info(f'/mnt/root 目录内容:\n{result.stdout}')
else:
logger.error(f'执行 ls -l /mnt/root 失败: {result.stderr}')
except Exception as e:
logger.error(f'执行 ls -l 命令时发生错误: {str(e)}')
# 2. 校验 /mnt/root/non_root_python 是一个目录,uid 和 gid 均为 10002,mode 为 777
logger.info('=== 步骤2: 校验 /mnt/root/non_root_python ===')
root_dir_path = '/mnt/root/non_root_python'
try:
if os.path.exists(root_dir_path) and os.path.isdir(root_dir_path):
logger.info(f'{root_dir_path} 存在且为目录')
stat_info = os.stat(root_dir_path)
uid = stat_info.st_uid
gid = stat_info.st_gid
mode = stat.S_IMODE(stat_info.st_mode)
logger.info(f'{root_dir_path} - UID: {uid}, GID: {gid}, Mode: {oct(mode)}')
if uid == 10002 and gid == 10002:
logger.info('UID 和 GID 都是 10002')
else:
logger.warning(f'UID 或 GID 不是 10002: UID={uid}, GID={gid}')
if mode == 0o777:
logger.info('目录权限为 777')
else:
logger.warning(f'目录权限不是 777: {oct(mode)}')
else:
logger.error(f'{root_dir_path} 不存在或不是目录')
except Exception as e:
logger.error(f'校验 {root_dir_path} 时发生错误: {str(e)}')
# 3. 校验主进程的 uid 和 gid 均为 10002
logger.info('=== 步骤3: 校验主进程的 UID 和 GID ===')
try:
current_uid = os.getuid()
current_gid = os.getgid()
logger.info(f'当前进程 UID: {current_uid}, GID: {current_gid}')
if current_uid == 10002 and current_gid == 10002:
logger.info('主进程 UID 和 GID 都是 10002')
else:
logger.warning(f'主进程 UID 或 GID 不是 10002: UID={current_uid}, GID={current_gid}')
except Exception as e:
logger.error(f'校验主进程 UID/GID 时发生错误: {str(e)}')
# 4. 在 /mnt/subdir 下创建子目录和子文件后,在 /mnt/root/non_root_python 中能看到
logger.info('=== 步骤4: 以用户 10002 身份创建文件和目录 ===')
subdir_path = '/mnt/subdir'
try:
# 确保 /mnt/subdir 目录存在
os.makedirs(subdir_path, exist_ok=True)
# 创建测试文件和目录
test_file_path = os.path.join(subdir_path, 'user10002_test_file.txt')
test_dir_path = os.path.join(subdir_path, 'user10002_test_dir')
with open(test_file_path, 'w') as f:
f.write('test content as user 10002')
os.makedirs(test_dir_path, exist_ok=True)
logger.info('以用户 10002 身份创建测试文件和目录成功')
# 检查在 /mnt/root/non_root_python 中是否能看到
root_file_path = os.path.join(root_dir_path, 'user10002_test_file.txt')
root_dir_check_path = os.path.join(root_dir_path, 'user10002_test_dir')
if os.path.exists(root_file_path):
logger.info('在 /mnt/root/non_root_python 中能看到创建的文件')
file_stat = os.stat(root_file_path)
file_uid = file_stat.st_uid
file_gid = file_stat.st_gid
file_mode = stat.S_IMODE(file_stat.st_mode)
logger.info(f'文件 - UID: {file_uid}, GID: {file_gid}, Mode: {oct(file_mode)}')
if file_uid == 10002 and file_gid == 10002:
logger.info('文件 UID 和 GID 都是 10002')
else:
logger.warning(f'文件 UID 或 GID 不是 10002: UID={file_uid}, GID={file_gid}')
if file_mode == 0o644:
logger.info('文件权限为 644')
else:
logger.warning(f'文件权限不是 644: {oct(file_mode)}')
else:
logger.warning('在 /mnt/root/non_root_python 中看不到创建的文件')
if os.path.exists(root_dir_check_path):
logger.info('在 /mnt/root/non_root_python 中能看到创建的目录')
dir_stat = os.stat(root_dir_check_path)
dir_uid = dir_stat.st_uid
dir_gid = dir_stat.st_gid
dir_mode = stat.S_IMODE(dir_stat.st_mode)
logger.info(f'目录 - UID: {dir_uid}, GID: {dir_gid}, Mode: {oct(dir_mode)}')
if dir_uid == 10002 and dir_gid == 10002:
logger.info('目录 UID 和 GID 都是 10002')
else:
logger.warning(f'目录 UID 或 GID 不是 10002: UID={dir_uid}, GID={dir_gid}')
if dir_mode == 0o755:
logger.info('目录权限为 755')
else:
logger.warning(f'目录权限不是 755: {oct(dir_mode)}')
else:
logger.warning('在 /mnt/root/non_root_python 中看不到创建的目录')
except Exception as e:
logger.error(f'以用户 10002 身份创建文件/目录时发生错误: {str(e)}')
# 5. 将主进程的 gid 切换为 10001
logger.info('=== 步骤5: 将主进程的 GID 切换为 10001 ===')
try:
os.setgid(10001)
logger.info('成功设置进程 GID 为 10001')
new_gid = os.getgid()
logger.info(f'设置后进程 GID: {new_gid}')
except PermissionError:
logger.warning('权限不足,无法设置 GID 为 10001')
except OSError as e:
logger.error(f'设置 GID 时发生系统错误: {str(e)}')
except Exception as e:
logger.error(f'设置进程 GID 时发生错误: {str(e)}')
# 6. 将主进程的 uid 切换为 10001
logger.info('=== 步骤6: 将主进程的 UID 切换为 10001 ===')
try:
os.setuid(10001)
logger.info('成功设置进程 UID 为 10001')
new_uid = os.getuid()
logger.info(f'设置后进程 UID: {new_uid}')
except PermissionError:
logger.warning('权限不足,无法设置 UID 为 10001')
except OSError as e:
logger.error(f'设置 UID 时发生系统错误: {str(e)}')
except Exception as e:
logger.error(f'设置进程 UID 时发生错误: {str(e)}')
# 7. 在 /mnt/subdir 下创建子目录和子文件后,在 /mnt/root/non_root_python 中能看到
logger.info('=== 步骤7: 以用户 10001 身份创建文件和目录 ===')
try:
# 创建测试文件和目录
test_file_path = os.path.join(subdir_path, 'user10001_test_file.txt')
test_dir_path = os.path.join(subdir_path, 'user10001_test_dir')
with open(test_file_path, 'w') as f:
f.write('test content as user 10001')
os.makedirs(test_dir_path, exist_ok=True)
logger.info('以用户 10001 身份创建测试文件和目录成功')
# 检查在 /mnt/root/non_root_python 中是否能看到
root_file_path = os.path.join(root_dir_path, 'user10001_test_file.txt')
root_dir_check_path = os.path.join(root_dir_path, 'user10001_test_dir')
if os.path.exists(root_file_path):
logger.info('在 /mnt/root/non_root_python 中能看到创建的文件')
file_stat = os.stat(root_file_path)
file_uid = file_stat.st_uid
file_gid = file_stat.st_gid
file_mode = stat.S_IMODE(file_stat.st_mode)
logger.info(f'文件 - UID: {file_uid}, GID: {file_gid}, Mode: {oct(file_mode)}')
if file_uid == 10002 and file_gid == 10002:
logger.info('文件 UID 和 GID 都是 10002')
else:
logger.warning(f'文件 UID 或 GID 不是 10002: UID={file_uid}, GID={file_gid}')
if file_mode == 0o644:
logger.info('文件权限为 644')
else:
logger.warning(f'文件权限不是 644: {oct(file_mode)}')
else:
logger.warning('在 /mnt/root/non_root_python 中看不到创建的文件')
if os.path.exists(root_dir_check_path):
logger.info('在 /mnt/root/non_root_python 中能看到创建的目录')
dir_stat = os.stat(root_dir_check_path)
dir_uid = dir_stat.st_uid
dir_gid = dir_stat.st_gid
dir_mode = stat.S_IMODE(dir_stat.st_mode)
logger.info(f'目录 - UID: {dir_uid}, GID: {dir_gid}, Mode: {oct(dir_mode)}')
if dir_uid == 10002 and dir_gid == 10002:
logger.info('目录 UID 和 GID 都是 10002')
else:
logger.warning(f'目录 UID 或 GID 不是 10002: UID={dir_uid}, GID={dir_gid}')
if dir_mode == 0o755:
logger.info('目录权限为 755')
else:
logger.warning(f'目录权限不是 755: {oct(dir_mode)}')
else:
logger.warning('在 /mnt/root/non_root_python 中看不到创建的目录')
except Exception as e:
logger.error(f'以用户 10001 身份创建文件/目录时发生错误: {str(e)}')
return 'hello world'
本文以Python事件函数代码为例,在代码中实现对PolarFS文件系统目录的读取,以及目录所有者和权限查询,并尝试切换用户。
2.查看结果
代码部署成功后,单击代码页签的测试函数。执行成功后,您可以选择
查看执行结果。输出示例如下:
FunctionCompute python3 runtime inited.
FC Invoke Start RequestId: 1-68e9ecf8-14a2ddf2-fed64814f73a
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] hello world
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] === 步骤1: 列出 /mnt/root 下的目录 ===
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] /mnt/root 目录内容:
total 32
drwxrwxrwx 2 99 nogroup 4096 Sep 23 12:36 10000_dir
drwxrwxrwx 2 user10001 10001 4096 Sep 24 01:37 10001_dir
drwxrwxrwx 4 user10002 10002 4096 Sep 25 02:46 non_root_image
drwxrwxrwx 4 user10002 10002 4096 Sep 25 02:30 non_root_python
drwxrwxrwx 4 root root 4096 Sep 25 02:24 root_dir
drwxrwxrwx 4 root root 4096 Sep 25 02:25 root_image
drwxrwxrwx 2 99 nogroup 4096 Sep 23 11:54 share
drwxrwxrwx 2 nobody nogroup 4096 Sep 23 12:11 testdir
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] === 步骤2: 校验 /mnt/root/non_root_python ===
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] /mnt/root/non_root_python 存在且为目录
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] /mnt/root/non_root_python - UID: 10002, GID: 10002, Mode: 0o777
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] UID 和 GID 都是 10002
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] 目录权限为 777
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] === 步骤3: 校验主进程的 UID 和 GID ===
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] 当前进程 UID: 10002, GID: 10002
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] 主进程 UID 和 GID 都是 10002
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] === 步骤4: 以用户 10002 身份创建文件和目录 ===
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [ERROR] 以用户 10002 身份创建文件/目录时发生错误: [Errno 13] Permission denied: '/mnt/subdir'
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] === 步骤5: 将主进程的 GID 切换为 10001 ===
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [WARNING] 权限不足,无法设置 GID 为 10001
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] === 步骤6: 将主进程的 UID 切换为 10001 ===
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [WARNING] 权限不足,无法设置 UID 为 10001
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [INFO] === 步骤7: 以用户 10001 身份创建文件和目录 ===
2025-10-11 13:37:06 1-68e9ecf8-14a2ddf2-fed64814f73a [ERROR] 以用户 10001 身份创建文件/目录时发生错误: [Errno 2] No such file or directory: '/mnt/subdir/user10001_test_file.txt'
FC Invoke End RequestId: 1-68e9ecf8-14a2ddf2-fed64814f73a
结果分析:
根据步骤1执行结果,确认函数已成功读取PolarFS文件系统下
/mnt/root
目录内容。根据步骤2~4执行结果,确认
/mnt/root
目录的拥有者为挂载PolarFS文件系统时设置的用户,以及权限为777。根据步骤5~7执行结果,确认切换用户身份的局限性,在实际多租户场景中,只能通过会话隔离与存储粘性实现安全隔离,而非进程级UID切换。
相关文档
函数计算支持的存储类型包括PolarFS、文件存储NAS、对象存储OSS、临时硬盘和层,如果您希望了解这些存储类型的适用场景及差异,请参见函数存储选型。
如果您需要存储大量图片、视频和文档等非结构化数据,建议您挂载OSS对象存储系统来实现。更多信息,请参见配置OSS对象存储。
您还可以使用Serverless Devs为函数挂载PolarFS文件系统。具体操作,请参见Serverless Devs常用命令。