运行容器

Docker 在隔离的容器中运行进程。容器是在主机上运行的进程。主机可以是本地的或远程的。当您执行时docker run,运行的容器进程是隔离的,因为它有自己的文件系统、自己的网络以及与主机分开的自己的隔离进程树。

本页详细介绍了如何使用该docker run命令来运行容器。

一般形式

命令docker run采用以下形式:

$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

docker run命令必须指定 用于创建容器的图像引用。

图片参考

图像参考是图像的名称和版本。您可以使用镜像引用来创建或运行基于镜像的容器。

  • docker run IMAGE[:TAG][@DIGEST]
  • docker create IMAGE[:TAG][@DIGEST]

图像标签是图像版本,latest省略时默认为图像版本。使用该标签从特定版本的映像运行容器。例如,要运行图像23.10的版本ubuntudocker run ubuntu:23.10.

图像摘要

使用 v2 或更高版本图像格式的图像具有称为摘要的内容可寻址标识符。只要用于生成图像的输入不变,摘要值就是可预测的。

以下示例从alpine带有 sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0摘要的映像运行一个容器:

$ docker run alpine@sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0 date

选项

[OPTIONS]让您配置容器的选项。例如,您可以为容器命名 ( --name),或将其作为后台进程运行 ( -d)。您还可以设置选项来控制资源限制和网络等内容。

命令和参数

您可以使用[COMMAND][ARG...]位置参数来指定容器启动时要运行的命令和参数。例如,您可以指定sh与和标志[COMMAND]组合,以在容器中启动交互式 shell(如果您选择的映像 在 上有可执行文件)。-i-tshPATH

$ docker run -it IMAGE sh

笔记

根据您的 Docker 系统配置,您可能需要在docker run命令前面加上sudo.为了避免使用sudodocker命令,系统管理员可以创建一个名为 的 Unix 组docker并向其中添加用户。有关此配置的更多信息,请参阅适用于您的操作系统的 Docker 安装文档。

前景和背景

当启动容器时,容器默认在前台运行。如果您想在后台运行容器,可以使用 --detach(或-d) 标志。这将启动容器而不占用终端窗口。

$ docker run -d <IMAGE>

当容器在后台运行时,您可以使用其他 CLI 命令与容器交互。例如,docker logs允许您查看容器的日志,并将docker attach其带到前台。

$ docker run -d nginx
0246aa4d1448a401cabd2ce8f242192b6e7af721527e48a810463366c7ff54f1
$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS        PORTS     NAMES
0246aa4d1448   nginx     "/docker-entrypoint.…"   2 seconds ago   Up 1 second   80/tcp    pedantic_liskov
$ docker logs -n 5 0246aa4d1448
2023/11/06 15:58:23 [notice] 1#1: start worker process 33
2023/11/06 15:58:23 [notice] 1#1: start worker process 34
2023/11/06 15:58:23 [notice] 1#1: start worker process 35
2023/11/06 15:58:23 [notice] 1#1: start worker process 36
2023/11/06 15:58:23 [notice] 1#1: start worker process 37
$ docker attach 0246aa4d1448
^C
2023/11/06 15:58:40 [notice] 1#1: signal 2 (SIGINT) received, exiting
...

docker run有关与前台和后台模式相关的标志的更多信息,请参阅:

有关重新附加到后台容器的更多信息,请参阅 docker attach

集装箱识别

您可以通过三种方式识别容器:

标识符类型示例值
UUID长标识符f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778
UUID短标识符f78375b1c487
姓名evil_ptolemy

UUID 标识符是守护程序分配给容器的随机 ID。

守护进程自动为容器生成一个随机字符串名称。您还可以使用 flag定义--name自定义名称 。定义 aname可以是为容器添加含义的便捷方法。如果指定 a name,则可以在引用用户定义网络中的容器时使用它。这适用于后台和前台 Docker 容器。

容器标识符与图像引用不同。镜像引用指定运行容器时要使用的镜像。您无法运行 docker exec nginx:alpine sh以在基于映像的容器中打开 shell nginx:alpine,因为docker exec需要容器标识符(名称或 ID),而不是映像。

虽然容器使用的镜像不是容器的标识符,但您可以通过标志找到使用镜像的容器的 ID --filter。例如,以下docker ps命令根据镜像获取所有正在运行的容器的ID nginx:alpine

$ docker ps -q --filter ancestor=nginx:alpine

有关使用过滤器的更多信息,请参阅 过滤

容器网络

容器默认启用网络,并且可以建立传出连接。如果您正在运行多个需要相互通信的容器,则可以创建自定义网络并将容器附加到网络。

当多个容器连接到同一自定义网络时,它们可以使用容器名称作为 DNS 主机名相互通信。以下示例创建一个名为 的自定义网络my-net,并运行连接到该网络的两个容器。

$ docker network create my-net
$ docker run -d --name web --network my-net nginx:alpine
$ docker run --rm -it --network my-net busybox
/ # ping web
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.326 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.257 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.281 ms
^C
--- web ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.257/0.288/0.326 ms

有关容器网络的更多信息,请参阅 网络概述

文件系统挂载

