如何配置 Docker 权限以便容器以非 root 用户身份写入卷?

如何配置 Docker 权限以便容器以非 root 用户身份写入卷?

我将 Web 应用程序部署在几个 Docker 容器中,对于文件上传,我需要能够写入文件系统。该应用程序通过在同一台服务器上运行的 Nginx(但不在容器中)进行代理,Nginx 将上传的文件传递给用户。

我遇到的问题与权限有关 - Docker 容器默认运行root,但如果我的容器以 root 身份写入文件,则使用该用户的 Nginx 无法读取该文件www-data

我正在使用Distroless 容器并从其“非根”变体开始构建,其描述如下:The "nonroot" images are configured to default to executing as a normal user account called "nonroot", with user ID 65532.

在我的服务器上,我添加了一个名为 的用户nonroot,给他们 uid 65532 并将其添加到www-data组中。我可以su向该用户发送消息并将文件写入公共文件夹。

在我的docker-compose我有以下内容:

services:
   my-api:
      image: my-api
      ports:
         - 8080:8080
      user: 65532:65532
      volumes: 
         - /var/www/my-web-application/public-files:/public-files

容器启动正确,其他方面运行良好,但当我尝试上传文件时,我从 API 收到以下消息:Failed to create /public-files/user/1234: mkdir /public-files/user/1234: permission denied

我的理解是,容器内部和外部的相应用户应该自动匹配(因此容器中的 uid 65532 应该被视为容器外部的 uid 65532)但这似乎并没有发生。

如果我不使用nonroot该容器的版本并且代码以 root 身份运行,它可以成功写入卷,但它以 root 身份写入,然后 Nginx 无法读取它。

为了能够以 Nginx 提供服务的方式从我的 Docker 容器写入文件系统,我需要进行哪些更改?

编辑:经过进一步调查,似乎我尝试使用此配置可​​能无法实现 - Docker 容器创建的任何文件都将明确使用权限创建65532:65532。虽然我可以在文件夹外部以 uid 为 65532 的用户身份创建文件,但这是因为该用户对这些文件夹具有组权限。直接在容器内部设置用户和组权限意味着即使配置了权限以便 Nginx 可以读取而 docker 可以写入,Nginx 也无法读取 Docker 写入的内容,因为它同时设置了用户和组。如果我想以这种方式执行操作,似乎我必须构建自己的容器版本,noroot其 uid/gid 与www-data服务器上的用户匹配,这与我旨在通过容器化促进的可转移性不符。

我认为解决问题的另一种方法是将我的 Nginx 代理放在引用同一卷的非根容器中 - 这样应该可以正常工作,尽管在我的测试服务器上将 nginx 放在 nginx 后面感觉有点愚蠢,但我认为我可以使用该容器作为面向用户的生产 HTTP 服务器。

如果有其他方法可以做到这一点,我很乐意听到,但我认为我现在已经了解了它不起作用的原因。

答案1

我的理解是,容器内部和外部的相应用户应该自动匹配,但这似乎并没有发生。

您的理解不正确。如果您希望绑定挂载可由具有 id 的用户写入65532,那么您需要在启动容器之前确保这些权限(例如,通过运行chown 65532 /var/www/my-web-application/public-files)。

有几种方法可以管理事情,从而减少这个问题的发生。

一个选项是将应用程序的读写数据和只读数据分开。如果/var/www/my-web-application/public-files包含预先存在的内容,则修改应用程序以从中读取内容/public-files,但数据例如/home/nonroot。给定一个像这样的 Compose 文件:

volumes:
  app-data:

services:
   my-api:
      image: my-api
      ports:
         - 8080:8080
      volumes: 
        - /var/www/my-web-application/public-files:/public-files
        - app-data:/home/nonroot

该目录/home/nonroot将可由 uid 写入65532,因为当您在目录上安装卷时,它会继承该目录的所有权。


你不需要使用/home/nonroot;我选择它只是因为它已经存在并且具有正确的所有权。您可以在 Dockerfile 中创建一个备用目录,只要确保它由适当的 uid 拥有即可。

下面是一个示例,我们/home/nonroot使用多阶段构建将其复制到新位置:

FROM docker.io/debian:12 AS build
FROM gcr.io/distroless/static-debian12:nonroot AS nonroot

FROM gcr.io/distroless/static-debian12:nonroot

COPY --from=nonroot /home /var/

COPY --from=build /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
COPY --from=build /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libpcre2-8.so.0 /lib/x86_64-linux-gnu/libselinux.so.1 /lib/
COPY --from=build /bin/dash /usr/bin/id /usr/bin/ls /usr/bin/sleep /bin

CMD ["/bin/sh"]

这让我们:

$ docker run -it --rm my-api ls -ld /var/nonroot /home/nonroot
drwx------. 1 65532 65532 0 Jan  1  1970 /home/nonroot
drwx------. 1 65532 65532 0 Jan  1  1970 /var/nonroot

相关内容