Docker Desktop for Linux 常见问题解答

为什么 Docker Desktop for Linux 要运行一个虚拟机?

Docker Desktop for Linux 为以下原因运行一个虚拟机(VM):

  1. 为确保 Docker Desktop 在各个平台上提供一致的使用体验。

    在研究过程中,用户希望在 Linux 上使用 Docker Desktop 的最常见原因是确保在所有主流操作系统上获得一致的 Docker Desktop 使用体验,并实现功能对等。通过虚拟机(VM)实现,可确保 Linux 用户的 Docker Desktop 体验与 Windows 和 macOS 用户的体验高度一致。

  2. 利用新的内核特性。

    有时我们希望利用新的操作系统功能。由于我们控制着虚拟机(VM)内部的内核和操作系统,因此我们可以立即将这些功能推广给所有用户,即使某些用户故意坚持使用其机器操作系统长期支持(LTS)版本,也是如此。

  3. 为了增强安全性。

    容器镜像漏洞会对宿主机环境造成安全风险。存在大量未经验证的非官方镜像,无法保证其已排查已知漏洞。恶意用户可将恶意镜像推送至公共镜像仓库,并通过多种手段诱骗用户拉取并运行这些镜像。虚拟机(VM)方式可缓解此类威胁,因为即使恶意程序获取了root权限,也会被限制在虚拟机环境中,无法访问宿主机。

    为什么不运行无根(rootless)Docker?虽然这表面上限制了root用户的访问,使得在“top”命令中看起来更安全,但它允许非特权用户在自己的用户命名空间中获取CAP_SYS_ADMIN(即root权限),进而访问内核API——而这些API原本并未预期会被非特权用户调用,从而导致 漏洞

  4. 为提供功能对等和增强的安全性,同时将对性能的影响降至最低。

    Docker Desktop for Linux 所使用的虚拟机采用 VirtioFS,这是一种共享文件系统,可使虚拟机访问主机上某目录树。我们内部基准测试表明,在为虚拟机合理分配资源的前提下,VirtioFS 可实现接近原生的文件系统性能。

    因此,我们已调整 Docker Desktop for Linux 中虚拟机的默认可用内存。您可以通过 Docker Desktop 的 设置 > 资源 选项卡中的 内存 滑块,根据您的具体需求进行调整。

如何启用文件共享?

Docker Desktop for Linux 使用 VirtioFS 作为主机与 Docker Desktop 虚拟机之间启用文件共享的默认(且当前唯一)机制。

为避免需要提升权限,同时不过度限制对共享文件的操作,Docker Desktop 在用户命名空间(参见virtiofsd)内运行文件共享服务(virtiofsd),并配置了UID和GID映射。因此,Docker Desktop 依赖于宿主机已配置好,以允许当前用户使用从属ID委托(subordinate ID delegation)。为此,必须存在/etc/subuid(参见subuid(5))和/etc/subgid(参见subgid(5))。Docker Desktop 仅支持通过文件配置从属ID委托。Docker Desktop 将当前用户的UID和GID映射到容器内的0。它使用/etc/subuid/etc/subgid中对应当前用户的第一条记录,来设置容器内高于0的ID映射。

容器中的ID主机上的ID
0 (root)运行 DD 的用户 ID(例如 1000)
10 + 指定在 /etc/subuid//etc/subgid 中的 ID 范围起始值(例如 100000)
21 + ID 范围的起始值,由 /etc/subuid//etc/subgid 指定(例如 100001)
32 + /etc/subuid//etc/subgid 中指定的 ID 范围起始值(例如 100002)
......

如果 /etc/subuid/etc/subgid 不存在,则需要创建它们。 两者都应包含如下形式的条目—— <username>:<start of id range>:<id range size>。例如,若要允许当前用户使用从 100 000 到 165 535 的 ID:

$ grep "$USER" /etc/subuid >> /dev/null 2&>1 || (echo "$USER:100000:65536" | sudo tee -a /etc/subuid)
$ grep "$USER" /etc/subgid >> /dev/null 2&>1 || (echo "$USER:100000:65536" | sudo tee -a /etc/subgid)