默认情况下,容器中的数据存储在临时的、可写的容器层中。删除容器也会删除其数据。如果您想在容器中使用持久数据,可以使用文件系统挂载将数据持久存储在主机系统上。文件系统挂载还可以让您在容器和主机之间共享数据。

Docker 支持两大类挂载:

  • 卷安装
  • 绑定坐骑

卷挂载非常适合持久存储容器数据以及在容器之间共享数据。另一方面,绑定挂载用于在容器和主机之间共享数据。

--mount您可以使用该命令的标志 将文件系统挂载添加到容器docker run

以下部分显示了如何创建卷和绑定安装的基本示例。有关更深入的示例和说明,请参阅 文档中存储部分的部分。

卷安装

要创建卷安装:

$ docker run --mount source=<VOLUME_NAME>,target=[PATH] [IMAGE] [COMMAND...]

在这种情况下,该--mount标志采用两个参数:sourcetarget。该参数的值source是卷的名称。的值 target是容器内卷的安装位置。创建卷后,写入该卷的任何数据都会保留,即使您停止或删除容器也是如此:

$ docker run --rm --mount source=my_volume,target=/foo busybox \
  echo "hello, volume!" > /foo/hello.txt
$ docker run --mount source=my_volume,target=/bar busybox
  cat /bar/hello.txt
hello, volume!

必须target始终是绝对路径,例如/src/docs.绝对路径以/(正斜杠)开头。卷名称必须以字母数字字符开头,后跟a-z0-9_(下划线)、.(句点)或 -(连字符)。

绑定坐骑

要创建绑定安装:

$ docker run -it --mount type=bind,source=[PATH],target=[PATH] busybox

在本例中,该--mount标志采用三个参数。一个类型 ( bind) 和两个路径。该source路径是主机上要绑定安装到容器中的位置。该target路径是容器内的挂载目的地。

默认情况下,绑定挂载是读写的,这意味着您可以从容器的挂载位置读取和写入文件。您所做的更改(例如添加或编辑文件)会反映在主机文件系统上:

$ docker run -it --mount type=bind,source=.,target=/foo busybox
/ # echo "hello from container" > /foo/hello.txt
/ # exit
$ cat hello.txt
hello from container

退出状态

退出代码docker run提供有关容器运行失败或退出原因的信息。以下部分描述了不同容器退出代码值的含义。

125

退出代码125表明错误出在 Docker 守护进程本身。

$ docker run --foo busybox; echo $?

flag provided but not defined: --foo
See 'docker run --help'.
125

126

退出代码126表示无法调用指定的包含命令。以下示例中的容器命令为:/etc; echo $?

$ docker run busybox /etc; echo $?

docker: Error response from daemon: Container command '/etc' could not be invoked.
126

127

退出代码127表示找不到包含的命令。

$ docker run busybox foo; echo $?

docker: Error response from daemon: Container command 'foo' not found or does not exist.
127

其他退出代码

125除、126、 和之外的任何退出代码127均表示所提供容器命令的退出代码。

$ docker run busybox /bin/sh -c 'exit 3'
$ echo $?
3

运行时资源限制

操作者还可以调整容器的性能参数:

选项描述
-m,--memory=""内存限制(格式:<number>[<unit>])。 Number 是一个正整数。单位可以是bkm或之一g。最小为 6M。
--memory-swap=""总内存限制(内存+交换区,格式:)<number>[<unit>]。 Number 是一个正整数。单位可以是bkm或之一g
--memory-reservation=""内存软限制(格式:<number>[<unit>])。 Number 是一个正整数。单位可以是bkm或之一g
--kernel-memory=""内核内存限制(格式:<number>[<unit>])。 Number 是一个正整数。单位可以是bkm或之一g。最小为 4M。
-c,--cpu-shares=0CPU 份额(相对权重)
--cpus=0.000CPU 数量。数字是小数。 0.000 表示没有限制。
--cpu-period=0限制CPU CFS(完全公平调度程序)周期
--cpuset-cpus=""允许执行的 CPU (0-3, 0,1)
--cpuset-mems=""允许执行的内存节点 (MEM) (0-3, 0,1)。仅对 NUMA 系统有效。
--cpu-quota=0限制CPU CFS(完全公平调度程序)配额
--cpu-rt-period=0限制CPU实时时间。以微秒为单位。需要设置父 cgroup,并且不能高于父 cgroup。另请检查 rtprio ulimits。
--cpu-rt-runtime=0限制CPU实时运行时间。以微秒为单位。需要设置父 cgroup,并且不能高于父 cgroup。另请检查 rtprio ulimits。
--blkio-weight=0块 IO 权重(相对权重)接受 10 到 1000 之间的权重值。
--blkio-weight-device=""块IO权重(相对设备权重,格式DEVICE_NAME:WEIGHT:)
--device-read-bps=""限制设备的读取速率(格式:<device-path>:<number>[<unit>])。 Number 是一个正整数。单位可以是kbmb、 或之一gb
--device-write-bps=""限制设备的写入速率(格式:<device-path>:<number>[<unit>])。 Number 是一个正整数。单位可以是kbmb、 或之一gb
--device-read-iops=""限制设备的读取速率(每秒 IO)(格式:)<device-path>:<number>。 Number 是一个正整数。
--device-write-iops=""限制设备的写入速率(每秒 IO)(格式:)<device-path>:<number>。 Number 是一个正整数。
--oom-kill-disable=false是否为容器禁用 OOM Killer。
--oom-score-adj=0调整容器的 OOM 首选项(-1000 到 1000)
--memory-swappiness=""调整容器的内存交换行为。接受 0 到 100 之间的整数。
--shm-size=""大小为/dev/shm.格式为<number><unit>.number必须大于0.单位是可选的,可以是b(字节)、k(千字节)、m(兆字节)或g(千兆字节)。如果省略单位,系统将使用字节。如果完全省略大小,系统将使用64m.

