Docker run参考(10) – 资源使用限制

下面是可用于限制容器资源使用的选项:

限制指定设备读取速率(每秒IO操作数)[格式::]。number为正整数。

选项 描述
-m, –memory=”” 内存限制[格式:[]]。number是正整数。unit可以是b,k,m或g。最小4M。
–memory-swap=”” 总内存限制[memory+swap,格式:[]]。number是正整数。unit可以是b,k,m或g。
–memory-reservation=”” 内存软限制[格式:[]]。number是正整数。unit可以是b,k,m或g。
–kernel-memory=”” 内核内存限制[格式:[]]。number是正整数。unit可以是b,k,m或g。
-c, –cpu-shares=0 CPU share(相对权重)
–cpu-period=0 限制CPU CFS(完全公平调度程序)周期
–cpuset-cpus=”” 允许执行的CPU(0-3,0,1)
–cpuset-mems=”” 允许执行的内存节点(MEMs)(0-3,0,1)。 仅在NUMA系统上有效。
–cpu-quota=0 限制CPU CFS(完全公平调度程序)配额
–blkio-weight=0 块IO权重(相对权重)接受10和1000之间的权重值。
–blkio-weight-device=”” 块IO权重(相对设备权重,格式:DEVICE_NAME:WEIGHT)
–device-read-bps=”” 限制指定设备的读取速率[格式::[]]。number是一个正整数。unit可以是kb,mb或gb。
–device-write-bps=”” 限制指定设备的写入速率[格式::[]]。number是一个正整数。unit可以是kb,mb或gb。
–device-read-iops=””
–device-write-iops=”” 限制指定设备写入速率(每秒IO操作数)[格式::]。number为正整数。
–oom-kill-disable=false 是否禁用容器的OOM Killer
–oom-score-adj=0 调整容器的OOM偏好 (-1000 to 1000)
–memory-swappiness=”” 调整容器的内存swappiness行为。 接受介于0和100之间的整数。
–shm-size=”” /dev/shm的大小。格式为:。number必须大于0。unit可选,可以是b,k,m或g。如果不指定unit,系统默认使用字节。如果此参数不指定,默认使用64m。

用户内存约束

有四种方式来设置用户内存使用:

选项 结果
memory=inf, memory-swap=inf (default) 对容器内存使用无限制。容器可以根据需要使用尽可能多的内存。
memory=L<inf, memory-swap=inf [设置memory为正整数并设置memory-swap为-1]容器不允许使用超过L字节的内存,不过可以根据需要使用尽可能多的swap[如果主机支持swap内存]
memory=L<inf, memory-swap=2*L [只设置memory,不设置memory-swap]容器不允许使用超过L字节内存,swap加上memory总共不超过两倍L。
memory=L<inf, memory-swap=S<inf, L<=S [memory和memory-swap都设置]容器不允许使用超过L字节内存,swap加上memory不能超过S。

示例:

  1. $ docker run -it ubuntu:14.04 /bin/bash

这个示例我们没有设置内存限制,意味着容器进程可以根据需要使用尽可能多的内存和swap。

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

我们设置了memory限制,取消了swap内存限制,意味着容器进程可以使用300M内存,且可以按需使用尽可能多的swap[如果主机支持swap内存]。

  1. $ docker run -it -m 300M ubuntu:14.04 /bin/bash

我们只设置memory限制,意味着容器进程可以使用300M内存和300M swap,默认下,虚拟内存总共大小[-memory-swap]将设置为memory的两倍大小,所以在这种情况下,memory+swap将是2*300M,所以进程能使用300M swap内存。

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

memory和swap内存都设置了,所以容器进程能使用300M内存和700M swap内存。
内存预留(Memory reservation)是一种内存软限制,允许更大的内存共享。正常情况下,容器可以根据需要使用尽可能多的内存,且仅被硬限制-m/–memory限制。当设置了内存预留,Docker检测内存争用或低内存,并强制容器将其内存消耗限制为预留限制。
始终设置内存预留小于硬限制,否则硬限制优先触发。设置reservation为0表示不做限制。默认下[没有设置预留],内存预留与内存硬限制一样。
内存预留是一个软限制功能,不能保证不会超过限制。而是,这个功能尝试确保的是,当内存争用严重时,内存就按预留设置分配。
以下示例限制内存[-m]为500M,内存软限制200M。

  1. $ docker run -it -m 500M –memory-reservation 200M ubuntu:14.04 /bin/bash

