Docker

来自 Arch Linux 中文维基

Docker 是一种打包、传输和运行任何程序作为轻量级容器的实用工具.

安装[编辑 | 编辑源代码]

要拉取Docker镜像并运行Docker容器,你需要安装Docker引擎,其包含包括一个守护进程来管理容器,以及一个docker命令行界面前端。安装 docker 包 或者,对于开发版本,选择docker-gitAUR 包. 下一步启动 docker.service 或者 docker.socket。两者的差距在于docker.service将会在开机时启动,而docker.socket将会在第一次启动Docker时启动,使用后者可以减少开机启动时间。然后验证操作:

# docker info

注意, 如果你有一个活动的 VPN 连接, 那么 docker 服务的启动可能失败, 因为 VPN 和 Docker 的网桥 IP 冲突以及网络覆盖. 如果发生了这种事, 尝试在启动 docker 服务之前断开 VPN 连接. 你可以在之后立刻重连 VPN. 你也可以尝试手动解决网络冲突(也可参见[1][2])。

你也可以尝试验证是否可以运行容器。以下命令行将会下载一个最新的Arch Linux image,并使用其在这个容器中运行一个Hello World程序:

# docker run -it --rm archlinux bash -c "echo hello world"

如果你想以普通用户身份运行docker的话,添加你自己到 docker 用户组,重新登录并重启docker.service

警告: 任何加入到 docker 组的用户都和root用户等价,因为他们可以通过运行# docker run --privileged来以root权限启动容器。 参见 此处 以及 此处.

如果你还要使用 Docker 构建容器镜像,请安装docker-buildx以使用新版构建器(否则会使用已弃用的旧版构建器)。

Docker Compose[编辑 | 编辑源代码]

Docker Compose是另一种Docker引擎的CLI前端,它使用compose.yamlYAML文件来指定容器的属性,这样就可以不使用附带指令的docker run脚本了.如果你需要经常设置或者使用具有复杂选项的容器,可能使用docker-compose更为方便.你需要安装 docker-compose来使用.

Docker Desktop[编辑 | 编辑源代码]

Docker Desktop是一个专有的桌面应用程序,它在一个Linux虚拟机中运行Docker。它还包括Kubernetes集群以及一个漏洞扫描器。这个应用程序对于在macOS或Windows上进行开发Docker容器的团队非常友好。Docker Desktop适配的Linux版本相对较新,同时也保持了对Docker CLI的良好兼容[3]

Docker直接为Arch Linux提供了一个实验性的软件包(参见其官方文档手动安装Docker一节)。需要注意其手动下载的软件包会与docker-compose以及docker-buildx冲突,你需要在安装前手动移除这两个包。如果你想保留现有的软件包,你也可以从AUR安装docker-desktopAUR,它将不会与现有软件包发生冲突。

此外,在运行Docker Desktop之前,你需要确保你已经安装了所有的在Linux上运行的最小系统要求,包括使用KVM进行虚拟化技术支持。对于Gnome用户,你还需要安装gnome-shell-extension-appindicator以显示托盘图标。

最后,请注意文件共享功能是通过/etc/subuid/etc/subgid映射用户和组ID完成的。详细参见Docker Desktop的Linux文件共享说明

注意: 在Linux上的Docker Desktop会在一个虚拟机(VM)上启动,这个虚拟机会单独创建并使用一个自定义的Docker上下文,即desktop-linux。 这意味着在安装前,部署在Linux Docker引擎上的所有镜像与容器都无法在Docker Desktop中使用。[4]

此外,由于Docker Desktop是在VM上启动的,相比直接使用Docker引擎,预期性能会下降并且 CPU 使用率会提高。

GUI 工具[编辑 | 编辑源代码]

  • ducker — 一个用于管理docker容器的终端应用程序。
  • oxker-binAUR — 一个简单的 TUI程序,用于查看和控制 Docker 容器。
  • lazydockerAUR — 一个简单的 docker 和 docker-compose 管理TUI程序,使用 Go 语言和 gocui 库编写。
  • dokoAUR — 一个简单的docker TUI程序。
  • gomanagedockerAUR — 一款用于管理 Docker 对象的 TUI 程序。
  • whaler-gitAUR — 为 Pantheon 设计的 Docker 容器管理。
  • podman-desktopAUR — 从单一的用户界面和托盘管理 Podman以及其他容器引擎。
  • portainer-binAUR — 一款轻量级的 Docker 管理用户界面。
  • kitematicAUR — 可视化Docker 容器管理。