用户内存限制

我们有四种方法来设置用户内存使用情况:

选项结果
内存=inf,内存交换=inf(默认)容器没有内存限制。容器可以根据需要使用尽可能多的内存。
内存=L<inf,内存交换=inf(指定内存并将内存交换设置为-1)容器不允许使用超过 L 字节的内存,但可以根据需要使用尽可能多的交换(如果主机支持交换内存)。
内存=L<inf,内存交换=2*L(指定没有内存交换的内存)容器不允许使用超过L字节的内存,交换加上内存使用量是其两倍。
内存=L<inf,内存交换=S<inf,L<=S(同时指定内存和内存交换)容器不允许使用超过L字节的内存,交换内存使用量受S限制。

例子:

$ docker run -it ubuntu:22.04 /bin/bash

我们对内存没有设置任何内容,这意味着容器中的进程可以根据需要使用尽可能多的内存和交换内存。

$ docker run -it -m 300M --memory-swap -1 ubuntu:22.04 /bin/bash

我们设置了内存限制并禁用了交换内存限制,这意味着容器中的进程可以使用 300M 内存以及所需的交换内存(如果主机支持交换内存)。

$ docker run -it -m 300M ubuntu:22.04 /bin/bash

我们只设置内存限制,这意味着容器中的进程可以使用300M内存和300M交换内存,默认情况下,总虚拟内存大小(--memory-swap)将设置为内存的两倍,在这种情况下,内存+ 交换内存为 2*300M,因此进程也可以使用 300M 交换内存。

$ docker run -it -m 300M --memory-swap 1G ubuntu:22.04 /bin/bash

我们同时设置了内存和交换内存,因此容器中的进程可以使用300M内存和700M交换内存。

内存预留是一种内存软限制,允许更大程度地共享内存。正常情况下,容器可以根据需要使用尽可能多的内存,并且仅受 -m/--memory选项设置的硬限制的约束。设置内存预留后,Docker 会检测内存争用或内存不足,并强制容器将其消耗限制在预留限制内。

始终将内存预留值设置为低于硬限制,否则硬限制优先。保留为 0 与设置不保留相同。默认情况下(未设置预留),内存预留与硬内存限制相同。

内存预留是一项软限制功能,不保证不会超出限制。相反,该功能尝试确保当内存竞争激烈时,根据预留提示/设置来分配内存。

以下示例将内存 ( -m) 限制为 500M,并将内存预留设置为 200M。

$ docker run -it -m 500M --memory-reservation 200M ubuntu:22.04 /bin/bash

在此配置下,当容器消耗内存大于200M且小于500M时,下次系统内存回收会尝试将容器内存收缩到200M以下。

以下示例将内存预留设置为 1G,没有硬内存限制。

$ docker run -it --memory-reservation 1G ubuntu:22.04 /bin/bash

容器可以根据需要使用尽可能多的内存。内存预留设置确保容器不会长时间消耗太多内存,因为每次内存回收都会将容器的消耗缩减到预留。

默认情况下,如果发生内存不足 (OOM) 错误,内核会终止容器中的进程。要更改此行为,请使用该--oom-kill-disable选项。仅在您也设置了该选项的容器上禁用 OOM Killer -m/--memory。如果-m未设置该标志,则可能会导致主机内存不足,并需要终止主机的系统进程以释放内存。

以下示例将内存限制为 100M 并禁用该容器的 OOM Killer:

$ docker run -it -m 100M --oom-kill-disable ubuntu:22.04 /bin/bash

以下示例说明了使用该标志的危险方法:

$ docker run -it --oom-kill-disable ubuntu:22.04 /bin/bash

容器具有无限内存,这可能会导致主机耗尽内存并需要杀死系统进程以释放内存。可以更改该--oom-score-adj 参数来选择当系统内存不足时哪些容器将被杀死的优先级,负分数使它们更不可能被杀死,正分数则更有可能被杀死。

内核内存限制

内核内存与用户内存有根本的不同,因为内核内存无法换出。无法交换使得容器可能因消耗过多的内核内存而阻塞系统服务。内核内存包括:

  • 堆栈页
  • 平板页面
  • 套接字内存压力
  • TCP内存压力

您可以设置内核内存限制来限制这些类型的内存。例如,每个进程都会消耗一些堆栈页。通过限制内核内存,可以防止在内核内存使用率过高时创建新进程。

