运行容器

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

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

通用形式

一个 docker run 命令采用以下形式:

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

docker run 命令必须指定一个 image reference 来创建容器。

图片引用

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

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

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

图像摘要

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

以下示例从alpine镜像运行一个容器,使用sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0摘要:

$ docker run alpine@sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0 date

选项

[OPTIONS] 允许你配置容器的选项。例如,你可以为容器指定一个名称(--name),或者以后台进程运行它(-d)。你还可以设置选项来控制资源限制和网络等。

命令和参数

你可以使用[COMMAND][ARG...]位置参数来指定容器启动时运行的命令和参数。例如,你可以指定sh作为[COMMAND],结合-i-t标志,在容器中启动一个交互式shell(如果你选择的镜像在PATH上有sh可执行文件)。

$ docker run -it IMAGE sh

注意

根据您的Docker系统配置,您可能需要在docker run命令前加上sudo。为了避免在使用docker命令时需要使用sudo,您的系统管理员可以创建一个名为docker的Unix组并将用户添加到其中。有关此配置的更多信息,请参阅适用于您操作系统的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.

容器识别

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

Identifier typeExample value
UUID long identifierf78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778
UUID short identifierf78375b1c487
Nameevil_ptolemy

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

守护进程会自动为容器生成一个随机的字符串名称。你也可以使用 the --name flag. 定义一个name可以方便地为容器添加意义。如果你 指定了一个name,你可以在用户定义的网络中引用容器时使用它。 这适用于后台和前台Docker容器。

容器标识符与镜像引用不是一回事。镜像引用指定了在运行容器时使用哪个镜像。你不能运行docker exec nginx:alpine sh来在基于nginx:alpine镜像的容器中打开一个shell,因为docker exec期望的是一个容器标识符(名称或ID),而不是一个镜像。

虽然容器使用的镜像不是容器的标识符,但你可以通过使用--filter标志来查找使用该镜像的容器的ID。例如,以下docker ps命令获取所有基于nginx:alpine镜像运行的容器的ID:

$ 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 支持两种主要的挂载类型:

  • 卷挂载
  • 绑定挂载

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

你可以使用docker run命令的--mount标志向容器添加文件系统挂载。

以下部分展示了如何创建卷和绑定挂载的基本示例。有关更深入的示例和描述,请参阅文档中的存储部分

卷挂载

要创建卷挂载:

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

在这种情况下,--mount 标志接受两个参数:sourcetargetsource 参数的值是卷的名称。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

$ 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

其他退出代码

除了125126127之外的任何退出代码都代表提供的容器命令的退出代码。

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

运行时资源限制

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

