批量修改 AWS S3 挂载目录下文件权限

更新日期: 2026-01-21 阅读次数: 23 字数: 1608 分类: CDN

先交代一下背景,在服务器上挂载了一个 S3 类似的对象存储,用于存放网站的图片。 现在需要把这个挂载目录下的所有文件权限改为 644。但是执行命令:

find . -maxdepth 1 -type f -print0 | xargs -0 sudo chmod 644

服务器的系统负载很高,而 CPU 和内存占用都很低。这个目录下有 8 万多个文件。

为何系统负载飙高

S3 是对象存储,不是真正的硬盘。当执行 chmod 时,挂载工具(如 s3fsgoofys)必须为每个文件发送一个网络请求(通常是 COPY 请求以更新元数据)。8 万个文件意味着 8 万次网络往返。 CPU 在等待网络响应,所以负载(Load Average)很高,但并没在运算。

解决方案

最佳的解决方案是修改挂载参数。即,修改 /etc/fstab 中的挂载选项,添加 umask=022,并指定 uid 和 gid,这样所有文件在 Linux 看来都是 644。

由于,我还在 docker 中映射了这个目录,所以需要先停掉相关的 docker 容器,然后卸载目录,修改挂载参数,重新挂载,最后再启动 docker 容器。

停掉相关 Docker

docker compose stop xxx

卸载挂载的目录

umount /var/www/some_directory

确认服务器用户的 uid gid

例如,如果是 www 用户:

> id www
uid=1000(www) gid=1000(www) groups=1000(www),27(sudo),100(users)

修改挂载参数

由于使用的是类似 S3 存储的 Linode Object Storage,所以挂载参数如下:

xxx.sunzhongwei.com /var/www/some_directory fuse.s3fs _netdev,allow_other,umask=022,uid=1000,gid=1000,use_path_request_style,nonempty,url=https://us-east-1.linodeobjects.com/ 0 0

umask 的全称是 User File-Creation Mask(用户文件创建掩码)。它的作用是:规定“不允许”出现哪些权限。

在 Linux 中,权限是通过从“满权限”中减去 umask 的值来计算的。

执行重新挂载

mount -a

参考:s3fs-fuse 将 Linode Object Storage 挂载到 Ubuntu Server 本地文件系统

启动相关 Docker

docker compose start xxx

确认

> ls -lah /var/www/some_directory
total 543K
drwxr-xr-x 1 www www    0 Jan 16 06:08  .
drwxr-xr-x 1 www www    0 Dec 13  2024  ..
-rwxr-xr-x 1 www www 330K Jan 16 06:11  a.jpg
-rwxr-xr-x 1 www www 214K Jan 17 03:04  b.jpg

到此搞定。但是,我还是有一些其他疑问的,所以继续下面的整理。

新建文件的权限

设置了 umask=022 后,如果是 root 用户在这个 s3 目录下新建一个文件,文件的所有人是否会改变。

umask 只管“权限数字”,不管“所有人(Owner)”。 但是,在 S3 挂载(FUSE)的环境下,新建文件的所有人到底是谁,取决于你挂载时的参数设置,而不是 umask。

当挂载时指定了固定的 uid 和 gid,即在挂载命令或 /etc/fstab 中设置了 -o uid=1000,gid=1000。

无论你用 root 还是普通用户新建文件,在这个目录下看到的文件的所有人永远是 UID 1000 的用户。

原因: FUSE 驱动会“劫持”所有权信息。即使 root 写入了对象,挂载工具也会在显示时把文件强行显示为 UID 1000。

修改挂载参数对 Docker 容器的影响

修改挂载参数后重新挂载, 如果这个目录也挂载到了某个 docker 容器中,重新挂载是否会影响 docker 容器的运行?

重新挂载(Unmount & Remount)宿主机的目录,一定会影响正在运行的 Docker 容器。

如果不重启容器,容器内部通常会看到一个空目录或者遇到 Stale file handle(失效的文件句柄) 错误。

Docker 的容器卷挂载(Bind Mount)在容器启动时,是基于宿主机路径的 Inode(索引节点) 或当时的挂载点建立的连接。

断开连接: 当在宿主机执行 umount 时,宿主机内核会撤销该路径的挂载。虽然容器还在运行,但它原本引用的文件系统指针已经“断了”。

无法自动跟随: 当在宿主机执行新的 mount 后,虽然路径没变,但宿主机内核为它分配了新的挂载 ID。已经运行的容器不会自动同步这个新挂载,它会继续盯着那个已经变成空目录的原始挂载点。

对于 s3 的文件,在服务器本地执行 chmod 后,权限信息是保存在哪里?

在 S3 挂载的目录下执行 chmod,权限信息并不存在于一个类似 Linux Inode 的本地索引中,而是直接保存在 S3 对象的元数据(Metadata) 里。

如果使用的是最常用的 s3fs,权限信息被存储在 S3 对象的 HTTP 自定义元数据头中。

存储位置: AWS S3 对象的 Metadata 部分。

具体的 Key:

  • x-amz-meta-mode: 存储权限位(如 33188 代表 644)。
  • x-amz-meta-uid: 存储所有者的 UID。
  • x-amz-meta-gid: 存储组的 GID。

如果你登录 AWS 控制台,随便找一个文件点击“属性(Properties)”,在“元数据”一栏就能看到这些以 x-amz-meta- 开头的参数。

关于作者 🌱

我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式