在这个配置下,当容器消耗内存超过200M,小于500M时,下一个系统内存回收将尝试缩减容器内存到200M以下。
以下示例设置内存软限制为1G,没有设置内存硬限制。

  1. $ docker run -it –memory-reservation 1G ubuntu:14.04 /bin/bash

容器可以按需使用尽可能多的内存。这个内存软限制设置只是确保容器不会长时间消耗过多内存,因为每次内存回收就缩减容器内存消耗到软限制。默认下,如果out-of-memory[OOM]错误发生,内核将杀死容器的进程。要更改这个行为,使用–oom-kill-disable选项。这个只在容器设置了-m/–memory选项时才禁止OOM killer。如果-m没有设置,这会导致消耗完主机内存,然后需要杀掉主机系统进程来释放内存。
以下示例限制内存为100M并禁止容器的OOM killer:

  1. $ docker run -it -m 100M –oom-kill-disable ubuntu:14.04 /bin/bash

以下示例说明了使用这个选项的一种危险方式:

  1. $ docker run -it –oom-kill-disable ubuntu:14.04 /bin/bash

这个容器可以无限制使用内存,这会导致主机消耗完内存,然后需要杀掉系统进程来释放内存。–oom-score-adj参数可以设置当系统内存不足时哪些容器将被杀死的优先级,数字越大越容易被杀死。

内核内存约束