OptionDescription
-m, --memory=""Memory limit (format: <number>[<unit>]). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 6M.
--memory-swap=""Total memory limit (memory + swap, format: <number>[<unit>]). Number is a positive integer. Unit can be one of b, k, m, or g.
--memory-reservation=""Memory soft limit (format: <number>[<unit>]). Number is a positive integer. Unit can be one of b, k, m, or g.
--kernel-memory=""Kernel memory limit (format: <number>[<unit>]). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 4M.
-c, --cpu-shares=0CPU shares (relative weight)
--cpus=0.000Number of CPUs. Number is a fractional number. 0.000 means no limit.
--cpu-period=0Limit the CPU CFS (Completely Fair Scheduler) period
--cpuset-cpus=""CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems=""Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
--cpu-quota=0Limit the CPU CFS (Completely Fair Scheduler) quota
--cpu-rt-period=0Limit the CPU real-time period. In microseconds. Requires parent cgroups be set and cannot be higher than parent. Also check rtprio ulimits.
--cpu-rt-runtime=0Limit the CPU real-time runtime. In microseconds. Requires parent cgroups be set and cannot be higher than parent. Also check rtprio ulimits.
--blkio-weight=0Block IO weight (relative weight) accepts a weight value between 10 and 1000.
--blkio-weight-device=""Block IO weight (relative device weight, format: DEVICE_NAME:WEIGHT)
--device-read-bps=""Limit read rate from a device (format: <device-path>:<number>[<unit>]). Number is a positive integer. Unit can be one of kb, mb, or gb.
--device-write-bps=""Limit write rate to a device (format: <device-path>:<number>[<unit>]). Number is a positive integer. Unit can be one of kb, mb, or gb.
--device-read-iops=""Limit read rate (IO per second) from a device (format: <device-path>:<number>). Number is a positive integer.
--device-write-iops=""Limit write rate (IO per second) to a device (format: <device-path>:<number>). Number is a positive integer.
--oom-kill-disable=falseWhether to disable OOM Killer for the container or not.
--oom-score-adj=0Tune container's OOM preferences (-1000 to 1000)
--memory-swappiness=""Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
--shm-size=""Size of /dev/shm. The format is <number><unit>. number must be greater than 0. Unit is optional and can be b (bytes), k (kilobytes), m (megabytes), or g (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses 64m.

用户内存限制

我们有四种设置用户内存使用的方法:

OptionResult
memory=inf, memory-swap=inf (default)There is no memory limit for the container. The container can use as much memory as needed.
memory=L<inf, memory-swap=inf(specify memory and set memory-swap as -1) The container is not allowed to use more than L bytes of memory, but can use as much swap as is needed (if the host supports swap memory).
memory=L<inf, memory-swap=2*L(specify memory without memory-swap) The container is not allowed to use more than L bytes of memory, swap plus memory usage is double of that.
memory=L<inf, memory-swap=S<inf, L<=S(specify both memory and memory-swap) The container is not allowed to use more than L bytes of memory, swap plus memory usage is limited by S.

示例:

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

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

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

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

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

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

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

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

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

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

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

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

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

在此配置下,当容器消耗的内存超过200M且少于500M时,系统下一次内存回收将尝试将容器内存缩减至200M以下。

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

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

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

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

以下示例将内存限制为100M,并为此容器禁用OOM killer:

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

以下示例展示了使用标志的危险方式:

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

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

内核内存限制

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

  • 堆叠页面
  • slab 页面
  • 套接字内存压力
  • TCP 内存压力

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

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

OptionResult
U != 0, K = inf (default)This is the standard memory limitation mechanism already present before using kernel memory. Kernel memory is completely ignored.
U != 0, K < UKernel memory is a subset of the user memory. This setup is useful in deployments where the total amount of memory per-cgroup is overcommitted. Overcommitting kernel memory limits is definitely not recommended, since the box can still run out of non-reclaimable memory. In this case, you can configure K so that the sum of all groups is never greater than the total memory. Then, freely set U at the expense of the system's service quality.
U != 0, K > USince kernel memory charges are also fed to the user counter and reclamation is triggered for the container for both kinds of memory. This configuration gives the admin a unified view of memory. It is also useful for people who just want to track kernel memory usage.

示例:

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

我们设置了内存和内核内存,因此容器中的进程总共可以使用500M内存,在这500M内存中,最多可以有50M的内核内存。

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

我们没有设置-m的内核内存,因此容器中的进程可以使用任意数量的内存,但它们只能使用50M的内核内存。

Swappiness 约束

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

例如,您可以设置:

$ docker run -it --memory-swappiness=0 ubuntu:24.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时,第一个容器将获得总CPU时间的50%。如果你添加第四个cpu-share为1024的容器,第一个容器只能获得33%的CPU。剩下的容器分别获得16.5%、16.5%和33%的CPU。

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

例如,考虑一个拥有超过三个核心的系统。如果你启动一个容器 {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(完全公平调度器)周期为100毫秒。我们可以使用 --cpu-period 来设置CPU的周期以限制容器的CPU使用。 通常 --cpu-period 应该与 --cpu-quota 一起使用。

示例:

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

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

除了使用--cpu-period--cpu-quota来设置CPU周期限制外,还可以使用浮点数指定--cpus来实现相同的目的。例如,如果有1个CPU,那么--cpus=0.5将实现与设置--cpu-period=50000--cpu-quota=25000(50% CPU)相同的结果。

--cpus 的默认值为 0.000,这意味着没有限制。

欲了解更多信息,请参阅 CFS带宽限制文档

Cpuset 约束

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

示例:

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

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

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

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

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

示例:

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

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

$ docker run -it --cpuset-mems="0-2" ubuntu:24.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-weight标志来更改容器的blkio权重相对于所有其他运行容器的权重。

注意

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

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

$ docker run -it --name c1 --blkio-weight 300 ubuntu:24.04 /bin/bash
$ docker run -it --name c2 --blkio-weight 600 ubuntu:24.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 标志限制了从设备读取的速率(每秒字节数)。 例如,这个命令创建了一个容器,并将从 /dev/sda 读取的速率限制为每秒 1mb

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

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

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

两个标志都采用:[unit]格式的限制。读取和写入速率必须为正整数。您可以以kb(千字节)、mb(兆字节)或gb(千兆字节)为单位指定速率。

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

$ 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

两个标志都采用:格式的限制。读取和写入速率必须为正整数。

附加组

--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能力

OptionDescription
--cap-addAdd Linux capabilities
--cap-dropDrop Linux capabilities
--privilegedGive extended privileges to this container
--device=[]Allows you to run devices inside the container without the --privileged flag.

默认情况下,Docker容器是“非特权”的,因此无法在Docker容器内运行Docker守护进程。这是因为默认情况下,容器不允许访问任何设备,但“特权”容器被授予访问所有设备的权限(请参阅cgroups设备的文档)。

--privileged 标志赋予容器所有能力。当操作员执行 docker run --privileged 时,Docker 允许访问主机上的所有设备,并重新配置 AppArmor 或 SELinux,以使容器几乎拥有与主机上容器外运行的进程相同的访问权限。请谨慎使用此标志。 有关 --privileged 标志的更多信息,请参阅 docker run 参考

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

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

默认情况下,容器将能够readwritemknod这些设备。 可以通过为每个--device标志使用第三个:rwm选项集来覆盖此行为:

$ 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,操作员可以使用--cap-add--cap-drop对能力进行细粒度控制。默认情况下,Docker有一个默认保留的能力列表。下表列出了默认允许并且可以删除的Linux能力选项。

Capability KeyCapability Description
AUDIT_WRITEWrite records to kernel auditing log.
CHOWNMake arbitrary changes to file UIDs and GIDs (see chown(2)).
DAC_OVERRIDEBypass file read, write, and execute permission checks.
FOWNERBypass permission checks on operations that normally require the file system UID of the process to match the UID of the file.
FSETIDDon't clear set-user-ID and set-group-ID permission bits when a file is modified.
KILLBypass permission checks for sending signals.
MKNODCreate special files using mknod(2).
NET_BIND_SERVICEBind a socket to internet domain privileged ports (port numbers less than 1024).
NET_RAWUse RAW and PACKET sockets.
SETFCAPSet file capabilities.
SETGIDMake arbitrary manipulations of process GIDs and supplementary GID list.
SETPCAPModify process capabilities.
SETUIDMake arbitrary manipulations of process UIDs.
SYS_CHROOTUse chroot(2), change root directory.

下表显示了默认未授予且可能添加的功能。

Capability KeyCapability Description
AUDIT_CONTROLEnable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules.
AUDIT_READAllow reading the audit log via multicast netlink socket.
BLOCK_SUSPENDAllow preventing system suspends.
BPFAllow creating BPF maps, loading BPF Type Format (BTF) data, retrieve JITed code of BPF programs, and more.
CHECKPOINT_RESTOREAllow checkpoint/restore related operations. Introduced in kernel 5.9.
DAC_READ_SEARCHBypass file read permission checks and directory read and execute permission checks.
IPC_LOCKLock memory (mlock(2), mlockall(2), mmap(2), shmctl(2)).
IPC_OWNERBypass permission checks for operations on System V IPC objects.
LEASEEstablish leases on arbitrary files (see fcntl(2)).
LINUX_IMMUTABLESet the FS_APPEND_FL and FS_IMMUTABLE_FL i-node flags.
MAC_ADMINAllow MAC configuration or state changes. Implemented for the Smack LSM.
MAC_OVERRIDEOverride Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM).
NET_ADMINPerform various network-related operations.
NET_BROADCASTMake socket broadcasts, and listen to multicasts.
PERFMONAllow system performance and observability privileged operations using perf_events, i915_perf and other kernel subsystems
SYS_ADMINPerform a range of system administration operations.
SYS_BOOTUse reboot(2) and kexec_load(2), reboot and load a new kernel for later execution.
SYS_MODULELoad and unload kernel modules.
SYS_NICERaise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes.
SYS_PACCTUse acct(2), switch process accounting on or off.
SYS_PTRACETrace arbitrary processes using ptrace(2).
SYS_RAWIOPerform I/O port operations (iopl(2) and ioperm(2)).
SYS_RESOURCEOverride resource Limits.
SYS_TIMESet system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock.
SYS_TTY_CONFIGUse vhangup(2); employ various privileged ioctl(2) operations on virtual terminals.
SYSLOGPerform privileged syslog(2) operations.
WAKE_ALARMTrigger something that will wake up the system.

进一步的参考信息可以在 capabilities(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 ...

为了与网络栈进行交互,应该使用--cap-add=NET_ADMIN来修改网络接口,而不是使用--privileged

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

RTNETLINK answers: Operation not permitted

$ docker run -it --rm --cap-add=NET_ADMIN ubuntu:24.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的人可能已经使用Dockerfile的CMD指令提供了默认的COMMAND。当你运行一个容器时,你可以通过指定一个新的COMMAND来覆盖那个CMD指令。

如果镜像还指定了一个ENTRYPOINT,那么CMDCOMMAND将作为参数附加到ENTRYPOINT上。

默认入口点

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

入口点指的是当你运行一个容器时默认调用的可执行文件。容器的入口点是使用Dockerfile中的ENTRYPOINT指令定义的。它类似于指定一个默认命令,因为它指定了,但区别在于你需要传递一个显式标志来覆盖入口点,而你可以用位置参数覆盖默认命令。入口点定义了容器的默认行为,其理念是当你设置一个入口点时,你可以运行容器就像它是那个二进制文件一样,带有默认选项,并且你可以传递更多选项作为命令。但有些情况下,你可能想在容器内运行其他东西。这时,在运行时使用docker run命令的--entrypoint标志来覆盖默认入口点就非常有用。

--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 会清除镜像上设置的任何默认命令。也就是说,用于构建它的 Dockerfile 中的任何 CMD 指令都会被清除。

暴露的端口

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

您可以使用-P-p标志启动容器以暴露其端口:

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

    -P 标志仅发布明确标记为暴露的端口号,无论是使用 Dockerfile 的 EXPOSE 指令还是 docker run 命令的 --expose 标志。

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

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

环境变量

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

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

VariableValue
HOMESet based on the value of USER
HOSTNAMEThe hostname associated with the container
PATHIncludes popular directories, such as /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
TERMxterm if the container is allocated a pseudo-TTY

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

如果你命名了一个环境变量但没有指定值,主机上该命名变量的当前值将被传播到容器的环境中:

$ 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 命令,允许您控制容器健康检查的参数:

OptionDescription
--health-cmdCommand to run to check health
--health-intervalTime between running the check
--health-retriesConsecutive failures needed to report unhealthy
--health-timeoutMaximum time to allow one check to run
--health-start-periodStart period for the container to initialize before starting health-retries countdown
--health-start-intervalTime between running the check during the start period
--no-healthcheckDisable any container-specified 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指令设置一个默认用户来运行第一个进程。在启动容器时,你可以通过传递-u选项来覆盖USER指令。

-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的范围内。如果您传递一个用户名,该用户必须存在于容器中。

工作目录

容器内运行二进制文件的默认工作目录是根目录(/)。镜像的默认工作目录是通过Dockerfile中的WORKDIR命令设置的。你可以使用docker run命令的-w(或--workdir)标志来覆盖镜像的默认工作目录:

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

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