了解 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之类的命令。
  • 确保在/etc/hosts中定义了localhostkubernetes.docker.internal 一些旧的 macOS 安装在/etc/hosts中没有localhost,这会导致 Docker 失败。定义 DNS 名称kubernetes.docker.internal允许 Docker 与容器共享 Kubernetes 上下文。
  • 安全地缓存注册表访问管理策略,该策略对于开发者是只读的。

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


从 4.18 及更高版本开始,Docker Desktop for Mac 提供了对安装期间启用的功能的更精细控制。

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

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

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

根据您配置的高级设置,您必须输入密码进行确认。

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

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

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


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


使用 4.18 及更高版本,您可以在安装 Docker Desktop 期间选择是否在/usr/local/bin$HOME/.docker/bin中安装符号链接。

如果选择/usr/local/bin,并且非特权用户无法写入此位置,则 Docker Desktop 需要授权才能在/usr/local/bin中创建指向 Docker 二进制文件的符号链接之前确认此选择。如果选择$HOME/.docker/bin,则不需要授权,但是您必须手动将$HOME/.docker/bin添加到他们的 PATH。

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

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

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

  • 如果非特权用户可以写入/usr/local/bin,则创建符号链接,无需管理员权限。
  • 触发管理员提示,以授权您在/usr/local/bin中创建符号链接。如果您授权此操作,则会在/usr/local/bin中创建指向 Docker 二进制文件的符号链接。如果您拒绝提示,不愿意运行需要提升权限的配置,或者没有计算机的管理员权限,Docker Desktop 会在~/.docker/bin中创建符号链接,并编辑您的 shell 配置文件以确保此位置在您的 PATH 中。这需要重新加载所有打开的 shell。该拒绝操作会被记录下来,以便在未来的运行中避免再次提示您。对于任何无法确保二进制文件位于 PATH 中的情况,您可能需要手动将/Applications/Docker.app/Contents/Resources/bin添加到 PATH 中,或使用 Docker 二进制文件的完整路径。

一个特殊的案例是安装/var/run/docker.sock符号链接。创建此符号链接可确保依赖于默认 Docker socket 路径的各种 Docker 客户端无需额外更改即可正常工作。由于/var/run被挂载为 tmpfs,其内容会在重启时被删除,包括 Docker socket 的符号链接。为确保 Docker socket 在重启后存在,Docker Desktop 会设置一个launchd启动任务,通过运行ln -s -f /Users//.docker/run/docker.sock /var/run/docker.sock来创建符号链接。这可以确保您在每次启动时不会被提示创建符号链接。如果您拒绝提示,则不会创建符号链接和启动任务,您可能需要在使用的客户端中显式设置DOCKER_HOST/Users//.docker/run/docker.sock。Docker CLI 依赖于当前上下文来检索 socket 路径,在 Docker Desktop 启动时,当前上下文设置为desktop-linux


绑定特权端口


对于 4.18 及更高版本,您可以在安装过程中选择启用特权端口映射,或者在安装后从**设置**中的**高级**页面进行设置。Docker Desktop 需要授权才能确认此选择。

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

如果特权辅助进程未运行,Docker Desktop 会提示您授权在launchd下运行它。这会配置特权辅助程序,使其像 4.15 之前的 Docker Desktop 版本一样运行。但是,此特权辅助程序提供的功能现在仅支持端口绑定和缓存注册表访问管理策略。如果您拒绝启动特权辅助进程,则无法绑定特权端口,并且 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,并提示您执行此操作。


从命令行安装

在 4.11 及更高版本的 Docker Desktop for Mac 中,特权配置在安装过程中使用安装命令上的--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身份运行,但这不会授予对 Mac 主机的root访问权限。Linux 虚拟机充当安全边界,并限制可以从主机访问的资源。从主机绑定安装到 Docker 容器的任何目录仍然保留其原始权限。

增强的容器隔离

此外,Docker Desktop 支持增强型容器隔离模式(ECI),仅供企业客户使用,它可以进一步保护容器而不会影响开发人员的工作流程。

ECI 会自动在 Linux 用户命名空间中运行所有容器,以便容器中的 root 会映射到 Docker Desktop 虚拟机内的非特权用户。ECI 使用此技术和其他高级技术来进一步保护 Docker Desktop Linux 虚拟机内的容器,从而使它们与 Docker 守护程序和虚拟机内运行的其他服务进一步隔离。