来自 Arch Linux 中文维基

本文或本节需要翻译。要贡献翻译,请访问简体中文翻译团队

附注: 请完成翻译。(在 Talk:Docker# 中讨论)

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

安装

要拉取Docker镜像并运行Docker容器,你需要安装Docker引擎,其包含包括一个守护进程来管理容器,以及一个docker命令行界面前端。安装 docker 包 或者,对于开发版本,选择docker-gitAUR 包. 下一步 启动 docker.service 然后验证操作:

# 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 Compose

Docker Compose是另一种Docker引擎的CLI前端,它使用docker-compose.ymlYAML文件来指定容器的属性,这样就可以不使用附带指令的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-compose。如果你想保留现有的软件包,你也可以从AUR安装docker-desktopAUR,它将不会与现有软件包发生冲突。

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

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

使用

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驱动具有良好的性能,并且它在现代的Linux内核与文件系统上运行良好。还有一些较老的驱动程序,例如devicemapperaufs,它们旨在与旧版本的Linux内核兼容,但是在Arch Linux上对比起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守护进程的TCP访问等同于不安全的远程root访问。除非同时启用了 TLS 加密和授权(通过认证的 HTTP 反向代理或适当的 附加Docker配置。一般来说,启用Docker API TCP套接字应视为高风险操作。

注意默认的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文档:设置systemd的drop-in单元以配置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以应用更改。

不安全的注册

如果你想用自签名的证书, docker会拒绝它直到你定义你相信它. 例如,要信任托管于myregistry.example.com:8443上的镜像,在文件/etc/docker/daemon.json中配置insecure-registries的值:

{{hc|/etc/docker/daemon.json|2= {

 "insecure-registries": [
   "my.registry.example.com:8443"
 ]

}

IPv6

为了开启Docker中的IPv6支持,参见[4][5]

首先,将/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来在特定的容器中禁用用户命名空间隔离,参见[6]

无根模式运行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

Enable native overlay diff engine

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

原因: This may not be necessary on your system. Though metacopy=on redirect_dir=on is the default on Arch Linux kernels, some report those settings getting disabled during runtime.(在 Talk:Docker#Native overlay diff 中讨论)


By default, Docker cannot use the native overlay diff engine on Arch Linux, which makes building Docker images slow. If you frequently build images, configure the native diff engine as described in [7]:

/etc/modprobe.d/disable-overlay-redirect-dir.conf
options overlay metacopy=off redirect_dir=off

Then stop docker.service, reload the overlay module as follows:

# modprobe -r overlay
# modprobe overlay

You can then start docker.service again.

To verify, run docker info and check that Native Overlay Diff is 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 maintains distroless images which are minimal images without OS components such as package managers or shells, resulting in very small images for packaging software.

See the GitHub README for a list of images and instructions on their use with various programming languages.

有用的建议

抓取运行容器的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

Run graphical programs inside a container

This section describes the necessary steps to allow graphical programs (including those that rely on OpenGL or Vulkan) to run on the host's X server.

First, the correct drivers, compatible with the host's graphics hardware, need to be installed inside the container. The installation procedure depends on the type of the container, but for containers based on Arch Linux images, refer to OpenGL#Installation and Vulkan#Installation for packages specific to your hardware.

Next, the container must be granted access to the host's X server. In a single-user environment, this can easily be done by running Xhost on the host system, which adds non-network local connections to the access control list:

$ xhost +local:

Lastly, the following parameters need to be passed to docker run:

  • -e "DISPLAY=$DISPLAY" sets the environment variable DISPLAY within the container to the host's display;
  • --mount type=bind,src=/tmp/.X11-unix,dst=/tmp/.X11-unix mounts the host's X server sockets inside the container under the same path;
  • --device=/dev/dri:/dev/dri gives the container access to Direct Rendering Infrastructure devices on the host.

To confirm that everything is set up correctly, run glxgears from the package mesa-utils, or vkcube from the package vulkan-tools in the container.

Start Docker Compose projects on boot

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

原因: This is not necessary with restart: always in the compose.yml. [11](在 Talk:Docker#"Start Docker Compose projects on boot" Spurious? 中讨论)


First, create a template unit for Docker Compose which is parameterized by the name of the service (see 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

Then, for each service you would like to run, set up a directory with the Compose file and any other required files (such as .env files) at /opt/project_name. [12]

Then, enable/start docker-compose@project_name.service.

Using buildx for cross-compiling

The buildx CLI plugin makes use of the new BuildKit building toolkit. Install the docker-buildx package. The buildx interface supports building multi-platform images, including architectures other than that of the host.

QEMU is required to cross-compile images. To setup the static build of QEMU within Docker, see the usage information for the multiarch/qemu-user-static image. Otherwise, to setup QEMU on the host system for use with Docker, see QEMU#Chrooting into arm/arm64 environment from x86_64. In either case, your system will be configured for user-mode emulation of the guest architecture.

$ 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容器

使用NVIDIA Container Toolkit (推荐)

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

# 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 [13][失效链接 2023-04-23 ⓘ].(在 Talk:Docker#GPU accelerated Docker Nvidia 中讨论)


If, when using the above commands, you receive an error such as Failed to initialize NVML: Unknown Error, you can try being more specific in specifying the 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

参阅 README.mdWiki.

If you have VirtualGL installed and get the NVML error, replace

/etc/nvidia-container-runtime/config.toml
#user = "root:video"

with

user = "root:root"

For more information see the issue at NVIDIA/nvidia-docker at GitHub

使用 NVIDIA Container Runtime

安装 nvidia-container-runtimeAUR 包. 之后,编辑/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.

使用 nvidia-docker (已废弃)

nvidia-docker is a wrapper around NVIDIA Container Runtime which registers the NVIDIA runtime by default and provides the nvidia-docker command.

To use nvidia-docker, install the nvidia-dockerAUR package and then 重启 docker. Containers with NVIDIA GPU support can then be run using any of the following methods:

# docker run --runtime=nvidia nvidia/cuda:9.0-base nvidia-smi
# nvidia-docker run nvidia/cuda:9.0-base nvidia-smi

or (required Docker version 19.03 or higher)

# docker run --gpus all nvidia/cuda:9.0-base nvidia-smi
注意: nvidia-docker 是直到Docker 19.03版本,运行 NVIDIA GPU加速的容器的遗留方法,已被废弃。如果使用19.03版本或更高Docker,建议使用NVIDIA Container Toolkit 替代。

有CUDA的 Arch Linux 镜像

可使用以下Dockerfile 构建自定义的有CUDA的 Arch Linux 镜像。它使用 Dockerfile frontend syntax 1.2 在宿主机上缓存pacman包。DOCKER_BUILDKIT=1 environment variable 必须于构建镜像之前设置。

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>

Delete all images, containers, volumes, and networks that are not associated with a container (dangling):

# docker system prune

To additionally remove any stopped containers and all unused images (not just dangling ones), add the -a flag to the command:

# docker system prune -a

删除所有docker数据 (清除目录):

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

原因: 执行 # rm -R /var/lib/docker 将会留下已删除容器的btrfs子卷(在 Talk:Docker 中讨论)


# rm -R /var/lib/docker

故障排除

使用systemd-networkd时,docker0 网桥无法获取 IP / internet 到容器

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

When systemd-networkd tries to manage the network interfaces created by Docker, e.g. when you configured Name=* in the Match section, this can lead to connectivity issues. The problem should be solved by matching interfaces more specifically, i.e. avoid using Name=* or other wildcard that matches an interface managed by Docker. Verify that networkctl list reports unmanaged in the SETUP column for all networks created by Docker.

注意:
  • 你可能需要在每次 restart systemd-networkd.service 或者 iptables.service 之后手动重启 docker.service.
  • Also be aware that nftables may block docker connections by default. Use nft list ruleset to check for blocking rules. nft flush chain inet filter forward removes all forwarding rules temporarily. Edit /etc/nftables.conf to make changes permanent. Remember to restart nftables.service to reload rules from the configuration file. See [14] for details about nftables support in Docker.

默认的允许的进程/线程数太少

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

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

那么你可能需要调整被systemd允许的进程数. 默认的是 500 (see system.conf), 这对需要允许几个容器的话太少了. Edit 并添加下面片段 docker.service :

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

初始化显卡驱动错误: 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, [15] 是有区别的。这里值得一读.

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。

Starting Docker breaks KVM bridged networking

The issue is that Docker's scripts add some iptables rules to block forwarding on other interfaces other than its own. This is a known issue.

Adjust the solutions below to replace br0 with your own bridge name.

Quickest fix (but turns off all Docker's iptables self-added adjustments, which you may not want):

/etc/docker/daemon.json
{
  "iptables": false
}

If there is already a network bridge configured for KVM, this may be fixable by telling docker about it. See [16] where docker configuration is modified as:

/etc/docker/daemon.json
{
  "bridge": "br0"
}

If the above does not work, or you prefer to solve the issue through iptables directly, or through a manager like UFW, add this:

iptables -I FORWARD -i br0 -o br0 -j ACCEPT

Even more detailed solutions are here.

Image pulls from Docker Hub are rate limited

Beginning on November 1st 2020, rate limiting is enabled for downloads from Docker Hub from anonymous and free accounts. See the rate limit documentation for more information.

Unauthenticated rate limits are tracked by source IP. Authenticated rate limits are tracked by account.

If you need to exceed the rate limits, you can either sign up for a paid plan or mirror the images you need to a different image registry. You can host your own registry or use a cloud hosted registry such as Amazon ECR, Google Container Registry, Azure Container Registry or Quay Container Registry.

To mirror an image, use the pull, tag and push subcommands of the Docker CLI. For example, to mirror the 1.19.3 tag of the Nginx image to a registry hosted at 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

You can then pull or run the image from the mirror:

$ docker pull cr.example.com/nginx:1.19.3
$ docker run cr.example.com/nginx:1.19.3

iptables (legacy): unknown option "--dport"

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

原因: Nftables#Working with Docker advises to not use iptables-nft.(在 Talk:Docker 中讨论)


If you see this error when running a container, install iptables-nft instead of iptables (legacy) and reboot[17].

"Your password will be stored unencrypted" when running docker login

By default Docker will try to use the pass or secretservice binaries to store your registry passwords. If they are not found, it will store them in plain text (base64-encoded) in $HOME/.docker/config.json and print the following message after successfully logging in:

$ WARNING! Your password will be stored unencrypted in /home/username/.docker/config.json.

If you are using a password manager that implements the Secret Service Freedesktop DBUS API, like KDE's kwallet or GNOME's gnome-keyring, you can install the docker-credential-secretserviceAUR package to store your passwords in them.

"Could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network"

Sometimes if you use a lot of Docker projects (ex. using docker-compose) it can happens that you run out of available IPs for Docker containers triggering the error:

Could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network

As found on this Docker issue, the defaults are:

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

This can be easily fixed increasing the Docker IP space by configuring default-address-pools in /etc/docker/daemon.json increasing the size value from 16 to 24 on the first IP range, keeping the second one unaltered to avoid ip collision on the local network:

/etc/docker/daemon.json
{
  ...
  "default-address-pools" : [
    {
      "base" : "172.17.0.0/12",
      "size" : 24
    },
    {
      "base" : "192.168.0.0/16",
      "size" : 24
    }
  ]
}

Restart docker.service to apply changes.

More details and technical explanations can be found on the following excellent article: The definitive guide to docker's default-address-pools option.

查阅更多