了解 Mac 上 Docker Desktop 的权限要求

此页面包含在 Mac 上运行和安装 Docker Desktop 所需的权限要求信息。

它还明确了以 root 身份运行容器,而不是在主机上拥有 root 权限。

权限要求

Docker Desktop for Mac 以非特权用户身份运行。然而,Docker Desktop 需要某些功能来执行一组有限的特权配置,例如:

  • 安装符号链接/usr/local/bin中。
  • 绑定特权端口(小于 1024 的端口)。所谓的“特权端口”通常不被用作安全边界,但操作系统仍然会阻止非特权进程绑定这些端口,从而导致类似 docker run -p 127.0.0.1:80:80 docker/getting-started 的命令失败。
  • 确保已定义 localhostkubernetes.docker.internal(位于 /etc/hosts 中)。某些旧的 macOS 安装在 /etc/hosts 中缺少 localhost,这会导致 Docker 失败。定义 DNS 名称 kubernetes.docker.internal 可使 Docker 与容器共享 Kubernetes 上下文。
  • 安全地缓存对开发者只读的注册表访问管理策略。

根据所使用的 Docker Desktop for Mac 版本,特权访问权限可能在安装期间、首次运行时授予,或仅在需要时授予。


从 4.18 版本及更高版本开始,Docker Desktop for Mac 在安装过程中对启用的功能提供了更大的控制权。

首次启动适用于 Mac 的 Docker Desktop 时,会显示一个安装窗口,您可以选择使用适用于大多数开发人员的默认设置(需要授予特权访问权限),或使用高级设置。

如果您在具有更高安全要求的环境中工作(例如禁止本地管理员访问),则可以使用高级设置来免除授予特权访问权限的需要。您可以配置:

  • Docker CLI 工具在系统目录或用户目录中的位置
  • 默认 Docker 套接字
  • 特权端口映射

根据您配置的高级设置,您可能需要输入密码以进行确认。

您可以在稍后从 设置 中的 高级 页面更改这些配置。

Docker Desktop for Mac 的 4.15 至 4.17 版本不需要永久运行特权进程。每当配置需要提升权限时,Docker Desktop 会提示您所需执行任务的相关信息。大多数配置仅需应用一次,后续运行将不再请求特权访问。 唯一可能启动特权进程的情况是绑定主机操作系统默认不允许的特权端口。

Mac 版 Docker Desktop 4.15 之前的版本需要在首次运行时授予 root 访问权限。Docker Desktop 首次启动时,您会收到一个管理员提示,要求授权安装 com.docker.vmnetd 特权辅助服务。对于后续运行,不再需要 root 特权。遵循最小权限原则,这种方法仅在绝对必要的操作中才使用 root 访问权限,同时仍允许以非特权用户身份使用 Docker Desktop。 所有特权操作均通过特权辅助进程 com.docker.vmnetd 运行。


Docker Binaries默认安装在 /Applications/Docker.app/Contents/Resources/bin。Docker Desktop 会在 /usr/local/bin 中为这些Binaries创建符号链接,这意味着在大多数系统上它们会自动被包含在 PATH 中。


从 4.18 版本起,您可在安装 Docker Desktop 时选择将符号链接安装到 /usr/local/bin$HOME/.docker/bin 中。

如果选择 /usr/local/bin,且该位置不允许非特权用户写入,则 Docker Desktop 将在创建指向 Docker Binaries的符号链接至 /usr/local/bin 之前,要求授权以确认此选择。如果选择 $HOME/.docker/bin,则无需授权,但您必须 手动将 $HOME/.docker/bin 添加到其 PATH 环境变量中。

您还可以选择启用 /var/run/docker.sock 符号链接的安装。创建此符号链接可确保依赖默认 Docker 套接字路径的各种 Docker 客户端无需额外修改即可正常工作。

