有没有办法在运行时重新映射用户 ID?



我有一个容器,它创建了一个默认用户,该用户具有UID 1000。

在我的 Dockerfile 中,我正在创建用户:

RUN groupadd sudo && useradd -G sudo -u 1000 -U ${RUST_USER}

现在,当我运行容器时,除非我当前用户正好具有 UID 1000,否则卷权限会搞砸:

docker run -it --rm naftulikay/circleci-lambda-rust:latest 
-v $PWD:/home/circleci/project 
.local/bin/build

在运行时:

error: failed to write /home/circleci/project/Cargo.lock
Caused by:
failed to open: /home/circleci/project/Cargo.lock
Caused by:
Permission denied (os error 13)
Exited with code 101

这是因为容器内的用户具有 UID 1000,容器外部的用户具有 UID 1001。

我想,由于这已经是内核命名空间中的所有虚拟映射,因此可以将内部 UID 从容器映射到外部 UID。

是否有命令行选项允许我根据需要动态重新映射 UID?

已经请求了容器和主机之间 UID 的动态映射,但我相信它需要内核和文件系统更改才能实现。在此之前,您有以下几种选择:

  1. 使主机与容器匹配。对于主机卷,这并不容易。但是对于命名卷,docker 会将卷初始化为映像的内容,包括目录和文件权限,使其相当无缝。您需要调整工作流,使其不再能够直接访问卷中的数据,而是使用容器来访问数据。

  2. 以主机 uid 身份运行容器。您可以将/etc/passwd 作为主机卷挂载到容器中,并且可以以任何 uid 的形式启动容器(在撰写文件中使用docker run -uuser条目)。唯一的缺点是映像中的文件可能已经归用于构建映像的 uid 所有,因此它们要么需要全局可读(可能是可写的)要么移动到卷中。

  3. 众所周知,我以 root 身份启动我的容器,并使用一个入口点,该入口点根据卷挂载中的文件权限更正 uid/gid 不匹配。然后,我的入口点的最后一步是将权限删除到新 uid 的权限并执行容器应用程序。有关执行此操作的入口点的示例,请参阅我的 docker 示例中的这个 jenkins,它将 jenkins gid 与从主机挂载的 docker 套接字的 gid 相匹配。

就像 BMitch 说的那样,根据你的系统,你有很多选择,但请记住,你可能必须重新启动正在运行的进程(例如 php-fpm)

有关如何实现此目的的一些示例:(您可以使用以下方法在容器外部运行命令:docker container exec ...

  • 示例 1:

usermod -g 1007 www-data

它将用户 www-data 的 uid 更新为 1007

  • 示例 2:

deluser www-data

adduser -u 1007 -D -S -G www-data www-data

它将删除用户 www-data 并使用 uid 1007 重新创建它

  • 获取 pid 并重新启动过程

要重新启动正在运行的进程,例如 php-fpm,您可以这样做:

首先使用以下命令之一获取 pid:

pidof php-fpm

ps -ef | grep -v grep | grep php-fpm | awk '{print $2}'

find /proc -mindepth 2 -maxdepth 2 -name exe -lname '*/php-fpm' -printf %h\n 2>/dev/null | sed s+^/proc/++

然后使用您之前获得的 pid 重新启动进程(如果您的进程支持 USR2 信号):

kill -USR2 pid<-- 将 pid 替换为之前获得的数字

我发现最简单的方法是更新主机或构建容器,知道正确的 pid(如果您使用不同的环境,并不总是可行的)

最新更新