Docker
Docker 是一个用于打包、交付和运行任何应用程序作为轻量级容器的实用程序。
安装
要拉取 Docker 镜像并运行 Docker 容器,您需要 Docker Engine。Docker Engine 包括一个用于管理容器的守护进程,以及 docker
CLI 前端。 安装 docker 软件包,或者对于开发版本,安装 docker-gitAUR 软件包。接下来 启用/启动 docker.service
或 docker.socket
。请注意,docker.service
在启动时启动服务,而 docker.socket
在首次使用时启动 docker 这可以减少启动时间。然后验证 docker 的状态
# docker info
请注意,如果您有活动的 VPN 连接,则启动 docker 服务可能会失败,这是因为 VPN 和 Docker 的桥接和 overlay 网络之间存在 IP 冲突。如果发生这种情况,请尝试断开 VPN 连接,然后再启动 docker 服务。您可以在之后立即重新连接 VPN。您也可以尝试解决网络冲突(请参阅解决方案 [1] 或 [2])。
接下来,验证您是否可以运行容器。以下命令下载最新的 Arch Linux 镜像,并使用它在容器中运行 Hello World 程序
# docker run -it --rm archlinux bash -c "echo hello world"
要删除下载的 archlinux docker 镜像,请参阅 #移除 Docker 和镜像。
如果您希望能够以非 root 用户身份运行 docker
CLI 命令,请将您的用户添加到 docker
用户组,重新登录并重启 docker.service
。
docker
组的任何人都等同于 root,因为他们可以使用 docker run --privileged
命令来启动具有 root 权限的容器。有关更多信息,请参阅 [3] 和 [4]。如果您计划使用 Docker 构建容器镜像,请安装 docker-buildx 以使用当前的构建器,而不是已弃用的旧构建器。
Docker Compose
Docker Compose 是 Docker Engine 的备用 CLI 前端,它使用 compose.yaml
YAML 文件而不是例如带有 docker run
选项的脚本来指定容器的属性。这对于设置经常使用和/或具有复杂配置的重复性服务非常有用。要使用它,安装 docker-compose。
Docker Desktop
Docker Desktop 是一个专有的桌面应用程序,它在 Linux 虚拟机内部运行 Docker Engine。还包括 Kubernetes 集群和漏洞扫描器等附加功能。此应用程序对于使用 macOS 和 Windows 开发 Docker 容器的软件开发团队非常有用。该应用程序的 Linux 端口相对较新,是对 Docker 的 CLI 前端 [5] 的补充。
Docker 直接提供了一个用于 Arch 的实验性软件包;有关更多信息,请参阅 手册。不幸的是,它包含与 docker-compose 和 docker-buildx 软件包冲突的文件,因此如果已安装,您需要先删除它们。或者,您可以安装 docker-desktopAUR 软件包,该软件包与现有软件包不冲突。
此外,要运行 Docker Desktop,您需要确保 Linux 系统要求,包括通过 KVM 的虚拟化支持。要在 Gnome 下查看托盘图标,需要 gnome-shell-extension-appindicator。
最后,文件共享支持需要通过 /etc/subuid
和 /etc/subgid
映射用户和组 ID。有关更多详细信息,请参阅 Docker Desktop For Linux 文件共享说明。
有关更多信息,请参阅 Linux 版 Docker Desktop 和 Docker Engine 之间有什么区别。
此外,预计在 Linux 上使用 Docker Desktop 时,性能会降低,并且 cpu 使用率会更高。
默认情况下,Docker Desktop 启用用户级别的 systemd 服务,该服务在启动时自动启动应用程序。在 Docker Desktop 仪表板中禁用“自动启动”设置 并不能 阻止此服务启动(链接的问题页面包含修复程序)。
前端
- DockStation — 一个以开发者为中心的应用程序 (GUI),用于管理基于 Docker 的项目。
- Ducker — 一个用于管理 docker 容器的终端应用程序。
- goManageDocker — 一个用于管理 docker 对象的 TUI 工具。
- Lazydocker — 一个用于 docker 和 docker-compose 的简单终端 UI,用 Go 和 gocui 库编写。
- oxker — 一个用于查看和控制 Docker 容器的简单 TUI。
- Podman Desktop — 从单个 UI 和托盘管理 Podman 和其他容器引擎。
- Portainer — 一个轻量级的 docker 管理 UI。
- Whaler — 为 Pantheon 设计的 Docker 容器管理工具。
用法
Docker 由多个部分组成
- Docker 守护进程(有时也称为 Docker Engine),它是一个作为
docker.service
运行的进程。它服务于 Docker API 并管理 Docker 容器。 docker
CLI 命令,它允许用户通过命令行与 Docker API 交互并控制 Docker 守护进程。- Docker 容器,它们是由 Docker 守护进程启动和管理的命名空间进程,通过 Docker API 请求。
通常,用户通过运行 docker
CLI 命令来使用 Docker,这些命令反过来请求 Docker 守护进程执行操作,从而导致 Docker 容器的管理。了解客户端 (docker
)、服务器 (docker.service
) 和容器之间的关系对于成功管理 Docker 非常重要。
请注意,如果 Docker 守护进程停止或重启,所有当前正在运行的 Docker 容器也会停止或重启。
另请注意,无需使用 docker
CLI 命令即可向 Docker API 发送请求并控制 Docker 守护进程。有关更多信息,请参阅 Docker API 开发者文档。
有关更多用法文档,请参阅 Docker 入门指南。
配置
可以通过 /etc/docker/daemon.json
中的配置文件或通过将命令行标志添加到 docker.service
systemd 单元来配置 Docker 守护进程。根据 Docker 官方文档,配置文件方法是首选。如果您希望改用命令行标志,请使用 systemd drop-in 文件 来覆盖 docker.service
中的 ExecStart
指令。
有关 daemon.json
中选项的更多信息,请参阅 dockerd 文档。
存储驱动
存储驱动程序 控制镜像和容器如何在您的 Docker 主机上存储和管理。默认的 overlay2
驱动程序对于大多数用例都具有良好的性能。
btrfs 或 ZFS 的用户可以使用 btrfs
或 zfs
驱动程序,每个驱动程序都利用了这些文件系统的独特功能。有关更多信息和分步说明,请参阅 btrfs 驱动程序 和 zfs 驱动程序 文档。
守护进程套接字
默认情况下,Docker 守护进程使用 /var/run/docker.sock
处的 Unix 套接字 服务 Docker API。对于大多数用例,这是一个合适的选择。
可以将守护进程配置为额外侦听 TCP 套接字,这可以允许从其他计算机进行远程 Docker API 访问。 [7] 这对于允许主机上的 docker
命令访问 Linux 虚拟机(例如 Windows 或 macOS 系统上的 Arch 虚拟机)上的 Docker 守护进程非常有用。
请注意,默认的 docker.service
文件默认设置了 -H
标志,并且如果标志和 /etc/docker/daemon.json
文件中都存在选项,则 Docker 将无法启动。因此,更改套接字设置的最简单方法是使用 drop-in 文件,例如以下文件在端口 2376 上添加 TCP 套接字
/etc/systemd/system/docker.service.d/docker.conf
[Service] ExecStart= ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376
重新加载 systemd 守护进程并重启 docker.service
以应用更改。
HTTP 代理
配置 Docker 以使用 HTTP 代理有两个部分:配置 Docker 守护进程和配置 Docker 容器。
Docker 守护进程代理配置
请参阅 Docker 文档关于配置 Docker 守护进程以使用 HTTP 代理。
Docker 容器代理配置
请参阅 Docker 文档关于配置代理,以了解如何为使用 docker
CLI 创建的所有容器自动配置代理。
配置 DNS
请参阅 Docker 的 DNS 文档,了解 Docker 容器中 DNS 的文档化行为以及有关自定义 DNS 配置的信息。在大多数情况下,主机上配置的解析器也在容器中配置。
托管在 127.0.0.0/8
上的大多数 DNS 解析器由于容器和主机网络命名空间之间的冲突而不受支持。此类解析器从容器的 /etc/resolv.conf 中删除。如果这会导致 /etc/resolv.conf
为空,则会改用 Google DNS。
此外,如果 127.0.0.53
是唯一配置的名称服务器,则会处理一个特殊情况。在这种情况下,Docker 假定解析器是 systemd-resolved,并使用来自 /run/systemd/resolve/resolv.conf
的上游 DNS 解析器。
如果您正在使用诸如 dnsmasq 之类的服务来提供本地解析器,请考虑添加一个虚拟接口,其链路本地 IP 地址在 169.254.0.0/16
块中,供 dnsmasq 绑定到,而不是 127.0.0.1
,以避免网络命名空间冲突。
镜像位置
默认情况下,docker 镜像位于 /var/lib/docker
。它们可以移动到其他分区,例如,如果您希望为镜像使用专用分区或磁盘。在本例中,我们将镜像移动到 /mnt/docker
。
首先,停止 docker.service
,这也将停止所有当前正在运行的容器并卸载任何正在运行的镜像。然后,您可以将镜像从 /var/lib/docker
移动到目标位置,例如 cp -r /var/lib/docker /mnt/docker
。
在 /etc/docker/daemon.json
中配置 data-root
/etc/docker/daemon.json
{ "data-root": "/mnt/docker" }
重启 docker.service
以应用更改。
不安全仓库
如果您决定为您的私有仓库使用自签名证书,Docker 将拒绝使用它,除非您声明您信任它。例如,要允许来自托管在 myregistry.example.com:8443
的仓库的镜像,请在 /etc/docker/daemon.json
文件中配置 insecure-registries
/etc/docker/daemon.json
{ "insecure-registries": [ "my.registry.example.com:8443" ] }
重启 docker.service
以应用更改。
IPv6
为了在 Docker 中启用 IPv6 支持,您需要做几件事。有关详细信息,请参阅 [8] 和 [9]。
首先,在 /etc/docker/daemon.json
中启用 ipv6
设置并设置特定的 IPv6 子网。在本例中,我们将使用私有 fd00::/80
子网。确保使用至少 80 位的子网,因为这允许容器的 IPv6 以容器的 MAC 地址结尾,这允许您缓解 NDP 邻居缓存失效问题。
/etc/docker/daemon.json
{ "ipv6": true, "fixed-cidr-v6": "fd00::/80" }
重启 docker.service
以应用更改。
最后,为了让容器访问主机网络,您需要解决因使用私有 IPv6 子网而引起的路由问题。添加 IPv6 NAT 以实际获取一些流量
# ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE
现在 Docker 应该已正确启用 IPv6。要对其进行测试,您可以运行
# docker run curlimages/curl curl -v -6 archlinux.org
如果您使用 firewalld,您可以像这样添加规则
# firewall-cmd --zone=public --add-rich-rule='rule family="ipv6" destination not address="fd00::1/80" source address="fd00::/80" masquerade'
如果您使用 ufw,您需要首先按照 Uncomplicated Firewall#转发策略 启用 ipv6 转发。接下来,您需要编辑 /etc/default/ufw
并取消注释以下行
/etc/ufw/sysctl.conf
net/ipv6/conf/default/forwarding=1 net/ipv6/conf/all/forwarding=1
然后,您可以添加 iptables 规则
# ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE
应该注意的是,对于使用 docker-compose 创建的 docker 容器,您可能需要在相应网络的 networks
部分中设置 enable_ipv6: true
。此外,您可能需要配置 IPv6 子网。有关详细信息,请参阅 [10]。
用户命名空间隔离
默认情况下,Docker 容器中的进程与主 dockerd
守护进程在同一用户命名空间中运行,即容器未通过 user_namespaces(7) 功能隔离。这允许容器内的进程根据 用户和组#权限和所有权 访问主机上配置的资源。这最大限度地提高了兼容性,但如果发现容器特权提升或突破漏洞,允许容器访问主机上非预期的资源,则会构成安全风险。(2019 年 2 月 发布并修补了一个此类漏洞。)
通过启用 用户命名空间隔离 可以降低此类漏洞的影响。这在单独的用户命名空间中运行每个容器,并将该用户命名空间内的 UID 和 GID 映射到主机上不同的(通常是非特权的)UID/GID 范围。
在 /etc/docker/daemon.json
中配置 userns-remap
。default
是一个特殊值,它将自动创建一个名为 dockremap
的用户和组以用于重新映射。
/etc/docker/daemon.json
{ "userns-remap": "default" }
使用用户名/组名、起始 UID/GID 和 UID/GID 范围大小配置 /etc/subuid
和 /etc/subgid
,以分配给重新映射用户和组。此示例为 dockremap
用户和组分配了从 165536 开始的 65536 个 UID 和 GID 范围。
/etc/subuid
dockremap:165536:65536
/etc/subgid
dockremap:165536:65536
重启 docker.service
以应用更改。
应用此更改后,所有容器都将默认在隔离的用户命名空间中运行。可以通过将 --userns=host
标志传递给 docker
命令来部分禁用特定容器上的重新映射。有关详细信息,请参阅 [11]。
无根 Docker 守护进程
CONFIG_USER_NS_UNPRIVILEGED
)。这在 linux、linux-lts 和 linux-zen 内核中默认启用。其他内核的用户可能需要启用它。这有一些安全隐患,有关详细信息,请参阅 安全#应用程序沙盒化。要以常规用户身份运行 Docker 守护进程本身,请安装 docker-rootless-extrasAUR 软件包。
使用用户名/组名、起始 UID/GID 和 UID/GID 范围大小配置 /etc/subuid
和 /etc/subgid
,以分配给重新映射用户和组。
/etc/subuid
your_username:165536:65536
/etc/subgid
your_username:165536:65536
启用 docker.socket
用户单元:这将导致 docker 使用 systemd 的套接字激活启动。
最后设置 docker 套接字 环境变量
$ export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
启用原生 overlay diff 引擎
默认情况下,Docker 无法在 Arch Linux 上使用原生 overlay diff 引擎,这使得构建 Docker 镜像速度缓慢。如果您经常构建镜像,请按照 [12] 中的描述配置原生 diff 引擎
/etc/modprobe.d/disable-overlay-redirect-dir.conf
options overlay metacopy=off redirect_dir=off
然后停止 docker.service
,如下所示重新加载 overlay
模块
# modprobe -r overlay # modprobe overlay
然后您可以启动 docker.service
。
要验证,请运行 docker info
并检查 Native Overlay Diff
是否为 true
。
镜像
Arch Linux
以下命令拉取 archlinux x86_64 镜像。这是一个精简版的 Arch core,没有网络等。
# docker pull archlinux
另请参阅 README.md。
对于完整的 Arch 基础镜像,请从上面克隆存储库并构建您自己的镜像。
$ git clone https://gitlab.archlinux.org/archlinux/archlinux-docker.git
确保已安装 devtools、fakechroot 和 fakeroot 软件包。
要构建基础镜像
$ make image-base
Alpine Linux
Alpine Linux 是小型容器镜像的热门选择,尤其适用于编译为静态二进制文件的软件。以下命令拉取最新的 Alpine Linux 镜像
# docker pull alpine
Alpine Linux 使用 musl libc 实现,而不是大多数 Linux 发行版使用的 glibc libc 实现。由于 Arch Linux 使用 glibc,因此 Arch Linux 主机和 Alpine Linux 容器之间存在许多功能差异,这些差异可能会影响软件的性能和正确性。这些差异的列表记录在 此处。
请注意,在 Arch Linux(或任何其他使用 glibc 的系统)上构建的动态链接软件在 Alpine Linux(或任何其他使用不同 libc 的系统)上运行时可能存在 bug 和性能问题。有关示例,请参阅 [13]、[14] 和 [15]。
Debian
以下命令拉取最新的 debian 镜像
# docker pull debian
有关可用标签的完整列表,包括每个 Debian 版本的标准版和精简版,请参阅 Docker Hub 页面。
Distroless
Google 维护 distroless 镜像,这些镜像是不包含软件包管理器或 shell 等操作系统组件的最小镜像,从而为打包软件提供了非常小的镜像。
有关镜像列表以及如何在各种编程语言中使用它们的说明,请参阅 GitHub README。
技巧与诀窍
获取运行中容器的 IP 地址
要获取运行中容器的 IP 地址
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container-name OR id>
172.17.0.37
对于每个正在运行的容器,可以列出名称和相应的 IP 地址,以便在 /etc/hosts
中使用
#!/usr/bin/env sh for ID in $(docker ps -q | awk '{print $1}'); do IP=$(docker inspect --format="{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" "$ID") NAME=$(docker ps | grep "$ID" | awk '{print $NF}') printf "%s %s\n" "$IP" "$NAME" done
在容器内运行图形程序
本节介绍允许图形程序(包括依赖 OpenGL 或 Vulkan 的程序)在主机的 X 服务器上运行的必要步骤。
首先,需要在容器内安装与主机的图形硬件兼容的正确驱动程序。安装过程取决于容器的类型,但对于基于 Arch Linux 镜像的容器,请参阅 OpenGL#安装 和 Vulkan#安装,了解特定于您的硬件的软件包。
接下来,必须授予容器访问主机 X 服务器的权限。在单用户环境中,可以通过在主机系统上运行 Xhost 轻松完成此操作,这会将非网络本地连接添加到访问控制列表
$ xhost +local:
最后,需要将以下参数传递给 docker run
-e "DISPLAY=$DISPLAY"
将容器内的环境变量DISPLAY
设置为主机的显示器;--mount type=bind,src=/tmp/.X11-unix,dst=/tmp/.X11-unix
将主机 X 服务器套接字挂载到容器内,路径相同;--device=/dev/dri:/dev/dri
允许容器访问主机上的 Direct Rendering Infrastructure 设备。
要确认一切设置正确,请在容器中运行软件包 mesa-utils 中的 glxgears
或软件包 vulkan-tools 中的 vkcube
。
在启动时启动 Docker Compose 项目
首先,为 Docker Compose 创建一个模板 unit,它由服务名称参数化(参见 systemd.service(5) § SERVICE TEMPLATES)
/etc/systemd/system/docker-compose@.service
[Unit] Description=%i service with docker compose Requires=docker.service After=docker.service [Service] WorkingDirectory=/opt/%i ExecStartPre=-/usr/bin/docker compose pull ExecStart=/usr/bin/docker compose up --remove-orphans ExecStop=/usr/bin/docker compose down ExecReload=/usr/bin/docker compose pull ExecReload=/usr/bin/docker compose up --remove-orphans [Install] WantedBy=multi-user.target
然后,对于您想要运行的每个服务,在 /opt/project_name
目录下设置一个包含 Compose 文件和任何其他所需文件(例如 .env
文件)的目录。[17]
然后,启用/启动 docker-compose@project_name.service
。
使用 buildx 进行交叉编译
buildx CLI 插件 使用了新的 BuildKit 构建工具包。安装 docker-buildx 软件包。buildx 接口支持构建多平台镜像,包括主机架构以外的其他架构。
需要 QEMU 来交叉编译镜像。要在 Docker 中设置 QEMU 的静态构建,请参阅 multiarch/qemu-user-static 镜像的用法信息。否则,要在主机系统上设置 QEMU 以与 Docker 一起使用,请参阅 QEMU#从 x86_64 环境 chroot 到 arm/arm64 环境。无论哪种情况,您的系统都将配置为访客架构的用户模式模拟。
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS default * docker default default running linux/amd64, linux/386, linux/arm64, linux/riscv64, linux/s390x, linux/arm/v7, linux/arm/v6
使用 NVIDIA GPU 运行 GPU 加速的 Docker 容器
从 Docker 版本 19.03 开始,NVIDIA GPU 原生支持作为 Docker 设备。NVIDIA Container Toolkit 是运行利用 NVIDIA GPU 的容器的推荐方式。
安装 nvidia-container-toolkit 软件包并 重启 docker。您现在可以使用 --gpus
选项或注册 NVIDIA 容器运行时来运行使用 NVIDIA GPU 的容器。
使用 --gpus 选项(推荐)
# docker run --gpus all nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi
指定容器内启用多少个 GPU
# docker run --gpus 2 nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi
指定要使用的 GPU
# docker run --gpus '"device=1,2"' nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi
或
# docker run --gpus '"device=UUID-ABCDEF,1"' nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi
如果在使用上述命令时,您收到类似 Failed to initialize NVML: Unknown Error
的错误,您可以尝试更具体地指定 GPU
# docker run --gpus all --device /dev/nvidiactl:/dev/nvidiactl --device /dev/nvidia-uvm:/dev/nvidia-uvm --device /dev/nvidia0:/dev/nvidia0 nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi
为容器指定一种能力(graphics,compute,...)(尽管以这种方式使用的情况极少)
# docker run --gpus all,capabilities=utility nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi
使用 NVIDIA 容器运行时
通过编辑 /etc/docker/daemon.json
注册 NVIDIA 运行时
/etc/docker/daemon.json
{ "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } } }
然后 重启 docker。
也可以通过 dockerd 的命令行选项注册运行时
# /usr/bin/dockerd --add-runtime=nvidia=/usr/bin/nvidia-container-runtime
之后,可以使用以下命令启动 GPU 加速的容器
# docker run --runtime=nvidia nvidia/cuda:9.0-base nvidia-smi
另请参阅 README.md。
带有 CUDA 的 Arch Linux 镜像
您可以使用以下 Dockerfile
构建带有 CUDA 的自定义 Arch Linux 镜像。它使用 Dockerfile frontend syntax 1.2 在主机上缓存 pacman 软件包。在构建 Docker 镜像之前,必须在客户端上设置 DOCKER_BUILDKIT=1
环境变量。
Dockerfile
# syntax=docker/dockerfile:1.2 FROM archlinux:base-devel # Install packages RUN --mount=type=cache,sharing=locked,target=/var/cache/pacman \ pacman -Syu --noconfirm --needed cuda # Configure nvidia container runtime # https://github.com/NVIDIA/nvidia-container-toolkit/tree/main/cmd/nvidia-container-runtime#environment-variables-oci-spec ENV NVIDIA_VISIBLE_DEVICES=all ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility
移除 Docker 和镜像
如果您想完全移除 Docker,您可以按照以下步骤操作
检查正在运行的容器
# docker ps
列出主机上所有正在运行的容器以进行删除
# docker ps -a
停止正在运行的容器
# docker stop <CONTAINER ID>
杀死仍在运行的容器
# docker kill <CONTAINER ID>
删除按 ID 列出的容器
# docker rm <CONTAINER ID>
列出所有 Docker 镜像
# docker images
按 ID 删除镜像
# docker rmi <IMAGE ID>
删除所有未与容器关联的镜像、容器、卷和网络(悬挂的)
# docker system prune
要额外删除任何已停止的容器和所有未使用的镜像(不仅仅是悬挂的镜像),请向命令添加 -a 标志
# docker system prune -a
删除所有 Docker 数据(清除目录)
# rm -R /var/lib/docker
故障排除
使用 systemd-networkd 时,docker0 Bridge 没有 IP / 容器中没有互联网访问
Docker 尝试全局启用 IP 转发,但默认情况下 systemd-networkd 会覆盖每个已定义网络配置文件的全局 sysctl 设置。在网络配置文件中设置 IPForward=yes
。有关详细信息,请参阅 Internet sharing#启用数据包转发。
当 systemd-networkd 尝试管理 Docker 创建的网络接口时,例如当您在 Match
部分中配置了 Name=*
或 Type=ether
时,这可能会导致连接问题。通过更具体地匹配接口应该可以解决该问题,即避免使用 Name=*
或 Type=ether
或其他匹配 Docker 管理的接口的通配符。验证 networkctl list
报告所有 Docker 创建的网络在 SETUP 列中显示 unmanaged
。
默认允许的进程/线程数太低
如果您遇到类似这样的错误消息
# e.g. Java java.lang.OutOfMemoryError: unable to create new native thread # e.g. C, bash, ... fork failed: Resource temporarily unavailable
那么您可能需要调整 systemd 允许的进程数。编辑 docker.service
,添加以下代码段
[Service] TasksMax=infinity
有关更多背景信息,请在 systemd-system.conf(5) § OPTIONS 中查找 DefaultLimitNPROC
。并在 systemd.resource-control(5) § OPTIONS 中查找 TasksMax
。
Error initializing graphdriver: devmapper
如果 systemctl 无法启动 docker 并提供错误
Error starting daemon: error initializing graphdriver: devmapper: Device docker-8:2-915035-pool is not a thin pool
然后,尝试以下步骤来解决错误。停止服务,备份 /var/lib/docker/
(如果需要),删除 /var/lib/docker/
的内容,然后尝试启动服务。有关详细信息,请参阅 https://github.com/moby/moby/issues/21304。
未能创建 some/path/to/file:设备上没有剩余空间
如果您在构建或运行 Docker 镜像时收到类似这样的错误消息
ERROR: Failed to create some/path/to/file: No space left on device
即使您有足够的可用磁盘空间,也要确保
- Tmpfs 已禁用或具有足够的内存分配。Docker 可能正在尝试将文件写入
/tmp
,但由于内存使用限制而不是磁盘空间而失败。 - 如果您正在使用 XFS,您可能需要从
/etc/fstab
中相关条目(通常是/tmp
和/或/var/lib/docker
所在的位置)中删除noquota
挂载选项。有关更多信息,请参阅 磁盘配额,特别是如果您计划使用和调整overlay2
Docker 存储驱动程序的大小。 - XFS 配额挂载选项(
uquota
、gquota
、prjquota
等)在重新挂载文件系统期间失败。要为根文件系统启用配额,必须将挂载选项作为 内核参数rootflags=
传递给 initramfs。随后,不应将其列在根 (/
) 文件系统的/etc/fstab
中的挂载选项中。
Docker-machine 无法使用 virtualbox 驱动程序创建虚拟机
如果 docker-machine 无法使用 virtualbox 驱动程序创建 VM,并出现以下情况
VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory
只需通过 CLI 使用 vboxreload
重新加载 virtualbox。
启动 Docker 破坏 KVM 桥接网络
问题在于 Docker 的脚本添加了一些 iptables 规则来阻止在其他接口(而非其自身接口)上转发。这是一个 已知问题。
调整以下解决方案以将 br0 替换为您自己的桥接名称。
最快的解决方法(但会关闭 Docker iptables 自行添加的所有调整,这可能不是您想要的)
/etc/docker/daemon.json
{ "iptables": false }
如果已经为 KVM 配置了网络桥接,则可以通过告诉 docker 来修复此问题。请参阅 [21],其中 docker 配置被修改为
/etc/docker/daemon.json
{ "bridge": "br0" }
如果以上方法不起作用,或者您更喜欢通过 iptables 直接或通过 UFW 等管理器解决问题,请添加此项
iptables -I FORWARD -i br0 -o br0 -j ACCEPT
更详细的解决方案 在此处。
从 Docker Hub 拉取镜像受到速率限制
从 2020 年 11 月 1 日开始,匿名和免费帐户从 Docker Hub 下载受到速率限制。有关更多信息,请参阅 速率限制文档。
未经身份验证的速率限制按源 IP 跟踪。经过身份验证的速率限制按帐户跟踪。
如果您需要超出速率限制,您可以 注册付费计划 或将您需要的镜像镜像到不同的镜像注册表。您可以 托管您自己的注册表 或使用云托管的注册表,例如 Amazon ECR、Google Container Registry、Azure Container Registry 或 Quay Container Registry。
要镜像镜像,请使用 Docker CLI 的 pull
、tag
和 push
子命令。例如,要将 Nginx 镜像的 1.19.3
标签镜像到托管在 cr.example.com
的注册表
$ docker pull nginx:1.19.3 $ docker tag nginx:1.19.3 cr.example.com/nginx:1.19.3 $ docker push cr.example.com/nginx:1.19.3
然后您可以从镜像中拉取或运行镜像
$ docker pull cr.example.com/nginx:1.19.3 $ docker run cr.example.com/nginx:1.19.3
iptables (legacy):未知选项 "--dport"
如果您在运行容器时看到此错误,请安装 iptables-nft 而不是 iptables (legacy) 并重启[22]。
运行 docker login 时出现“您的密码将以未加密的方式存储”
默认情况下,Docker 将尝试使用 pass
或 secretservice
二进制文件来存储您的注册表密码。如果找不到它们,它将以纯文本形式(base64 编码)将其存储在 $HOME/.docker/config.json
中,并在成功登录后打印以下消息
$ WARNING! Your password will be stored unencrypted in /home/username/.docker/config.json.
如果您正在使用实现 Secret Service Freedesktop DBUS API 的密码管理器,例如 KDE 的 kwallet 或 GNOME 的 gnome-keyring,您可以安装 docker-credential-secretserviceAUR 软件包以将您的密码存储在其中。
“无法在默认值中找到可用于分配给网络的可用、非重叠的 IPv4 地址池”
有时,如果您使用大量的 Docker 项目(例如,使用 docker-compose),可能会发生 Docker 容器的可用 IP 不足的情况,从而触发错误
Could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
如 这个 Docker 问题 中所述,默认值是
类型 | 默认大小 | 默认池 |
---|---|---|
本地 | /16 | 172.17.0.0/12 |
本地* | /20 | 192.168.0.0/16 |
通过在 /etc/docker/daemon.json
中配置 default-address-pools
,将第一个 IP 范围的大小值从 16 增加到 24,并保持第二个范围不变以避免本地网络上的 IP 冲突,可以轻松修复此问题
/etc/docker/daemon.json
{ ... "default-address-pools" : [ { "base" : "172.17.0.0/12", "size" : 24 }, { "base" : "192.168.0.0/16", "size" : 24 } ] }
重启 docker.service
以应用更改。
有关更多详细信息和技术解释,请参阅以下优秀文章:Docker 默认地址池选项的权威指南。
golang 编译缓慢
由于 ulimit 配置,使用 makepkg 构建 docker 镜像及其依赖项非常缓慢(卡在“Entering fakeroot environment...”步骤)。
您可以将 --ulimit "nofile=1024:524288"
添加到 docker build 选项或创建/编辑
/etc/docker/daemon.json
{ "default-ulimits": { "nofile": { "Name": "nofile", "Soft": 1024, "Hard": 524288 } } }
另请参阅
- 官方网站
- docs.docker.com 上的 Arch Linux
- Docker 容器真的安全吗? — opensource.com
- Awesome Docker
- 为什么 Docker 中的特权容器是个坏主意