由于 /var/run 以 tmpfs 方式挂载,其内容在重启时会被删除,包括指向 Docker 套接字的符号链接。为确保重启后 Docker 套接字存在,Docker Desktop 会设置一个 launchd 启动任务,通过运行 ln -s -f /Users/<user>/.docker/run/docker.sock /var/run/docker.sock 来创建该符号链接。这样可避免每次启动时都被提示创建符号链接。如果您在安装时未启用此选项,则不会创建该符号链接和启动任务,此时您可能需要在客户端中显式将 DOCKER_HOST 环境变量设置为 /Users/<user>/.docker/run/docker.sock。Docker CLI 依赖当前上下文来获取套接字路径,而 Docker Desktop 启动时会将当前上下文设置为 desktop-linux

对于 4.18 之前的版本,在首次启动时,Docker Desktop 会以特权配置方式在 /usr/local/bin 中安装符号链接。Docker Desktop 会检查符号链接是否存在,并执行以下操作:

  • 如果/usr/local/bin可被非特权用户写入,则在不显示管理员提示的情况下创建符号链接。
  • 触发管理员提示,要求您授权在 /usr/local/bin 中创建符号链接。如果您授权此操作,将在 /usr/local/bin 中创建指向 Docker 可执行文件的符号链接。如果您拒绝该提示、不愿运行需要提升权限的配置,或您的计算机上没有管理员权限,Docker Desktop 将在 ~/.docker/bin 中创建符号链接,并编辑您的 shell 配置文件以确保该位置已加入 PATH 环境变量。这要求所有已打开的终端窗口重新加载配置。 拒绝操作将被记录,以便后续运行时不再重复提示您。 若因任何原因未能确保可执行文件已加入 PATH,您可能需要手动将 /Applications/Docker.app/Contents/Resources/bin 添加到 PATH 环境变量,或直接使用 Docker 可执行文件的完整路径。

一种特殊情况是 /var/run/docker.sock 符号链接的安装。创建此符号链接可确保依赖默认 Docker 套接字路径的各种 Docker 客户端无需额外配置即可正常工作。由于 /var/run 以 tmpfs 方式挂载,其内容在重启时会被删除,Docker 套接字的符号链接也包含在内。 为确保 Docker 套接字在重启后依然存在,Docker Desktop 会设置一个 launchd 启动任务,该任务通过运行 ln -s -f /Users/<user>/.docker/run/docker.sock /var/run/docker.sock 来创建该符号链接。这样可避免每次启动时都被提示创建符号链接。如果您拒绝该提示,则符号链接和启动任务均不会被创建,您可能需要在所使用的客户端中显式将 DOCKER_HOST 设置为 /Users/<user>/.docker/run/docker.sock。Docker CLI 依赖当前上下文来获取套接字路径,而 Docker Desktop 启动时会将当前上下文设置为 desktop-linux


绑定特权端口


从 4.18 版本开始,您可在安装过程中选择启用特权端口映射,或在安装后于 设置 中的 高级 页面进行配置。Docker Desktop 需要获得授权以确认此选择。

对于低于 4.18 的版本,如果您运行的容器需要绑定特权端口,Docker Desktop 首先会尝试以非特权进程直接进行绑定。如果操作系统阻止此操作导致绑定失败,Docker Desktop 将检查 com.docker.vmnetd 特权辅助进程是否正在运行,以通过该进程绑定特权端口。

如果特权辅助进程未运行,Docker Desktop 将提示您授权在 launchd下运行该进程。 此配置将使特权辅助进程以 Docker Desktop 4.15 之前版本的方式运行。然而,当前特权辅助进程所提供的功能仅支持端口绑定及缓存 Registry Access Management(注册表访问管理)策略。 如果您拒绝启动特权辅助进程,则无法绑定特权端口,Docker CLI 将返回错误:

$ docker run -p 127.0.0.1:80:80 docker/getting-started