使用[编辑 | 编辑源代码]

Docker由多个部分组成:

  • Docker守护进程(也称Docker引擎),这是一个以docker.service形式运行的进程。其提供了Docker API接口并管理Docker容器。
  • docker CLI命令,其允许用户使用命令行来与Docker API交互,并控制 Docker 守护进程。
  • Docker容器,这是一种命名进程,由Docker守护进程通过Docker API的请求进行管理。

一般来说,用户通过使用docker命令行来对Docker进行操作,命令行又通过Docker API对Docker守护进程发起请求以执行对容器的相关操作。掌握客户端 (docker), 服务端(docker.service)和容器之间的关系是很必要的。

请注意,如果Docker守护进程停止/重启,那么当前运行的所有Docker容器也会停止/重启。

你也可以不借助docker CLI来对Docker API发起请求来控制容器,参见Docker API开发指南

更多使用文档请参见Docker入门指南

配置[编辑 | 编辑源代码]

Docker守护进程可以通过修改配置文件/etc/docker/daemon.json或者直接在docker.service中添加命令行标志来进行配置。根据Docker官方文档, 推荐使用修改配置文件的方法进行配置。如果你想使用添加命令行标志的方法进行配置,使用Systemd#附加配置片段覆盖docker.service中的ExecStart部分。

对于daemon.json中的选项,参见守护进程配置文件参考

存储驱动程序[编辑 | 编辑源代码]

存储驱动程序控制着Docker主机上的镜像与容器的储存与管理方式。默认的overlay2驱动在大部分情况下都具有良好的性能。

如果你的文件系统使用的是btrfs或者ZFS,你可以使用对应的btrfs或者zfs驱动,它们可以利用这些文件系统独有的功能,要使用这些驱动请参见btrfs驱动zfs驱动文档。

启用守护进程TCP套接字[编辑 | 编辑源代码]

本文内容或本节内容已经过期。

默认情况下,Docker守护进程使用位于/var/run/docker.sockUnix套接字来提供Docker API。大部分情况下,这是一个合适的选择。

你可以将设置守护进程设置为额外监听TCP套接字,这样就能使Docker API被远程访问了(参见允许远程访问Docker API)。如果你在Windows或macOS上使用Arch虚拟机,你可以在完成设置后使用宿主机上直接使用docker命令行访问虚拟机中允许的Docker守护进程。

警告: Docker API默认情况下既没有加密也没有身份验证。除非你在附加Docker配置中启用了 使用SSH或TLS进行连接,否则对Docker守护进程的TCP访问等同于不安全的远程root访问。

注意默认的docker.service设置了-H标志,如果选项同时存在于标志与/etc/docker/daemon.json文件中,Docker将不会启动,因此最简单的更改监听TCP套接字设置的方法是使用一个附加文件。例如,如果你想在端口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文档:如何配置代理,使用dockerCLI来自动为所有容器配置代理。

配置DNS[编辑 | 编辑源代码]

参见Docker中网络配置了解Docker容器内部的DNS行为以及如何自定义Docker的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来提供一个本地解析器,考虑为dnsmasq添加一个虚拟接口(使用169.254.0.0/16网段的链路本地IP地址来绑定,而不是127.0.0.1)以避免网络命名空间冲突。

镜像位置[编辑 | 编辑源代码]

默认,docker镜像放置在 /var/lib/docker。他们可以被移动到其他分区,例如你想将镜像移动到别的磁盘上,在这个例子中,假设我们要将镜像移动到/mnt/docker

首先, 停止docker.service,注意,这也会停止所有当前运行的容器并卸载任何正在运行的镜像。

如果你正在运行docker镜像,你必须确定镜像被完全解除挂载。一旦这个完成后,你就可以把镜像从 /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以应用更改。

不安全的自建仓库[编辑 | 编辑源代码]

如果您使用自签名证书的仓库(registries),或该自建仓库未使用TLS加密(即:http), 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支持,参见[5][6]

首先,将/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 NAT以解决使用私有IPv6子网时出现的路由问题:

# 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来创建的容器,你可能还需要在networks中对应的部分设置enable_ipv6: true。另外,你可能还需要手动指定IPv6子网,参见compose-file中的ipv6地址设置

