Docker
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 Compose[编辑 | 编辑源代码]
Docker Compose是另一种Docker引擎的CLI前端,它使用docker-compose.yml
YAML文件来指定容器的属性,这样就可以不使用附带指令的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内核与文件系统上运行良好。还有一些较老的驱动程序,例如devicemapper
与aufs
,它们旨在与旧版本的Linux内核兼容,但是在Arch Linux上对比起overlay2
没有任何优势。
如果你的文件系统使用的是btrfs或者ZFS,你可以使用对应的btrfs
或者zfs
驱动,它们可以利用这些文件系统独有的功能,要使用这些驱动请参见btrfs驱动或zfs驱动文档。
启用守护进程TCP套接字[编辑 | 编辑源代码]
默认情况下,Docker守护进程使用位于/var/run/docker.sock
的Unix套接字来提供Docker API。大部分情况下,这是一个合适的选择。
你可以将设置守护进程设置为额外监听TCP套接字,这样就能使Docker API被远程访问了(参见允许远程访问Docker API)。如果你在Windows或macOS上使用Arch虚拟机,你可以在完成设置后使用宿主机上直接使用docker
命令行访问虚拟机中允许的Docker守护进程。
注意默认的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文档:如何配置代理,使用docker
CLI来自动为所有容器配置代理。
配置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[编辑 | 编辑源代码]
首先,将/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)[编辑 | 编辑源代码]
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的镜像)上可能会出现错误或性能问题。参见[7], [8]和[9]。
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 项目[编辑 | 编辑源代码]
首先,创建一个用于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
文件)[12]。
最后, 启用/启动 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容器[编辑 | 编辑源代码]
使用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
如果在执行指令时收到错误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文档 与 安装指南。
如果你安装了VirtualGL并且收到了NVML错误,请将:
/etc/nvidia-container-runtime/config.toml
#user = "root:video"
改为
user = "root:root"
参见[14]。
使用 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是NVIDIA容器运行时的封装,它默认注册了NVIDIA运行时并提供了nvidia-docker命令。
要使用nvidia-docker,安装nvidia-dockerAUR 随后 重启 docker。然后你可以使用以下任一方法来运行支持NVIDIA GPU的容器:
# docker run --runtime=nvidia nvidia/cuda:9.0-base nvidia-smi
# nvidia-docker run nvidia/cuda:9.0-base nvidia-smi
或者(需要Docker版本19.03或更高)
# docker run --gpus all nvidia/cuda:9.0-base nvidia-smi
有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
. 查阅 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 restartnftables.service
to reload rules from the configuration file. See [15] 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 (/
) 文件系统.
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 [17] 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"[编辑 | 编辑源代码]
If you see this error when running a container, install iptables-nft包 instead of iptables包 (legacy) and reboot[18].
"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.