内核内存永远不会完全独立于用户内存。相反,您可以在用户内存限制的上下文中限制内核内存。假设“U”是用户内存限制,“K”是内核限制。设置限制的方法有以下三种:

选项结果
U != 0,K = inf(默认)这是在使用内核内存之前已经存在的标准内存限制机制。内核内存被完全忽略。
U != 0,K < U内核内存是用户内存的子集。此设置在每个 cgroup 内存总量过量使用的部署中非常有用。绝对不建议过度使用内核内存限制,因为盒子仍然可能耗尽不可回收的内存。在这种情况下,您可以配置 K,使所有组的总和永远不会大于总内存。然后,随意设置U,但会牺牲系统的服务质量。
U != 0,K > U由于内核内存费用也被馈送到用户计数器,并且两种内存的容器都会触发回收。此配置为管理员提供了统一的内存视图。对于只想跟踪内核内存使用情况的人来说它也很有用。

例子:

$ docker run -it -m 500M --kernel-memory 50M ubuntu:22.04 /bin/bash

我们设置了内存和内核内存,那么容器中的进程总共可以使用500M内存,在这500M内存中,可以是50M内核内存。

$ docker run -it --kernel-memory 50M ubuntu:22.04 /bin/bash

我们在不使用-m 的情况下设置内核内存,因此容器中的进程可以使用尽可能多的内存,但它们只能使用 50M 内核内存。

交换约束

默认情况下,容器的内核可以交换一定比例的匿名页面。要为容器设置此百分比,请指定--memory-swappiness0 到 100 之间的值。值 0 将关闭匿名页面交换。值 100 将所有匿名页面设置为可交换。默认情况下,如果您不使用 --memory-swappiness,内存交换值将从父级继承。

例如,您可以设置:

$ docker run -it --memory-swappiness=0 ubuntu:22.04 /bin/bash

--memory-swappiness当您想要保留容器的工作集并避免交换性能损失时,设置该选项非常有用。

CPU 共享限制

默认情况下,所有容器都获得相同比例的 CPU 周期。可以通过更改容器相对于所有其他正在运行的容器的权重的 CPU 份额权重来修改此比例。

要修改默认值 1024 的比例,请使用-c--cpu-shares 标志将权重设置为 2 或更高。如果设置为 0,系统将忽略该值并使用默认值 1024。

该比例仅在 CPU 密集型进程运行时适用。当一个容器中的任务空闲时,其他容器可以使用剩余的 CPU 时间。实际的 CPU 时间量将根据系统上运行的容器数量而有所不同。

例如,考虑三个容器,一个容器的 cpu-share 为 1024,另外两个容器的 cpu-share 设置为 512。当所有三个容器中的进程尝试使用 100% 的 CPU 时,第一个容器将获得 50% 的 CPU 份额。总 CPU 时间。如果添加 cpu-share 为 1024 的第四个容器,则第一个容器仅获得 33% 的 CPU。其余容器获得 16.5%、16.5% 和 33% 的 CPU。

在多核系统上,CPU 时间份额分布在所有 CPU 核心上。即使容器被限制为低于 100% 的 CPU 时间,它也可以 100% 使用每个单独的 CPU 核心。

例如,考虑一个具有三个以上核心的系统。如果启动一个容器{C0}运行-c=512一个进程,而另一个容器 {C1}运行-c=1024两个进程,则可能会导致以下 CPU 份额划分:

PID    container	CPU	CPU share
100    {C0}		0	100% of CPU0
101    {C1}		1	100% of CPU1
102    {C1}		2	100% of CPU2

CPU周期限制

默认的CPU CFS(完全公平调度程序)周期为100ms。我们可以 --cpu-period通过设置CPU的周期来限制容器的CPU使用率。通常--cpu-period应该与--cpu-quota.

例子:

$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:22.04 /bin/bash

如果有 1 个 CPU,这意味着容器每 50 毫秒可以获得 50% CPU 的运行时间。

除了使用--cpu-period--cpu-quota设置 CPU 周期约束之外,还可以指定--cpus浮点数来​​达到相同的目的。例如,如果有1个CPU,则将达到与设置和(50%CPU)--cpus=0.5相同的结果。--cpu-period=50000--cpu-quota=25000

默认值为,--cpus0.000意味着没有限制。

有关更多信息,请参阅 有关带​​宽限制的 CFS 文档

中央处理器限制

我们可以设置允许容器执行的CPU。

例子:

$ docker run -it --cpuset-cpus="1,3" ubuntu:22.04 /bin/bash

这意味着容器中的进程可以在 cpu 1 和 cpu 3 上执行。

$ docker run -it --cpuset-cpus="0-2" ubuntu:22.04 /bin/bash

这意味着容器中的进程可以在 cpu 0、cpu 1 和 cpu 2 上执行。

我们可以设置内存以允许容器执行。仅对 NUMA 系统有效。

例子:

$ docker run -it --cpuset-mems="1,3" ubuntu:22.04 /bin/bash

此示例限制容器中的进程仅使用内存节点 1 和 3 中的内存。

$ docker run -it --cpuset-mems="0-2" ubuntu:22.04 /bin/bash