要验证配置是否已正确创建,请检查其内容:

$ echo $USER
exampleuser
$ cat /etc/subuid
exampleuser:100000:65536
$ cat /etc/subgid
exampleuser:100000:65536

在此场景中,如果一个共享文件在 Docker Desktop 容器内被 chown(归零)所有权,且该容器由 UID 为 1000 的用户所拥有,那么该文件在宿主机上将显示为属于 UID 为 100999 的用户。这会产生一个不理想的结果:导致在宿主机上难以访问该文件。解决此问题的方法是:创建一个具有新 GID 的用户组,并将当前用户添加至该组;或为与 Docker Desktop 虚拟机共享的文件夹设置递归 ACL(参见 setfacl(1))。

Docker Desktop 将 Linux 容器存储在哪里?

Docker Desktop 在 Linux 文件系统中将 Linux 容器和镜像存储在一个单独的、大型的“磁盘镜像”文件中。这与 Linux 上的 Docker 不同,后者通常将容器和镜像存储在主机文件系统的 /var/lib/docker 目录中。

磁盘镜像文件位于何处?

要定位磁盘镜像文件,请在 Docker Desktop 仪表板中选择 设置,然后在 资源 标签页中选择 高级

高级选项卡显示磁盘镜像的位置。它还显示磁盘镜像的最大大小以及该镜像实际占用的空间。请注意,其他工具可能以文件的最大大小而非实际文件大小来显示空间使用情况。

如果文件太大怎么办?

如果磁盘镜像文件过大,您可以:

  • 将它移动到更大的磁盘
  • 删除不必要的容器和镜像
  • 减小允许的最大文件大小
我该如何将文件移动到更大的硬盘上?

要将磁盘镜像文件移动到其他位置:

  1. 资源 选项卡中选择 设置,然后选择 高级

  2. 磁盘镜像位置 部分中,选择 浏览 并为磁盘镜像选择一个新的位置。

  3. 选择 应用并重启 以使更改生效。

请勿直接在 Finder 中移动文件,因为这可能导致 Docker Desktop 丢失对文件的跟踪。

如何删除不必要的容器和镜像?

检查是否存在不必要的容器和镜像。如果您的客户端和守护进程 API 版本为 1.25 或更高版本(可在客户端使用 docker version 命令检查客户端和守护进程 API 版本),您可以通过运行以下命令查看详细的磁盘空间使用信息:

$ docker system df -v

或者,要列出镜像,请运行:

$ docker image ls

要列出容器,请运行:

$ docker container ls -a

如果存在大量冗余对象,请运行以下命令:

$ docker system prune

此命令删除所有已停止的容器、未使用的网络、悬空镜像以及构建缓存。

根据磁盘镜像文件的格式不同,可能需要几分钟时间在主机上回收空间:

  • 如果文件名为 Docker.raw:主机上的空间应在几秒内被回收。
  • 如果文件名为 Docker.qcow2:空间将在几分钟后由后台进程释放。

空间仅在删除镜像时才会被释放。在正在运行的容器内删除文件时,空间不会自动释放。若需随时触发空间回收,请执行以下命令:

$ docker run --privileged --pid=host docker/desktop-reclaim-space

请注意,许多工具报告的是文件的最大大小,而非实际大小。 若要从终端查询主机上文件的实际大小,请运行:

$ cd ~/.docker/desktop/vms/0/data
$ ls -klsh Docker.raw
2333548 -rw-r--r--@ 1 username  staff    64G Dec 13 17:42 Docker.raw

在本示例中,磁盘的实际大小为 2333548 KB,而磁盘的最大大小为 64 GB。

如何减小文件的最大大小?

为了减小磁盘镜像文件的最大尺寸:

  1. 从 Docker Desktop 仪表板中选择 设置,然后在 资源 选项卡中选择 高级

  2. 磁盘镜像大小部分包含一个滑块,允许您更改磁盘镜像的最大大小。通过调整滑块来设置较低的限制。

  3. 选择 应用并重启

当你减小最大容量时,当前磁盘镜像文件将被删除,因此所有容器和镜像将丢失。