Docker (简体中文)

From ArchWiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
翻译状态:本文是 Docker翻译。上次翻译日期:2018-10-22。如果英文版本有所更改,则您可以帮助同步翻译。

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

安装

安装 docker 包 或者,对于开发版本,选择docker-gitAUR 包. 下一步 启动 docker.service 然后验证操作:

# docker info

注意, 如果你有一个活动的 VPN 连接, 那么 docker 服务的启动可能失败, 因为 VPN 和 Docker 的网桥 IP 冲突以及网络覆盖. 如果发生了这种事, 尝试在启动 docker 服务之前断开 VPN 连接. 你可以在之后立刻重连 VPN. You can also try to deconflict the networks.

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

警告: 任何加入到 docker 组的用户都和root用户等价,因为他们可以通过# docker run --privileged来以root权限启动容器。 查阅更多信息可访问 这里这里.

配置

存储驱动程序

docker存储驱动 (或者是显卡驱动) 对性能有巨大影响. 它的工作是高效存储容器镜像层,也就是许多镜像共享一个层时只有一个层使用磁盘空间。作为兼容选项, `devicemapper` 提供了次优性能, 这在机械硬盘上是非常糟糕的. 例外, `devicemapper` 不建议在生产中使用.

随着arch Linux发布新的内核,没有必要使用兼容选项了。一个好的现代选择是 overlay2.

想看现在的存储驱动, 运行 # docker info | head; 现代docker安装应该已经默认使用 overlay2 了.

想设置你自己的存储驱动选项, 编辑 /etc/docker/daemon.json (如果不存在就自己创建):

/etc/docker/daemon.json
{
  "storage-driver": "overlay2"
}

然后, 重启 docker.

更多的选项信息能在 用户指南查阅. 更多的 daemon.json 选项查阅 docker 文档.

远程 API

手动打开远程 API 端口 4243 , 运行:

# /usr/bin/dockerd -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock

-H tcp://0.0.0.0:4243 部分是用来打开远程 API的.

-H unix:///var/run/docker.sock 部分是通过终端连接主机的.

用systemd打开远程API

如果要用docker守护进程开启远程API, 创建一个 Drop-in snippet ,内容如下:

/etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock

守护进程socket配置

docker 守护进场默认监听 Unix socket .如果要监听特定端口的话, 创建一个 Drop-in snippet ,内容如下:

/etc/systemd/system/docker.socket.d/socket.conf
[Socket]
ListenStream=0.0.0.0:2375

代理

代理配置分为两部分。一部分是主机docker守护进程的配置,另一部分是让容器检测到代理的配置

代理配置

创建一个 Drop-in snippet 内容如下:

/etc/systemd/system/docker.service.d/proxy.conf
[Service]
Environment="HTTP_PROXY=192.168.1.1:8080"
Environment="HTTPS_PROXY=192.168.1.1:8080"
注意: 这假定 192.168.1.1 是你的代理服务器,不要使用 127.0.0.1.

确定配置被加载了:

# systemctl show docker --property Environment
Environment=HTTP_PROXY=192.168.1.1:8080 HTTPS_PROXY=192.168.1.1:8080

容器配置

docker.service 文件里的设置并不会进入到容器里. 要实现这样的话必须设置 ENV 变量在你的 Dockerfile 里:

FROM base/archlinux
ENV http_proxy="http://192.168.1.1:3128"
ENV https_proxy="https://192.168.1.1:3128"

Docker 提供了配置的细节信息,通过Dockerfile的 ENV .

配置 DNS

默认的,docker会让容器里的 resolv.conf 和主机里的 /etc/resolv.conf 匹配, 并过滤掉本地地址 (e.g. 127.0.0.1). 如果这产生了一个空文件, 那么 Google DNS servers 就会被使用. 如果你用的是 dnsmasq (简体中文) 一样的服务来提供域名解析的话, 你可能需要在 /etc/resolv.conf 添加入口给docker网络借口让它不被过滤掉.

在systemd-networkd用手动定义的网络运行Docker

如果你是手动配置的网络,用的是 systemd-networkd 版本 220 或者更高, 你运行的容器可能无法连接网络. 从版本 220开始, 对于给定网络 (net.ipv4.conf.<interface>.forwarding) 的转发设置默认是 off. 这个设置阻止了IP转发. 它会与在容器里启用了 net.ipv4.conf.all.forwarding 设置的docker冲突

一个解决办法是编辑 在/etc/systemd/network/里的<interface>.network文件 , 添加 IPForward=kernel 到docker主机:

/etc/systemd/network/<interface>.network
[Network]
...
IPForward=kernel
...

这项设置像预期一样允许来自容器的IP转发.

镜像位置

默认,docker镜像放置在 /var/lib/docker. 他们可以被移动到其他分区. 首先, 停止 the docker.service.

如果你正在运行docker镜像,你必须确定镜像被完全解除挂载。一旦这个完成后,你就可以把镜像从 /var/lib/docker 移动到你的目标地点.

然后为docker.service添加 Drop-in snippet,加入 -g 参数到 ExecStart:

/etc/systemd/system/docker.service.d/docker-storage.conf
[Service]
ExecStart= 
ExecStart=/usr/bin/dockerd --data-root=/path/to/new/location/docker -H fd://

不安全的注册

如果你想用自签名的证书, docker会拒绝它直到你定义你相信它. 为docker.service添加 Drop-in snippet, 添加 --insecure-registry参数到 dockerd:

/etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --insecure-registry my.registry.name:5000

镜像

Arch Linux

下面的命令会拉取 archlinux x86_64 image.这是一个arch内核的剥离版本,没有网络等等.

# docker pull archlinux

也可查阅 README.md.

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

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

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

# make docker-image

Debian

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

# docker pull 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

用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:9.0-base nvidia-smi

指定容器内可使用多少GPU:

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

指定使用哪一个GPU:

# docker run --gpus '"device=1,2"' nvidia/cuda:9.0-base nvidia-smi

# docker run --gpus '"device=UUID-ABCDEF,1"' nvidia/cuda:9.0-base nvidia-smi

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

# docker run --gpus all,capabilities=utility nvidia/cuda:9.0-base nvidia-smi

参阅 README.mdWiki.

使用 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 -Suy --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数据 (清除目录):

Tango-inaccurate.pngThe factual accuracy of this article or section is disputed.Tango-inaccurate.png

Reason: 执行 # rm -R /var/lib/docker 将会留下已删除容器的btrfs子卷 (Discuss in Talk:Docker (简体中文))
# rm -R /var/lib/docker

有用的建议

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

故障排除

docker0 网桥无法获取 IP / internet 到容器

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

注意: 你可能需要在每次 restart systemd-networkd.service 或者 iptables.service 之后手动重启 docker.service

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

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

# 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文件系统启用配额挂载选项必须作为 Kernel parameters (简体中文) rootflags=传递到initramfs. 之后, 它就不应该在 /etc/fstab中的挂载选项中列出root (/) 文件系统.
注意: XFS配额和标准LinuxDisk quota, [1] 是有区别的。这里值得一读.

kernel 4.19.1下无效的跨设备链接

如果像 dpkg 这样的命令在docker运行失败, 比如:

dpkg: error: error creating new backup file '/var/lib/dpkg/status-old': Invalid cross-device link

可以 添加 overlay.metacopy=N kernel parameter 或者降级到 4.18.x 直到 这个 issue 被解决. 更多信息查看 Arch forum.

查阅更多