此示例限制容器中的进程仅使用内存节点 0、1 和 2 中的内存。

CPU配额限制

--cpu-quota标志限制容器的 CPU 使用率。默认值 0 允许容器占用 100% 的 CPU 资源 (1 CPU)。 CFS(完全公平调度程序)处理执行进程的资源分配,是内核使用的默认 Linux 调度程序。将此值设置为 50000 可将容器限制为 CPU 资源的 50%。对于多个 CPU,请--cpu-quota根据需要进行调整。有关更多信息,请参阅 有关带​​宽限制的 CFS 文档

块 IO 带宽 (Blkio) 约束

默认情况下,所有容器获得相同比例的块 IO 带宽 (blkio)。此比例为 500。要修改此比例,请使用该标志更改容器的 blkio 权重相对于所有其他正在运行的容器的权重--blkio-weight

笔记:

blkio权重设置仅适用于直接IO。目前不支持缓冲 IO。

--blkio-weight标志可以将权重设置为 10 到 1000 之间的值。例如,以下命令创建两个具有不同 blkio 权重的容器:

$ docker run -it --name c1 --blkio-weight 300 ubuntu:22.04 /bin/bash
$ docker run -it --name c2 --blkio-weight 600 ubuntu:22.04 /bin/bash

如果您同时在两个容器中阻塞 IO,例如:

$ time dd if=/mnt/zerofile of=test.out bs=1M count=1024 oflag=direct

你会发现时间的比例和两个容器的blkio权重的比例是一样的。

--blkio-weight-device="DEVICE_NAME:WEIGHT"标志设置特定的设备权重。是DEVICE_NAME:WEIGHT一个字符串,包含以冒号分隔的设备名称和权重。例如,将/dev/sda设备权重设置为200

$ docker run -it \
    --blkio-weight-device "/dev/sda:200" \
    ubuntu

如果您同时指定--blkio-weight--blkio-weight-device,Docker 会使用 和--blkio-weight作为默认权重,并使用--blkio-weight-device 特定设备上的新值覆盖此默认值。以下示例使用默认权重300并在/dev/sda将该权重设置为时覆盖此默认值200

$ docker run -it \
    --blkio-weight 300 \
    --blkio-weight-device "/dev/sda:200" \
    ubuntu

--device-read-bps标志限制设备的读取速率(每秒字节数)。例如,此命令创建一个容器并将读取速率限制为1mb 每秒/dev/sda

$ docker run -it --device-read-bps /dev/sda:1mb ubuntu

--device-write-bps标志限制设备的写入速率(每秒字节数)。例如,此命令创建一个容器并将写入速率限制为1mb 每秒/dev/sda

$ docker run -it --device-write-bps /dev/sda:1mb ubuntu

这两个标志都对<device-path>:<limit>[unit]格式有限制。读取和写入速率都必须是正整数。您可以以kb (千字节)、mb(兆字节)或gb(千兆字节)为单位指定速率。

--device-read-iops标志限制设备的读取速率(每秒 IO)。例如,此命令创建一个容器并将读取速率限制为 1000每秒 IO /dev/sda

$ docker run -it --device-read-iops /dev/sda:1000 ubuntu

--device-write-iops标志限制设备的写入速率(每秒 IO)。例如,此命令创建一个容器并将 1000每秒 IO 的写入速率限制为/dev/sda

$ docker run -it --device-write-iops /dev/sda:1000 ubuntu

这两个标志都对<device-path>:<limit>格式有限制。读取和写入速率都必须是正整数。

附加组

--group-add: Add additional groups to run as

默认情况下,docker 容器进程会使用为指定用户查找的补充组来运行。如果想向该组列表添加更多内容,则可以使用此标志:

$ docker run --rm --group-add audio --group-add nogroup --group-add 777 busybox id

uid=0(root) gid=0(root) groups=10(wheel),29(audio),99(nogroup),777

运行时权限和 Linux 功能

选项描述
--cap-add添加 Linux 功能
--cap-drop放弃 Linux 功能
--privileged授予此容器扩展权限
--device=[]允许您在没有标志的情况下在容器内运行设备--privileged

默认情况下,Docker 容器是“无特权的”,例如不能在 Docker 容器内运行 Docker 守护进程。这是因为默认情况下不允许容器访问任何设备,但“特权”容器可以访问所有设备(请参阅有关 cgroups devices的文档)。

--privileged标志为容器提供了所有功能。当操作员执行 时docker run --privileged,Docker 启用对主机上所有设备的访问,并重新配置 AppArmor 或 SELinux,以允许容器与主机上容器外部运行的进程几乎对主机进行相同的访问。请谨慎使用该标志。有关该--privileged标志的更多信息,请参阅 docker run参考资料

如果您想限制对特定设备的访问,可以使用该--device标志。它允许您指定可在容器内访问的一个或多个设备。

$ docker run --device=/dev/snd:/dev/snd ...

默认情况下,容器将能够readwrite、 和mknod这些设备。这可以使用每个标志:rwm的第三组选项来覆盖:--device

$ docker run --device=/dev/sda:/dev/xvdc --rm -it ubuntu fdisk  /dev/xvdc