docker: Error response from daemon: Ports are not available: exposing port
TCP 127.0.0.1:80 -> 0.0.0.0:0: failed to connect to /var/run/com.docker.vmnetd.sock:
is vmnetd running?: dial unix /var/run/com.docker.vmnetd.sock: connect: connection
refused.
ERRO[0003] error waiting for container: context canceled

注意

如果授权提示以启动辅助进程的时间过长,该命令可能会因超时而失败,并出现相同的错误。


确保已定义 localhostkubernetes.docker.internal


从 4.18 及更高版本开始,您需自行确保 localhost 解析为 127.0.0.1;若使用 Kubernetes,还需确保 kubernetes.docker.internal 解析为 127.0.0.1

首次运行时,Docker Desktop 会检查 localhost 是否解析为 127.0.0.1。若解析失败,系统将提示您允许添加 /etc/hosts 的映射。同样地,当安装 Kubernetes 集群时,它会检查 kubernetes.docker.internal 是否解析为 127.0.0.1,并提示您进行相应操作。


从命令行安装

在 Docker Desktop for Mac 的 4.11 及更高版本中,特权配置会在安装过程中通过在 安装命令 中使用 --user 标志来应用。此时,首次运行 Docker Desktop 时系统不会提示您授予 root 特权。具体而言,--user 标志:

  • 如果存在,则卸载之前的 com.docker.vmnetd
  • 设置符号链接
  • 确保将 localhost 解析为 127.0.0.1

此方法的局限性在于,Docker Desktop 仅能由每个设备上的一个用户账户运行,即在 -–user 参数中指定的账户。

特权助手

在需要使用特权辅助程序的有限场景中(例如绑定特权端口或缓存注册表访问管理策略),特权辅助程序由 launchd 启动,并在后台运行,除非按照前述方式在运行时将其禁用。Docker Desktop 后端通过 UNIX 域套接字 /var/run/com.docker.vmnetd.sock 与特权辅助程序进行通信。其执行的功能包括:

  • 绑定小于1024的特权端口。
  • 安全地缓存对开发者只读的注册表访问管理策略。
  • 正在卸载特权辅助工具。

特权辅助进程的移除方式与移除 launchd 个进程的方式相同。

$ ps aux | grep vmnetd
root             28739   0.0  0.0 34859128    228   ??  Ss    6:03PM   0:00.06 /Library/PrivilegedHelperTools/com.docker.vmnetd
user             32222   0.0  0.0 34122828    808 s000  R+   12:55PM   0:00.00 grep vmnetd

$ sudo launchctl unload -w /Library/LaunchDaemons/com.docker.vmnetd.plist
Password:

$ ps aux | grep vmnetd
user             32242   0.0  0.0 34122828    716 s000  R+   12:55PM   0:00.00 grep vmnetd

$ rm /Library/LaunchDaemons/com.docker.vmnetd.plist

$ rm /Library/PrivilegedHelperTools/com.docker.vmnetd

在 Linux 虚拟机中以 root 身份运行的容器

使用 Docker Desktop 时,Docker 守护进程及容器运行在一个由 Docker 管理的轻量级 Linux 虚拟机中。这意味着,尽管容器默认以 root 用户身份运行,但这并不会授予 root 对 Mac 主机的访问权限。该 Linux 虚拟机充当安全边界,限制了容器可访问的主机资源。任何从主机绑定挂载到 Docker 容器中的目录仍保留其原始权限。

增强的容器隔离性

此外,Docker Desktop 支持 增强型容器隔离模式(ECI), 该功能仅面向企业客户,可在不影响开发人员工作流的前提下进一步保障容器安全。

ECI 会自动在 Linux 用户命名空间中运行所有容器,从而使容器内的 root 用户映射为 Docker Desktop 虚拟机内的非特权用户。ECI 利用此技术及其他高级手段,进一步增强 Docker Desktop Linux 虚拟机内容器的安全性,使其与 Docker 守护进程及虚拟机内运行的其他服务实现更严格的隔离。