用户命名空间隔离[编辑 | 编辑源代码]

默认情况下,Docker中的进程和dockerd主守护程序运行在同一用户命名空间中,即容器不会通过用户命名空间隔离(参见user_namespaces(7))。这将会允许进程根据用户和用户组#权限与属主在主机上来访问已配置的资源。这样提升了容器运行的兼容性,但是一旦出现了一个允许容器中进程访问非预期资源的漏洞,这会带来很大的安全隐患。(一个这样的漏洞在2019年2月发布并修补。)

启用用户命名空间隔离可以降低此类漏洞的影响。其将会在单独的用户命空间中运行每个容器,并将这个空间中的UIDs/GIDs映射到主机上不同的(通常情况下也是非特权的)UIDs/GIDs。

注意:
  • dockerd守护程序依然是以root身份在主机上运行的,在非root身份下运行docker(rootless mode)是另一个功能。
  • 容器中的进程将会以Dockerfile中定义的USER指令定义的用户身份启动。
  • 所有容器都会映射到相同的UID/GID范围,这是为了让容器之间的共享卷功能生效。
  • 在一些情况下无法启用用户命名空间。
  • 由于 Docker 需要调整这些资源的所有权,因此启用用户命名空间隔离会有效屏蔽现有的映像层和容器层,以及 /var/lib/docker/ 中的其他 Docker 对象。上游文档建议仅在新安装的Docker上启用此功能,而不是在现有的Docker上启用。

/etc/docker/daemon.json中配置userns-remap的值。default是一个特殊值,其会自动创建名为dockremap的用户与用户组用于重映射。

/etc/docker/daemon.json
{
  "userns-remap": "default"
}

/etc/subuid/etc/subgid中配置用户名/组名,UID/GID的范围。在这个例子中,dockremap用户/用户组分配为从165536开始的65536个UIDs/GIDs。

/etc/subuid
dockremap:165536:65536
/etc/subgid
dockremap:165536:65536

重启docker.service以应用更改。

应用此更改后,默认情况下所有容器都将在隔离的用户命名空间中运行。你也可以在docker命令中加上添加标志--userns=host来在特定的容器中禁用用户命名空间隔离,参见[7]

无根模式运行Docker守护程序(Docker rootless)[编辑 | 编辑源代码]

注意: 无根模式下运行Docker守护程序(Docker rootless)依赖于非特权用户命名空间(CONFIG_USER_NS_UNPRIVILEGED)。在linux, linux-lts, 和linux-zen内核中默认启用这一功能。如果你使用其他版本的内核,你可能需要手动启用这一功能。这可能带来一些安全隐患,参见安全#沙盒程序

要将Docker守护程序作为普通用户运行,安装 docker-rootless-extrasAUR软件包。

随后在/etc/subuid/etc/subgid中配置用户名/用户组名,起始 UID/GID 和 UID/GID 范围大小,以分配重新映射的用户和组。以下是一个示例:

/etc/subuid
your_username:165536:65536
/etc/subgid
your_username:165536:65536

启用 docker.socket systemd/用户单元: 这将会使用systemd的套接字激活来启动docker。

最后设置docker套接字的环境变量:

$ export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock

启用本地覆盖差异引擎(native overlay diff engine)[编辑 | 编辑源代码]

默认情况下Docker无法在Arch Linux上使用本地覆盖差异引擎(native overlay diff engine),这会导致构建Docker镜像很慢。如果你经常构建镜像,请按照以下步骤配置:

/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 image.这是一个arch内核的剥离版本,没有网络等等.

# docker pull archlinux

也可查阅 README.md.

对于完整的arch基础,可以从下面克隆镜像并且建立你自己的镜像.

$ git clone https://gitlab.archlinux.org/archlinux/archlinux-docker.git

请确保devtools, fakechroot以及fakeroot软件包已被安装。

编辑包文件让它只含有 '基础'. 运行:

# make docker-image

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(或其他没有使用musl libc实现的发行版)上编译的动态链接软件在Alpine Linux (或其他使用musl libc的镜像)上可能会出现错误或性能问题。参见[8], [9][10]

Debian[编辑 | 编辑源代码]

下面的命令会拉取Debian镜像 debian x86_64 image.

# docker pull debian