Command (m for help): q
$ docker run --device=/dev/sda:/dev/xvdc:r --rm -it ubuntu fdisk  /dev/xvdc
You will not be able to write the partition table.

Command (m for help): q

$ docker run --device=/dev/sda:/dev/xvdc:w --rm -it ubuntu fdisk  /dev/xvdc
    crash....

$ docker run --device=/dev/sda:/dev/xvdc:m --rm -it ubuntu fdisk  /dev/xvdc
fdisk: unable to open /dev/xvdc: Operation not permitted

此外,操作员还可以使用和--privileged来对功能进行细粒度控制。默认情况下,Docker 有一个保留的默认功能列表。下表列出了默认允许且可以删除的 Linux 功能选项。--cap-add--cap-drop

能力关键能力描述
审计_写入将记录写入内核审核日志。
对文件 UID 和 GID 进行任意更改(请参阅 chown(2))。
DAC_OVERRIDE绕过文件读、写和执行权限检查。
福纳绕过对通常需要进程的文件系统 UID 与文件的 UID 相匹配的操作的权限检查。
FSETID修改文件时不要清除 set-user-ID 和 set-group-ID 权限位。
绕过发送信号的权限检查。
麦克诺德使用 mknod(2) 创建特殊文件。
NET_BIND_SERVICE将套接字绑定到 Internet 域特权端口(端口号小于 1024)。
NET_RAW使用 RAW 和 PACKET 套接字。
SETFCAP设置文件功能。
设置GID对进程 GID 和补充 GID 列表进行任意操作。
塞特普CAP修改流程能力。
设置用户ID对进程 UID 进行任意操作。
系统根目录使用 chroot(2),更改根目录。

下表显示了默认情况下未授予但可以添加的功能。

能力关键能力描述
审计控制启用和禁用内核审计;更改审核过滤规则;检索审核状态和过滤规则。
审计_读取允许通过多播 netlink 套接字读取审核日志。
BLOCK_SUSPEND允许防止系统挂起。
带通滤波器允许创建 BPF 映射、加载 BPF 类型格式 (BTF) 数据、检索 BPF 程序的 JIT 代码等等。
检查点_恢复允许检查点/恢复相关操作。在内核 5.9 中引入。
DAC_READ_SEARCH绕过文件读取权限检查以及目录读取和执行权限检查。
IPC_LOCK锁定内存(mlock(2)、mlockall(2)、mmap(2)、shmctl(2))。
IPC_OWNER绕过对 System V IPC 对象的操作的权限检查。
对任意文件建立租约(请参阅 fcntl(2))。
LINUX_IMMUTABLE设置 FS_APPEND_FL 和 FS_IMMUTABLE_FL i 节点标志。
MAC_管理员允许 MAC 配置或状态更改。为 Smack LSM 实施。
MAC_OVERRIDE覆盖强制访问控制 (MAC)。为 Smack Linux 安全模块 (LSM) 实施。
网络管理员执行各种与网络相关的操作。
网络广播进行套接字广播并侦听多播。
性能监视器允许使用 perf_events、i915_perf 和其他内核子系统进行系统性能和可观察性特权操作
系统管理员执行一系列系统管理操作。
系统引导使用reboot(2)和kexec_load(2),重新启动并加载新内核以供以后执行。
系统模块加载和卸载内核模块。
系统_NICE提高进程的nice值(nice(2)、setpriority(2))并更改任意进程的nice值。
系统_PACCT使用 acct(2),打开或关闭进程记帐。
系统_PTRACE使用 ptrace(2) 跟踪任意进程。
系统_RAWIO执行 I/O 端口操作(iopl(2) 和 ioperm(2))。
系统资源覆盖资源限制。
系统时间设置系统时钟(settimeofday(2), stime(2), adjtimex(2));设置实时(硬件)时钟。
SYS_TTY_配置使用 vhangup(2);在虚拟终端上使用各种特权 ioctl(2) 操作。
系统日志执行特权 syslog(2) 操作。
唤醒警报触发一些东西来唤醒系统。

更多参考信息可在 功能(7)-Linux 手册页Linux 内核源代码中找到。

两个标志都支持该值ALL,因此允许容器使用除以下之外的所有功能MKNOD

$ docker run --cap-add=ALL --cap-drop=MKNOD ...

--cap-add和标志--cap-drop接受使用前缀指定的功能CAP_。因此,以下示例是等效的:

$ docker run --cap-add=SYS_ADMIN ...
$ docker run --cap-add=CAP_SYS_ADMIN ...

为了与网络堆栈交互,不应使用--privileged它们,而应使用它们--cap-add=NET_ADMIN来修改网络接口。

$ docker run -it --rm  ubuntu:22.04 ip link add dummy0 type dummy

RTNETLINK answers: Operation not permitted

$ docker run -it --rm --cap-add=NET_ADMIN ubuntu:22.04 ip link add dummy0 type dummy

要挂载基于 FUSE 的文件系统,您需要结合使用--cap-add--device

$ docker run --rm -it --cap-add SYS_ADMIN sshfs sshfs sven@10.10.10.20:/home/sven /mnt

fuse: failed to open /dev/fuse: Operation not permitted