内核内存不同于用户内存,因为内核内存不能交换到硬盘。内核内存无法swap可能会当容器消耗过多的内核内存时导致其阻塞系统服务。内核内存包括:

  • stack pages
  • slab pages
  • sockets memory pressure
  • tcp memory pressure
  • 可以设置内核内存限制来约束这些类型的内存。例如,每个进程都会消耗一些stack pages。通过限制内核内存,当内核内存使用过多时,阻止新进程的创建。
    内核内存不会完全独立用户内存。而是,在用户内存限制的上下文中限制内核内存。假设”U”是用户内存限制,”K”是内核限制。有三种可能的方式设置限制:

    选项 结果
    U != 0, K = inf (default) 这个是在使用内核内存已经存在了的标准内存限制机制。内核内存是完全忽略的。
    U != 0, K < U 内核内存是用户内存的一个子集。这个设置适合用在每个cgroup的内存总量已经过度使用的部署中。不建议过度使用内核内存限制,因为这样仍然会消耗完不可回收的内存。在这种情况下,可以配置K以便所有的groups总数不会超过总内存。然后,以系统的服务质量为代价自由设置U。
    U != 0, K > U 因为内核内存的消耗也会反馈到用户计数器中,且容器的两种类型的内存也触发回收。这个配置给了管理员一个内存的统一视图。对仅仅想要追踪内核内存使用情况的用户也有帮助。

    示例:

    1. $ docker run -it -m 500M –kernel-memory 50M ubuntu:14.04 /bin/bash

    memory和内核memory都设置了,所以容器进程可以使用总共500M的内存,在500M内存中,可以使用最高50M内核内存。

    1. $ docker run -it –kernel-memory 50M ubuntu:14.04 /bin/bash

    这里只设置了内核内存限制,所以容器进程可以使用尽可能多的内存,不过只可以使用50M的内核内存。

    Swappiness约束

    默认下,容器内核可以设置交换指定百分比的匿名页面。要设置这个百分比,可以设置–memory-swappiness为0-100的值。0表示关闭匿名页面交换。100表示设置所有匿名页面可交换。默认下,如果没有设置memory-swappiness,内存swappiness的值将从父级继承。
    例如,设置:

    1. $ docker run -it –memory-swappiness=0 ubuntu:14.04 /bin/bash

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

    CPU share限制

    默认下,所有的容器都得到相同比例的CPU周期。这个比例可以通过改变容器的CPU share权重来更改,这个权重是相对于所有其它运行中的容器。
    要更改默认的1024比例,使用-c或–cpu-shares设置权限为2或更高。如果为0,系统将忽略这个值并使用默认的1024。
    这个比例只在当CPU密集型进程运行时应用。当一个容器空闲时,其它容器可以使用剩余CPU时间。实际的CPU时间总数根据运行在系统上的容器数量不同。
    例如,有三个容器,一个的cpu-share为1024,其它两个cpu-share为512。当所有三个容器进程尝试使用100%的CPU时,第一个容器将得到50%的CPU时间。如果添加一个cpu-share为1024的容器,第一个容器只得到33%的CPU。其余的容器得到16.5%, 16.5%和 33%的CPU时间。
    在一个多核系统,CPU时间的份额分布在所有CPU内核上。即使一个容器限制为小于100%的CPU,它也能使用每个单独CPU核的100%时间。
    例如,有一个越过3核的系统。如果启动一个容器{C0},-c=512,只运行一个进程,另一个容器{C1},-c=1024,运行两个进程,cpu shares分配如下:

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

    CPU周期约束

    默认的CPU CFS(完全公平调度器)周期为100ms。我们可以使用–cpu-period来设置CPU周期来限制容器CPU的使用。通常–cpu-period和–cpu-quota配合使用。
    示例:

    1. $ docker run -it –cpu-period=50000 –cpu-quota=25000 ubuntu:14.04 /bin/bash

    如果只有1个CPU,这意味着容器可以每50ms获得50%的CPU运行时间。
    更多信息,参考CFS有关带宽限制的文档

    Cpuset约束

    我们可以设置允许容器在哪个CPU执行。
    示例:

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

    这个示例意思是容器可以在cpu1和cpu3执行。

    1. $ docker run -it –cpuset-cpus="0-2" ubuntu:14.04 /bin/bash

    意思是容器可以在cpu 0, cpu 1和 cpu 2执行。
    我们可以设置允许容器在哪个mems执行。只在NUMA系统有效。
    示例:

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

    这个示例限制容器进程只能使用在memory节点1和3的内存。

    1. $ docker run -it –cpuset-mems="0-2" ubuntu:14.04 /bin/bash

    这个示例限制容器进程只能使用在memory节点0,1和2的内存。

    CPU配额约束

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

    块IO带宽(Blkio)约束

    默认下,所有的容器获得相同比例的块IO带宽[bokio]。这个比例是500。要更改这个比例,使用–bokio-weight参数。

    注意:bokio目前只支持直接IO。缓冲IO目前不支持。

    –blkio-weight参数可以设置10到100的值。例如,下面的命令创建两个容器不同的bokio权重:

    1. $ docker run -it –name c1 –blkio-weight 300 ubuntu:14.04 /bin/bash
    2. $ docker run -it –name c2 –blkio-weight 600 ubuntu:14.04 /bin/bash

    如果同时在这两个容器执行块IO操作,例如:

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

    你会发现这两个容器执行块操作所需的时间的比例与bokio权重的比较一样。
    –blkio-weight-device=”DEVICE_NAME:WEIGHT”设置一个指定设备的权重。DEVICE_NAME:WEIGHT是一个包含设备名称与权重,冒号分隔的字符串。例如,要设置/dev/sda设备权重为200:

    1. $ docker run -it
    2.     –blkio-weight-device "/dev/sda:200"
    3.     ubuntu

    如果–blkio-weight和–blkio-weight-device两个都设置了,docker使用–blkio-weight作为默认权重,并使用–blkio-weight-device来用指定设备的新权重覆盖这个默认值。以下示例使用默认的权重值300,并覆盖在/dev/sda的默认值设置为200:

    1. $ docker run -it
    2.     –blkio-weight 300
    3.     –blkio-weight-device "/dev/sda:200"
    4.     ubuntu

    –device-read-bps参数限制指定设备的读取速率[字节/秒]。例如,以下命令创建一个容器,并限制在/dev/sda的读取速率为每秒1mb:

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

    –device-write-bps参数限制指定设备的写入速率[字节/秒]。例如,以下命令创建一个容器并限制在/dev/sda的写入速率为每秒1mb:

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

    两个参数以:[unit]格式作限制。两个的读取和写入速率必须是一个正整数。可以在指定速率时使用kb,mb或gb。
    –device-read-iops参数限制指定设备读取速率[IO/秒]。例如,以下命令创建一个容器并限制在/dev/sda的读取速率为每秒10000IO:

    1. $ docker run -ti –device-read-iops /dev/sda:1000 ubuntu

    –device-write-iops参数限制指定设备的写入速率[IO/秒]。例如,以下命令创建一个容器并限制在/dev/sda的写入速率为每秒1000IO:

    1. $ docker run -ti –device-write-iops /dev/sda:1000 ubuntu

    两个参数以:[unit]格式作限制。两个的读取和写入速率必须是一个正整数。

    Docker run参考(9) – 清理(-rm)

    默认下,即使容器退出后,容器的文件系统仍然存在。这使得调度更加容易[因此你能查看最后的状态],且默认保存了容器所有的数据。不过如果你运行大量短暂时的前台进程,这些容器文件系统将堆积非常多。想让容器退出时自动清理容器和删除它的文件系统,可以使用–rm选项:

    1. –rm=false: Automatically remove the container when it exits (incompatible with -d)

    当设置–rm参数,docker也会在容器退出时删除与它关联的数据卷。这个与运行docker rm -v my-container类似。不过只删除没有指定名称的数据卷。例如docker run –rm -v /foo -v awesome:/bar busybox top,/foo数据卷将会删除,不过/bar数据卷不会。通过–volumes-from继承的数据卷也会使用同样的逻辑删除 – 如果原始的数据卷指定了一个名称,那么将不会删除。

    Docker run参考(8) – 退出状态码

    docker run的退出码给出了关于为什么容器运行失败或者为什么它退出了的信息。当docker run以非零代码退出时,退出代码遵循chroot标准,如下所示:
    125 – 如果是docker daemon本身的错误

    1. $ docker run –foo busybox; echo $?
    2. # flag provided but not defined: –foo
    3.   See ‘docker run –help’.
    4.   125

    126 – 如果无法调用容器命令

    1. $ docker run busybox /etc; echo $?
    2. # docker: Error response from daemon: Container command ‘/etc’ could not be invoked.
    3.   126

    127 – 如果容器命令不存在

    1. $ docker run busybox foo; echo $?
    2. # docker: Error response from daemon: Container command ‘foo’ not found or does not exist.
    3.   127

    否则,容器命令的退出码

    1. $ docker run busybox /bin/sh -c ‘exit 3’; echo $?
    2. # 3

    Docker run参考(7) – Restart策略(–restart)

    运行容器时使用–restart参数可以指定一个restart策略,来指示在退出时容器应该如何重启或不应该重启。
    当容器启用restart策略时,将会在docker ps显示Up或者Restarting状态。也可以使用docker events命令来生效中的restart策略。
    docker支持如下restart策略:

  • no – 容器退出时不要自动重启。这个是默认值。
  • on-failure[:max-retries] – 只在容器以非0状态码退出时重启。可选的,可以退出docker daemon尝试重启容器的次数。
  • always – 不管退出状态码是什么始终重启容器。当指定always时,docker daemon将无限次数地重启容器。容器也会在daemon启动时尝试重启,不管容器当时的状态如何。
  • unless-stopped – 不管退出状态码是什么始终重启容器,不过当daemon启动时,如果容器之前已经为停止状态,不要尝试启动它。
  • 在每次重启容器之前,不断地增加重启延迟[上一次重启的双倍延迟,从100毫秒开始]来防止影响服务器。这意味着daemon将等待100ms,然后200 ms, 400, 800, 1600等等,直到超过on-failure限制,或执行docker stop或docker rm -f。
    如果容器重启成功[容器启动后并运行至少10秒],然后delay重置为默认的100ms。
    你可以使用on-failure策略指定docker尝试重启容器的最大次数。默认下docker将无限次数重启容器。可以通过docker inspect来查看已经尝试重启容器了多少次。例如,获取容器“my-container”的重启次数:

    1. $ docker inspect -f "{{ .RestartCount }}" my-container
    2. # 2

    或者获取上一次容器重启时间:

    1. $ docker inspect -f "{{ .State.StartedAt }}" my-container
    2. # 2015-03-04T23:47:07.691840179Z

    示例

    1. $ docker run –restart=always redis

    这运行了一个restart策略为always的redis容器,以使得容器退出时,docker将重启它。

    1. $ docker run –restart=on-failure:10 redis

    这个运行了一个restart策略为on-failure,最大重启次数为10的redis容器。如果redis以非0状态退出连续退出超过10次,那么docker将中断尝试重启这个容器。只有on-failure策略支持设置最大重启次数限制。

    Docker run参考(6) – 网络设置

    1. –dns=[]           : Set custom dns servers for the container
    2. –network="bridge" : Connect a container to a network
    3.                       ‘bridge’: create a network stack on the default Docker bridge
    4.                       ‘none’: no networking
    5.                       ‘container:<name|id>’: reuse another container’s network stack
    6.                       ‘host’: use the Docker host network stack
    7.                       ‘<network-name>|<network-id>’: connect to a user-defined network
    8. –network-alias=[] : Add network-scoped alias for the container
    9. –add-host=""      : Add a line to /etc/hosts (host:IP)
    10. –mac-address=""   : Sets the container’s Ethernet device’s MAC address
    11. –ip=""            : Sets the container’s Ethernet device’s IPv4 address
    12. –ip6=""           : Sets the container’s Ethernet device’s IPv6 address
    13. –link-local-ip=[] : Sets one or more container’s Ethernet device’s link local IPv4/IPv6 addresses

    默认下,所有容器都启用了网络并且能够访问外部网络。使用docker run –network none能够完全地禁用网络,这将禁止所有的入站和出站连接。在这个情况下,你只能能够文件或STDIN和STDOUT完成I/O通信。
    发布端口和链接到其它容器只在默认的bridge工作。链接功能是一个旧的功能。你应该始终首选Docker网络驱动的链接功能。
    容器默认使用与主机相同的DNS服务器,不过可以使用–dns覆盖它。
    默认情况下,使用分配给容器的IP地址生成MAC地址。你可以通过–mac-address参数[格式:12:34:56:78:9a:bc]设置一个指定的容器MAC地址。要注意如果你手动指定MAC地址,docker不会检查地址是否唯一。

    支持的网络

  • none – 不使用网络
  • bridge[默认] – 通过veth接口连接容器到bridge
  • host – 在容器内使用主机的网络堆栈
  • container: – 使用其它容器的网络堆栈,通过name或id指定
  • NETWORK – 连接容器到一个用户创建的网络 [使用docker network create命令]
  • Network: none

    设置网络为none容器将无法与外部通信。容器仍然会有一个loopback接口,不过没有外部流量的路由。

    Network: bridge

    设置网络为bridge,容器将使用docker默认的网络设置。主机创建有一个bridge,名为docker0,并为容器创建一对veth接口。其中一个vetch在主机上附着到bridge,而另一个将设置到容器的命名空间内,除了loopback接口。容器在bridge网络分配到一个IP地址,且流量通过这个bridge路由到容器。
    容器默认能够通过它们的IP地址通信。如果要通过名称通信,并且使用链接功能。

    Network: host

    设置网络为host,容器将共享主机的网络堆栈,主机的所有接口将对容器可用。容器的主机名将与主机系统上的主机名匹配。注意–mac-address在host模式时无效。即使在host网络模式下容器默认有它自己的UTS命名空间。因此–hostname在host网络中是允许的,且只更改容器内的hostname。与–hostname类似的–add-host,–dns,–dns-search和–dns-opt选项可用于host网络模式中。这些选项将更新容器内的/etc/hosts或/etc/resolv.conff。不会更改主机中的/etc/hosts和/etc/resolv.conf。
    与默认的bridge模式对比,host模式有更好的网络性能,因为它使用了主机的本地网络堆栈,而bridge必须通过docker deamon进行一级虚拟化。当网络性能要求非常高时,推荐使用这个模式运行容器,例如,生产环境的负载均衡或高性能web server。

    注意:–network=”host”给了容器对本地系统服务全部的访问权限,如D-bus,因此此模式认为是不安全的。

    Network: container

    设置网络为container时,容器将共享另一个容器的网络堆栈。需要以–network container:的格式提供另一个容器的名称。–add-host –hostname –dns –dns-search –dns-opt和–mac-address 在container网络模式中是无效的,–publish –publish-all –expose在container网络模式同样无效。
    如下示例,启动了一个redis容器,绑定在localhost,然后运行另一个容器执行redis-cli命令通过localhost接口连接redis服务器。

    1. $ docker run -d –name redis example/redis –bind 127.0.0.1
    2. $ # use the redis container’s network stack to access localhost
    3. $ docker run –rm -it –network container:redis example/redis-cli -h 127.0.0.1

    User-defined network

    使用docker网络驱动或外部网络驱动插件可以创建一个自己的网络。之后可以连接多个容器到这个网络。一旦连接到用户自定义网络,容器将可以只使用另一个容器的IP地址或名称来通信。
    对于支持多主机网络通信的overlay网络或自定义插件,连接到相同的多主机网络但是从不同主机启动的容器能以这种方式互相通信。
    如下示例使用docker内置的bridge网络驱动创建了一个网络,并在这个网络运行一个容器。

    1. $ docker network create -d bridge my-net
    2. $ docker run –network=my-net -itd –name=container3 busybox

    管理/etc/hosts

    容器将会在/etc/hosts添加容器自身主机名条目,localhost和其它一些常见的条目。–add-host参数可以用来在/etc/hosts添加额外的条目。

    1. $ docker run -it –add-host db-static:86.75.30.9 ubuntu cat /etc/hosts
    2. 172.17.0.22     09d03f76bf2c
    3. fe00::0         ip6-localnet
    4. ff00::0         ip6-mcastprefix
    5. ff02::1         ip6-allnodes
    6. ff02::2         ip6-allrouters
    7. 127.0.0.1       localhost
    8. ::1             localhost ip6-localhost ip6-loopback
    9. 86.75.30.9      db-static

    如果一个容器连接到默认的bridge网络且链接到其它容器,那么这个容器的/etc/hosts文件将添加被链接容器的名称条目。
    如果容器连接到用户定义的网络,容器的/etc/hosts文件将添加在这个网络的所有其它容器的名称条目。

    注意:因此docker会实时更新容器的/etc/hosts文件,可能会出现当容器内的进程读取到空的或不完整的/etc/hosts文件。大多数情况下,重新读取应该能解决这个问题。

    Docker run参考(5) – UTS(–uts)和IPC (–ipc)设置

    UTS设置(–uts)

    1. –uts=""  : Set the UTS namespace mode for the container,
    2.        ‘host’: use the host’s UTS namespace inside the container

    UTS命名空间用于设置主机名和对该命名空间中正在运行的进程可见的域。默认下,所有的容器,包括那么以–network=host运行的容器,有它们自己的UTS命名空间。设置UTS为host将使容器使用与主机相同的U
    TS命名空间。注意–hostname在host UTS模式是无效的。
    当你想在主机更改hostname之后,同时也更改同样的hostname到容器, 这就需要与主机共享UTS命名空间。一个更高级的用例是从容器更改主机的hostname。

    IPC设置(–ipc)

    1. –ipc=""  : Set the IPC mode for the container,
    2.              ‘container:<name|id>’: reuses another container’s IPC namespace
    3.              ‘host’: use the host’s IPC namespace inside the container

    默认下,所有的容器都启用了IPC命名空间。
    IPC(POSIX / SysV IPC)命名空间提供命名的共享内存段,信号量和消息队列的分离。
    共享内存段用来加速内部进程以内存速度通信,而不是通过管道或网络。共享内存通常由数据库和定制(通常是C / OpenMPI,C ++ /使用boost库)的高性能应用程序用于科学计算和金融服务行业。如果这些类型的应用程序分成多个容器,可能需要共享容器的IPC机制。

    Docker run参考(4) – PID设置(–pid)

    1. –pid=""  : Set the PID (Process) Namespace mode for the container,
    2.              ‘container:<name|id>’: joins another container’s PID namespace
    3.              ‘host’: use the host’s PID namespace inside the container

    默认下,所有的容器都启用了PID命名空间。
    PID命名空间提供了进程的分离。PID命名空间删除系统进程视图,允许进程ID可重用,包括pid 1。
    在一些情况下需要容器共享主机进程命名空间,基本上允许容器内的进程可以查看主机的所有进程。例如,构建了一个带调试工具如strace或gdb的容器,想在容器使用这些工具来调试主机的进程。

    示例:容器内运行htop

    创建这个Dockerfile:

    1. FROM alpine:latest
    2. RUN apk add –update htop && rm -rf /var/cache/apk/*
    3. CMD ["htop"]

    构建Dockerfile并tag镜像为myhtop:

    1. $ docker build -t myhtop .

    使用如下命令在容器内运行htop命令:

    1. $ docker run -it –rm –pid=host myhtop

    这样htop就能看到宿主机上的所有进程。

    示例:加入其它容器pid命令空间

    启动一个容器运行redis服务器:

    1. $ docker run –name my-redis -d redis

    通过运行一个带strace的容器来debug这个redis容器:

    1. $ docker run -it –pid=container:my-redis my_strace_docker_image bash
    2. $ strace -p 1

    Docker run参考(3) – 容器标识

    Name (–name)

    此参数有三种方式识别一个容器:

    标识类型 示例值
    UUID long identifier “f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778”
    UUID short identifier “f78375b1c487”
    Name “evil_ptolemy”

    UUID标识符来自docker daemon。如果不使用–name参数指定一个容器名称,那么daemon将生成一个随机的名称。定义一个有意义容器名称方便识别容器。此名称可以用来把容器关联在一个指定的网络内。

    PID

    最后,为了方便自动化,可以让docker把容器ID写到一个你指定的文件。这个与一些程序把它们的进程id写到一个文件类似。

    1. –cidfile="": Write the container ID to the file

    Image[:tag]

    这个虽然不是严格识别一个容器的方法,不过可以使用image[:tag]来指定一个特定版本的镜像来运行一个容器。例如docker run ubuntu:14.04。

    Image[@digest]

    使用v2镜像或之后镜像的格式有一个称为digest的内容可寻址标识符。只要用来生成镜像的内容输入没有更改,这个digest值是可预测和可引用的。
    下面的示例使用sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0 digest来从alpine镜像运行一个容器:

    1. $ docker run alpine@sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0 date

    Docker run参考(2) – Detached vs foreground模式

    当要启动一个docker容器时,首先必须决定是以detached模式在后台运行容器还是以默认的foreground模式运行:

    1. -d=false: Detached mode: Run container in the background, print new container id

    Detached (-d)

    要在detached模式启动一个容器,必须使用-d=true或仅-d选项。docker是这样设计的,当运行在容器的根进程退出时,以detached模式启动的容器也退出。以detached模式运行的容器当它停止时无法自动删除,因此–rm选项和-d选项不能一起使用。
    不要传递一个service x start命令到deatched的容器。例如,下面的命令是尝试启动nginx服务。

    1. $ docker run -d -p 80:80 my_image service nginx start

    这个命令会成功启动nginx服务。不过在detached的容器会失败。根进程service nginx start启动后立即返回,导致detached容器按照设计停止。因此,nginx服务虽然启动了,不过无法使用。所以要按如下命令启动nginx服务:

    1. $ docker run -d -p 80:80 my_image nginx -g ‘daemon off;’

    要对一个detached容器输入/输出,使用网络连接或共享数据卷。
    要重新附着到一个detached容器,使用docker attach命令。

    Foreground

    在forgroud模式[当-d不指定时],docker run能够在容器启动进程并附着控制台到进程的标准输入,输出和标准错误。它甚至可以伪装为一个TTY(这是大多数命令行可执行程序所需要的)并传递信号。有配置的选项有:

    1. -a=[]           : Attach to `STDIN`, `STDOUT` and/or `STDERR`
    2. -t              : Allocate a pseudo-tty
    3. –sig-proxy=true: Proxy all received signals to the process (non-TTY mode only)
    4. -i              : Keep STDIN open even if not attached

    如果你没有指定-a,那么docker将附着所有标准流。可以从三个标准流(STDIN, STDOUT, STDERR)指定你想连接的标准流。如:

    1. $ docker run -a stdin -a stdout -i -t ubuntu /bin/bash

    对于交互的进程[如shell],为了给容器进程分配一个tty,必须-i -t一起使用。-i -t经常写为-it。当客户端标准输出重定向或管道传递时,不能指定-t:

    1. $ echo test | docker run -i busybox cat

    Linux对运行在容器PID 1的进程特别对待:它会忽略任何信号的默认行为。所以,进程不会收到SIGINT或SIGTERM时停止,除非它要这么做。

    Docker run参考(1) – 一般格式

    基本的docker run命令格式为:

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

    docker run命令必须指定创建容器的镜像。镜像开发者可以定义镜像默认的关于:

  • 后台或前台运行
  • 容器标识
  • 网络设置
  • CPU和内存运行时限制
  • 使用docker run [OPTIONS],镜像用户能够添加或覆盖镜像开发者设置的默认参数。并且,镜像用户几乎能够覆盖docker运行时的默认参数。之所以docker run命令有这么多选项设置是因为它能够覆盖镜像和docker运行默认参数。