请参阅Docker Hub页面查看可用标签的完整列表,包括每个Debian版本的标准版与精简版。

手动[编辑 | 编辑源代码]

debootstrap建立Debian镜像:

# mkdir jessie-chroot
# debootstrap jessie ./jessie-chroot http://http.debian.net/debian/
# cd jessie-chroot
# tar cpf - . | docker import - debian
# docker run -t -i --rm debian /bin/bash

Distroless[编辑 | 编辑源代码]

Google 维护着distroless镜像,这是没有基本操作系统组件(例如shells和包管理器)的最小化镜像。其最小镜像gcr.io/distroless/static-debian11仅有2MiB左右,可以用于打包软件并生成非常小的镜像。

请参阅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

运行容器中的图像程序[编辑 | 编辑源代码]

本节介绍了允许在主机的X服务器上运行图形程序(包括依赖于OpenGL或Vulkan的程序)所需的步骤。

首先,需要在容器内安装与主机图形硬件兼容的正确驱动程序。如果容器使用的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允许容器直接访问主机上的直接渲染(DRI) 设备。

为了验证设置是否生效,请在容器中运行mesa-utils中的glxgears命令(或者vulkan-tools中的vkcube命令)。

开机启动 Docker Compose 项目[编辑 | 编辑源代码]

本文或本章节的事实准确性存在争议。