$ docker run --rm -it --device /dev/fuse sshfs sshfs sven@10.10.10.20:/home/sven /mnt

fusermount: mount failed: Operation not permitted

$ docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs

# sshfs sven@10.10.10.20:/home/sven /mnt
The authenticity of host '10.10.10.20 (10.10.10.20)' can't be established.
ECDSA key fingerprint is 25:34:85:75:25:b0:17:46:05:19:04:93:b5:dd:5f:c6.
Are you sure you want to continue connecting (yes/no)? yes
sven@10.10.10.20's password:

root@30aa0cfaf1b5:/# ls -la /mnt/src/docker

total 1516
drwxrwxr-x 1 1000 1000   4096 Dec  4 06:08 .
drwxrwxr-x 1 1000 1000   4096 Dec  4 11:46 ..
-rw-rw-r-- 1 1000 1000     16 Oct  8 00:09 .dockerignore
-rwxrwxr-x 1 1000 1000    464 Oct  8 00:09 .drone.yml
drwxrwxr-x 1 1000 1000   4096 Dec  4 06:11 .git
-rw-rw-r-- 1 1000 1000    461 Dec  4 06:08 .gitignore
....

默认的 seccomp 配置文件将根据选定的功能进行调整,以允许使用功能允许的设施,因此您不必对此进行调整。

覆盖图像默认值

当您从Dockerfile构建映像 或提交映像时,您可以设置许多默认参数,这些参数在映像作为容器启动时生效。运行映像时,您可以使用命令标志覆盖这些默认值docker run

默认命令和选项

命令语法docker run支持选择性地指定容器入口点的命令和参数,在以下概要示例中表示为[COMMAND]和 :[ARG...]

$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

该命令是可选的,因为创建该命令的人IMAGE可能已经COMMAND使用 DockerfileCMD指令提供了默认值。当您运行容器时,您只需CMD指定一个新的COMMAND.

如果图像还指定了 则将ENTRYPOINTCMD作为COMMAND 参数附加到ENTRYPOINT

默认入口点

--entrypoint="": Overwrite the default entrypoint set by the image

入口点是指运行容器时调用的默认可执行文件。容器的入口点是使用 Dockerfile ENTRYPOINT指令定义的。它类似于指定默认命令,因为它指定了,但不同之处在于您需要传递显式标志来覆盖入口点,而您可以使用位置参数覆盖默认命令。定义了容器的默认行为,其思想是,当您设置入口点时,您可以像二进制文件一样运行容器,并使用默认选项,并且可以将更多选项作为命令传递。但在某些情况下,您可能想在容器内运行其他东西。这时,使用命令--entrypoint的标志来覆盖运行时的默认入口点就派上用场了docker run

--entrypoint标志需要一个字符串值,表示容器启动时要调用的二进制文件的名称或路径。以下示例向您展示如何在已设置为自动运行某些其他二进制文件(例如/usr/bin/redis-server)的容器中运行 Bash shell:

$ docker run -it --entrypoint /bin/bash example/redis

以下示例演示如何使用位置命令参数将其他参数传递到自定义入口点:

$ docker run -it --entrypoint /bin/bash example/redis -c ls -l
$ docker run -it --entrypoint /usr/bin/redis-cli example/redis --help

您可以通过传递空字符串来重置容器入口点,例如:

$ docker run -it --entrypoint="" mysql bash

笔记

传递--entrypoint将清除图像上设置的所有默认命令。也就是说,CMDDockerfile 中用于构建它的任何指令。

暴露端口

默认情况下,当您运行容器时,容器的任何端口都不会暴露给主机。这意味着您将无法访问容器可能正在侦听的任何端口。要使容器的端口可从主机访问,您需要发布端口。

-P您可以使用或标志启动容器-p以公开其端口:

  • -P(或)标志--publish-all将所有公开的端口发布到主机。 Docker 将每个公开的端口绑定到主机上的随机端口。

    -P标志仅发布使用 DockerfileEXPOSE指令或--expose 命令标志明确标记为公开的端口号docker run

  • -p(或)标志--publish允许您将容器中的单个端口或端口范围显式映射到主机。

容器内的端口号(服务侦听的位置)不需要与容器外部(客户端连接的位置)发布的端口号匹配。例如,在容器内部,HTTP 服务可能正在侦听端口 80。在运行时,该端口可能绑定到主机上的 42800。要查找主机端口和公开端口之间的映射,请使用以下 docker port命令。

环境变量

Docker 在创建 Linux 容器时会自动设置一些环境变量。 Docker 在创建 Windows 容器时不会设置任何环境变量。

为Linux容器设置以下环境变量:

多变的价值
HOME根据 的值设置USER
HOSTNAME与容器关联的主机名
PATH包括流行的目录,例如/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
TERMxterm如果容器分配了伪 TTY

-e此外,您可以使用一个或多个标志在容器中设置任何环境变量。您甚至可以覆盖上面提到的变量,或者ENV在构建镜像时使用 Dockerfile 指令定义的变量。

如果您命名环境变量而不指定值,则主机上命名变量的当前值将传播到容器的环境中:

$ export today=Wednesday
$ docker run -e "deep=purple" -e today --rm alpine env

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=d2219b854598
deep=purple
today=Wednesday
HOME=/root
PS C:\> docker run --rm -e "foo=bar" microsoft/nanoserver cmd /s /c set
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\ContainerAdministrator\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
COMPUTERNAME=C2FAEFCC8253
ComSpec=C:\Windows\system32\cmd.exe
foo=bar
LOCALAPPDATA=C:\Users\ContainerAdministrator\AppData\Local
NUMBER_OF_PROCESSORS=8
OS=Windows_NT
Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Users\ContainerAdministrator\AppData\Local\Microsoft\WindowsApps
PATHEXT=.COM;.EXE;.BAT;.CMD
PROCESSOR_ARCHITECTURE=AMD64
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 62 Stepping 4, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=3e04
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
ProgramFiles(x86)=C:\Program Files (x86)
ProgramW6432=C:\Program Files
PROMPT=$P$G
PUBLIC=C:\Users\Public
SystemDrive=C:
SystemRoot=C:\Windows
TEMP=C:\Users\ContainerAdministrator\AppData\Local\Temp
TMP=C:\Users\ContainerAdministrator\AppData\Local\Temp
USERDOMAIN=User Manager
USERNAME=ContainerAdministrator
USERPROFILE=C:\Users\ContainerAdministrator
windir=C:\Windows

健康检查

该命令的以下标志docker run可让您控制容器运行状况检查的参数:

选项描述
--health-cmd运行命令来检查运行状况
--health-interval运行检查之间的时间
--health-retries需要连续失败才能报告不健康
--health-timeout允许运行一项检查的最长时间
--health-start-period在开始运行状况重试倒计时之前容器初始化的开始时间
--health-start-interval开始期间运行检查之间的时间间隔
--no-healthcheck禁用任何容器指定的HEALTHCHECK

例子:

$ docker run --name=test -d \
    --health-cmd='stat /etc/passwd || exit 1' \
    --health-interval=2s \
    busybox sleep 1d
$ sleep 2; docker inspect --format='{{.State.Health.Status}}' test
healthy
$ docker exec test rm /etc/passwd
$ sleep 2; docker inspect --format='{{json .State.Health}}' test
{
  "Status": "unhealthy",
  "FailingStreak": 3,
  "Log": [
    {
      "Start": "2016-05-25T17:22:04.635478668Z",
      "End": "2016-05-25T17:22:04.7272552Z",
      "ExitCode": 0,
      "Output": "  File: /etc/passwd\n  Size: 334       \tBlocks: 8          IO Block: 4096   regular file\nDevice: 32h/50d\tInode: 12          Links: 1\nAccess: (0664/-rw-rw-r--)  Uid: (    0/    root)   Gid: (    0/    root)\nAccess: 2015-12-05 22:05:32.000000000\nModify: 2015..."
    },
    {
      "Start": "2016-05-25T17:22:06.732900633Z",
      "End": "2016-05-25T17:22:06.822168935Z",
      "ExitCode": 0,
      "Output": "  File: /etc/passwd\n  Size: 334       \tBlocks: 8          IO Block: 4096   regular file\nDevice: 32h/50d\tInode: 12          Links: 1\nAccess: (0664/-rw-rw-r--)  Uid: (    0/    root)   Gid: (    0/    root)\nAccess: 2015-12-05 22:05:32.000000000\nModify: 2015..."
    },
    {
      "Start": "2016-05-25T17:22:08.823956535Z",
      "End": "2016-05-25T17:22:08.897359124Z",
      "ExitCode": 1,
      "Output": "stat: can't stat '/etc/passwd': No such file or directory\n"
    },
    {
      "Start": "2016-05-25T17:22:10.898802931Z",
      "End": "2016-05-25T17:22:10.969631866Z",
      "ExitCode": 1,
      "Output": "stat: can't stat '/etc/passwd': No such file or directory\n"
    },
    {
      "Start": "2016-05-25T17:22:12.971033523Z",
      "End": "2016-05-25T17:22:13.082015516Z",
      "ExitCode": 1,
      "Output": "stat: can't stat '/etc/passwd': No such file or directory\n"
    }
  ]
}

健康状态也显示在docker ps输出中。

用户

容器内的默认用户是root(uid = 0)。您可以使用 Dockerfile 指令设置默认用户来运行第一个进程USER。启动容器时,您可以USER通过传递 -u选项来覆盖指令。

-u="", --user="": Sets the username or UID used and optionally the groupname or GID for the specified command.

以下示例均有效:

--user=[ user | user:group | uid | uid:gid | user:gid | uid:group ]

笔记

如果传递数字用户 ID,则它必须在 0-2147483647 范围内。如果传递用户名,则该用户必须存在于容器中。

工作目录

在容器内运行二进制文件的默认工作目录是根目录 ( /)。镜像的默认工作目录是使用 DockerfileWORKDIR命令设置的。您可以使用命令的-w(或--workdir) 标志覆盖图像的默认工作目录docker run

$ docker run --rm -w /my/workdir alpine pwd
/my/workdir

如果容器中尚不存在该目录,则会创建该目录。