原因: 没有必要在compose.yml中启用restart: always(讨论请参见[11])。[12](在 Talk:Docker#"开机启动 Docker Compose 项目" 是否多余? 中讨论)


首先,创建一个用于Docker Compose的Systemed单元,并通过服务名称进行参数化(参见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文件)[13]

最后, 启用/启动 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容器[编辑 | 编辑源代码]

从19.03版本开始,Docker原生支持NVIDIA GPU作为Docker设备。 推荐使用NVIDIA Container Toolkit来运行需要操作NVIDIA显卡的容器。 安装 nvidia-container-toolkit 包并重启Docker。之后可以用--gpus选项来运行使用NVIDIA显卡的容器

使用 --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

本文或本章节的事实准确性存在争议。

原因: More information on when the following error happens is needed. It should work, see [14][失效链接 2023-04-23 ⓘ].(在 Talk:Docker#GPU accelerated Docker Nvidia 中讨论)


如果在执行指令时收到错误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

指定需要的具体功能(图像、计算等)

# docker run --gpus all,capabilities=utility nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

参阅 container-toolkit文档安装指南

使用 NVIDIA Container Runtime[编辑 | 编辑源代码]

编辑/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

或 (要求 Docker 版本19.03或更高)

# docker run --gpus all nvidia/cuda:9.0-base nvidia-smi

参阅 README.md

有CUDA的 Arch Linux 镜像[编辑 | 编辑源代码]

可使用以下Dockerfile 构建自定义的有CUDA的 Arch Linux 镜像。它使用 Dockerfile frontend syntax 1.2 在宿主机上缓存pacman包。请注意,你必须在构建镜像之前设置环境变量DOCKER_BUILDKIT=1

Dockerfile
# syntax = docker/dockerfile:1.2

FROM archlinux

# 使用更快的镜像 
RUN echo 'Server = https://mirror.pkgbuild.com/$repo/os/$arch' > /etc/pacman.d/mirrorlist

# 安装包
RUN --mount=type=cache,sharing=locked,target=/var/cache/pacman \
    pacman -Syu --noconfirm --needed base base-devel cuda

# 配置 nvidia container runtime
# https://github.com/NVIDIA/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 网桥无法获取 IP / Internet 到容器[编辑 | 编辑源代码]

Docker会自己启用IP转发,但是默认 systemd-networkd 会覆盖对应的sysctl设置,在网络配置文件里设置 IPForward=yes。查阅网络分享#启用包转发获取细节。

systemd-networkd尝试管理由Docker创建的网络时,如果你在Match部分设置了Name=*Type=ether,这可能会导致网络连接出现问题。请更为具体地配置接口,即尽可能避免使用Name=*Type=ether等通配符来匹配Docker管理的接口。你可以验证 networkctl list 是否在 Docker 创建的所有网络的 SETUP 栏中设置为 unmanaged

注意:
  • 你可能需要在每次 重启 systemd-networkd.service 或者 iptables.service 之后,再手动重启 docker.service
  • 注意nftables默认情况下可能会禁止Docker的连接,你可以使用命令 nft list ruleset 来检查规则集。
  • 你可以使用 nft flush chain inet filter forward 来临时移除所有转发规则,或者编辑 /etc/nftables.conf 文件使其永久生效。在更改了配置文件,请 重启 nftables.service 以应用更改。详细了解Docker的nftables支持请参见 [15]

默认的允许的进程/线程数太少[编辑 | 编辑源代码]

如果你允许时得到下面的错误信息

# e.g. Java
java.lang.OutOfMemoryError: unable to create new native thread
# e.g. C, bash, ...
fork failed: Resource temporarily unavailable

那么你可能需要调整被systemd允许的进程数, 编辑并添加下面片段 docker.service :

# systemctl edit docker.service
[Service]
TasksMax=infinity

对于更多参数,例如 DefaultLimitNPROC,请参阅 systemd-system.conf(5) § OPTIONS。对于 TasksMax 请参阅 systemd.resource-control(5) § OPTIONS

初始化显卡驱动错误: devmapper[编辑 | 编辑源代码]

如果 systemctl 不能开启docker并提供了以下信息:

Error starting daemon: error initializing graphdriver: devmapper: Device docker-8:2-915035-pool is not a thin pool

那么尝试以下步骤来解决错误。停止docker服务,备份 /var/lib/docker/ (如果需要的话), 移除/var/lib/docker/的内容, 尝试重启docker服务. 查阅 GitHub issue 获取更多细节.

无法创建到某文件的路径: 设备没有多余的空间了[编辑 | 编辑源代码]

如果你获取到的错误信息是像这样的话:

ERROR: Failed to create some/path/to/file: No space left on device

当创建或者运行Docker镜像时,尽管磁盘还有多余的空间。所以请确保:

  • Tmpfs 被禁用了并且有足够的内存分配. Docker可能会尝试写入文件到 /tmp 但是失败了因为内存使用的限制和磁盘空间不足.
  • 如果你在使用 XFS, 你可能得从相关入口移除 noquota 挂载选项在 /etc/fstab里 (通常是 /tmp 和/或 /var/lib/docker 在的地方). 查阅 Disk quota 获取更多信息, 特别是你计划使用和调整 overlay2 Docker 存储驱动.
  • XFS 的配额挂载选项在文件系统重新挂载时 (uquota, gquota, prjquota, 等等.) 失败了. 为了为root文件系统启用配额挂载选项必须作为内核参数 rootflags=传递到initramfs. 之后, 它就不应该在 /etc/fstab中的挂载选项中列出root (/) 文件系统.
注意: XFS配额和标准LinuxDisk quota, [16] 是有区别的。这里值得一读.

Docker-machine无法使用virtualbox驱动程序创建虚拟机[编辑 | 编辑源代码]

如果docker-machine 无法使用 virtualbox 驱动程序创建虚拟机并提供了以下信息:

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的配置文件来解决这个问题,参见[17]将配置文件修改为:
/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 RegistryQuay Container Registry

使用Docker CLI 中的 pull, tag 以及 push 命令来镜像一个镜像。例如,将 Nginx 标签(tag)为 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 (旧版): 未知选项 "--dport"[编辑 | 编辑源代码]

本文或本章节的事实准确性存在争议。

原因: Nftables#与 Docker 一起工作 建议不要使用 iptables-nft。(在 Talk:Docker 中讨论)

如果你在运行容器时收到了这样的错误: iptables (legacy): unknown option "--dport"

安装 iptables-nft 而不是 iptables (旧版) 然后重启[18]

注意: 使用iptables-nft可能会导致docker 混合 nftables 和 iptables 规则,详细参见Nftables#与 Docker 一起工作

运行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 issue, 默认选项是:

Type Default Size Default Pool
local /16 172.17.0.0/12
local* /20 192.168.0.0/16

你可以在 /etc/docker/daemon.json 文件中修改 default-address-pools ,将其中第一个IP范围的值从16改为24解决这个问题。为了避免本地网络发生IP冲突,请不要修改第二个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..."处卡住)。

这是因为[19] [20],你可以尝试将 --ulimit "nofile=1024:524288" 添加到你的docker构建选项中来解决问题:

/etc/docker/daemon.json
{
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Soft": 1024,
      "Hard": 524288
    }
  }
} 

查阅更多[编辑 | 编辑源代码]