菜鸟笔记
提升您的技术认知

docker 中文文档(译)-ag真人游戏

docker 中文文档
docker 运行参考

  docker进程运行在独立的容器中。一个容器就是一个独立运行在宿主机上的进程,宿主机可能是本机或者是远程机器。当执行 docker run命令时,容器会使用它自己的文件系统、自己的网络、自己的进程树、以脱离宿主机的方式独立运行。

  本文详细介绍了如何使用docker run命令来在运行期定义容器内部资源。

常用类型

  docker run 的基础用法类似:

$ docker run [options] image[:tag|@digest] [command] [arg...]

  docker run 必须指定一个镜像来生成容器。

  一个镜像开发者可以定义以下相关内容:

  •   以后台方式运行(detached)还是以前台方式运行(foreground)
  • 容器标识(--name 指定容器名称)
  • 网络设置
  • 在受限制的cpu和内存上运行

  使用docker run可以添加或者覆盖镜像,默认被开发人员设置。另外,操作者几乎可以覆盖所有docker运行期的默认值。操作者能够覆盖镜像和docker运行时默认值,这就是为什么run比其他docker命令拥有更多选项的原因。

操作者特有选项

  只有操作者(执行docker run的人)可以使用一下选项:

  • 前台还是后台显示:-d (detached),默认-d 等于 -d=true
  • 容器唯一标识设置:-- name;pid
  • ipc设置:--ipc
  • 网络设置
  • 重启策略(--restart)
  • 自动清除已停止的容器(--rm)
  • 运行期资源约束
  • 运行期优先级和linux功能

分离式vs前台式

  当启动一个docker容器时,你必须先决定是想前台式运行还是分离式运行:

-d=false  分离模式: 在后台运行程序, 会在控制台打印一个新的容器id

分离方式 detached[-d]

  以分离式启动一个容器,你可以使用 -d=true 或者直接 -d 选项。根据设计描述,以分离式启动的所有容器当root进程执行容器退出命令时才会退出,如果指定了--rm选项还会删除容器。如果你使用了-d选项并同时使用了--rm,当容器退出了或者守护进程宕了,都会删除掉容器本身。

  分离模式不要使用 service x start,例如下面这个命令试图启动一个nginx服务:

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

  启动nginx容器成功了,然而,它并没有采用分离容器的方式,因为root进程(service nginx start) 返回了,分离容器按设计停止。结果是,nginx服务启动了,但是不能用。相对的,启动一个nginx服务应该像这样:

$ docker run -d -p 80:80 my_image nginx -g 'daemon off;'

  分离式启动的容器,需要输入/输出,需要使用网络连接或者共享数据卷。因为在 docker run之后容器不再监听命令行。如果想重新连接容器,使用 docker attach命令。

前台方式

  前台方式运行(当 -d 没有被指定的情况),docker run 可以启动一个进程(容器)并连接进程(容器)的标准输入、输出、错误信息。它甚至可以装成一个tty(这是大多数命令行执行所期望的)来发送信号。所有的一切都是可配置的:

-a=[]           : attach to `stdin`, `stdout` and/or `stderr`
-t              : allocate a pseudo-tty
--sig-proxy=true: proxy all received signals to the process (non-tty mode only)
-i              : keep stdin open even if not attached

如果没有指定 -a,那么docker将会默认连接 标准输入、输出、错误 三种。你可以指定想要连接哪一种(stdin/stdout/stderr),例如:

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

对于交互模式(像shell一样),你需要使用 -i -t 一起来分配一个tty给容器。 -i -t,经常写作-it,在后面的例子中也可以看到例子。指定-t 会禁止客户端接收它的标准输入流:

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

容器标识

  name [--name]

  给容器起一个标识符有三种方法:

标识类型 样例
uuid 长标识 “f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778”
uuid 短标识 “f78375b1c487”
名称 “evil_ptolemy”

uuid标识是由docker进程决定的,如果你不使用 --name 指定一个容器名称,docker进程会生成一个随机的字符串返回给你,给容器添加name能使容器更容易被理解。如果你指定了name,就在docker网络引用此容器时可以通过name直接使用,这在前端方式和分离方式都有效。

类似进程id

  最终效果是为了自动化,你可以让docker去输出容器id到一个指定的文件中。这类似于一些程序把自己的进程id写到一个文件中。

--cidfile="": write the container id to the file

image[:tag]

  虽然不是严格标识容器,但你可以指定镜像的版本,执行命令时加入标签(image[:tag])。例如, docker run ubuntu:14.04

image[@digest]

  使用v2或更高版本镜像格式的镜像具有摘要,可寻址内容标识符。只要用来生成摘要的镜像没有改变,摘要值就是可知的可信任的。

  下面的运行一个alpine容器的例子,返回的值:

sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0

  使用digest运行:

$ docker run alpine@sha256:9cacb71397b640eca97488cf08582ae4e4068513101088e9f96c9814bfda95e0 date

pid settings (--pid)

--pid=""  : set the pid (process) namespace mode for the container,
             'container:': joins another container's pid namespace
             'host': use the host's pid namespace inside the container

  默认的,所有容器的 pid命名空间都是激活的。

  pid命名空间提供了进程隔离。pid命名空间去除了系统进程视图,并且允许进程id复用(甚至包括pid 1)。

  有些情况,你想让容器共享宿主机的进程命名空间,事实上就是允许容器内的进程可以看到系统中的所有进程。例如,你可以使用调试工具构建一个容器,就像 “strace”或“gdb”,但是想在容器内使用这些调试工具。

例如:在容器里运行htop

  注:htop是一个内存、cpu 等使用情况的监控工具,是top命令的加强版(http://hisham.hm/htop/htop_talk.pdf),在容器里运行htop的意思是,如何在一个容器里面运行一条自定义的命令。

  创建一个dockerfile:

from alpine:latest
run apk add --update htop && rm -rf /var/cache/apk/*
cmd ["htop"]

  构建镜像,镜像名叫myhtop:

$ docker build -t myhtop .

  使用下面的命令,在容器里运行 htop:

$ docker run -it --rm --pid=host myhtop

  通过连接另一个容器的pid命名空间,可以调试另一个容器。

例子

  启动一个redis服务:

$ docker run --name my-redis -d redis

  通过运行另一个容器来绑定待调试的容器,通过strace来进行调试redis容器:

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

uts settings (--uts)

--uts=""  : set the uts namespace mode for the container,
       'host': use the host's uts namespace inside the container

  uts 命名空间是用来设置主机名和域名的,达到对所有在此命名空间中运行中的进程可见的效果。默认,所有容器,包括那些使用了 --network=host 的容器,都有它们自己的uts命名空间。host的设置会导致容器都在宿主机上使用相同的uts命名空间。需要注意, --hostname 在 host uts模式下是不生效的。

  你可能想把uts命名空间共享到宿主机,如果想把容器的主机名的变化同步到宿主机主机名,一个更为高级的用法可以做到。

ipc settings (--ipc)

inter-process communication,进程间通信

--ipc="mode"  : 给容器设置ipc模式
value description
”” use daemon’s default.
“none” own private ipc namespace, with /dev/shm not mounted.
“private” own private ipc namespace.
“shareable” own private ipc namespace, with a possibility to share it with other containers.
“container: <_name-or-id_>" join another (“shareable”) container’s ipc namespace.
“host” use the host system’s ipc namespace.

 

  如果没有指定,docker守护进程默认使用 “private”或“shareable”,具体使用哪个取决于docker守护进程的版本和配置。

  ipc命名空间提供了命名共享内存段、信号量和消息队列的分离。

  使用共享内存段来加速进程间通信,而不是通过管道或者网络堆栈。共享内存一般用来给数据库、和需要高性能的服务,例如,科学计算、金融业以及工业提供服务。如果这些类型的应用要被拆散到大量容器中,你就可能需要ipc机制,在主容器(i.e.“donor”)中使用“shareable”模式,然后在其它容器中配置“container:”。

网络设置

--dns=[]           : set custom dns servers for the container
--network="bridge" : connect a container to a network
                      'bridge': create a network stack on the default docker bridge
                      'none': no networking
                      'container:': reuse another container's network stack
                      'host': use the docker host network stack
                      '|': connect to a user-defined network
--network-alias=[] : add network-scoped alias for the container
--add-host=""      : add a line to /etc/hosts (host:ip)
--mac-address=""   : sets the container's ethernet device's mac address
--ip=""            : sets the container's ethernet device's ipv4 address
--ip6=""           : sets the container's ethernet device's ipv6 address
--link-local-ip=[] : sets one or more container's ethernet device's link local ipv4/ipv6 addresses

  默认所有容器的网络都是启用的,并且都是可以和外部连接的。也可以禁用网络的输入输出通过 docker run --network none 命令,这种情况,你执行io操作,只能通过文件操作或者标准输入(stdin)、输出(stdout)。

  发布一个端口并且连接到另一个容器,只能使用默认设置(bridge)。连接功能是一个遗留功能,因此你应该更倾向于使用network选项而非linking。

  你的容器将会使用和宿主机一样的dns服务,但是你可以通过 --dns 选项覆盖。

  mac(media access control)地址默认是使用ip地址生成,并分配给容器的,你也可以明确设置容器的mac地址,通过 --mac-address 参数(例如:12:34:56:78:9a:bc)。但是要注意,docker不会去检查这个手动添加的mac地址是否是有效的。

  现已支持的网络配置:

network description
none no networking in the container.
bridge(default) connect the container to the bridge via veth interfaces.
host use the host's network stack inside the container.
container: use the network stack of another container, specified via its name or id.
network connects the container to a user created network (using docker network create command)

network: none

  使用了 network none 的容器,将不能访问任何外部请求,它会有一个启动了的 loopback 接口,但是它无法于外部联通。

network: bridge

  网络配置为 bridge 的容器,将使用docker默认的网络设置。宿主机上有一个bridge的network,一般叫做 docker0 ,而且会为容器创建两个veth 接口。一方面 veth 接口会保bridge附属在宿主机上,另一方面 veth 会放在容器命名空间中的loopback接口中。将会给容器分配一个ip到bridge网络,而且路由都会通过这个bridge网络连到容器上。

network: host

  设置为 host 网络的容器,将会和宿主机网络堆栈共享网络,并且所有的宿主机的接口都能被容器使用。容器的主机名会匹配宿主机的。 需要注意, --mac-address 在host 模式下是不生效的。即使在 host网络模式下,容器也有它自己的默认uts命名空间。同样的, --hostname 在host网络模式下是可用的,而且只是能修改容器本身的主机名。类似于,--hostname ,和 --add-host,--dns,--dns-search,以及 --dns-option 可以在host 模式下使用。 这些选项会更新 容器中 /etc/hosts 或者 /etc/resolv.conf。不会对主机的 /etc/hosts 和 /etc/resolv.conf发生修改。

  和默认的bridge模式进行比较,host模式相当于宿主机和容器共享一个网络,bridge模式必须要穿过一层docker守护进程的虚拟层,因此在网络表现方面host要远远好于bridge。当容器之间网络要求特别苛刻的时候,建议使用host模式,例如:一个负载均衡前置的容器或一个高性能的web服务。

  注意:--network="host",给予了容器访问宿主机系统的所有权限,比如, d-bus, 因此需要考虑一下系统安全问题。

network: container

  设置为container模式的容器,将会和另一个容器共享网络。另一个容器的名字必须是以指定格式提供:--network container:。需要注意, --add-host、--hostname、--dns、--dns-search、--dns-option 和 --mac-address 在这种模式下是不生效的。另外 --publish、-publish-all、--expose也是不生效的。

  例如运行一个redis容器时,绑定到 localhost,然后运行 redis-cli 命令 通过localhost的接口进行连接。

$ docker run -d --name redis example/redis --bind 127.0.0.1
$ # use the redis container's network stack to access localhost
$ docker run --rm -it --network container:redis example/redis-cli -h 127.0.0.1

user-defined network

  用户可以通过docker 网络驱动或者其它的网络驱动插件,自己创建一个网络。可以将多个容器都连到相同的一个网络中。一旦容器都连接到了同一个用户自定义的网络,就可以很容易的使用另一个容器的ip地址或名称进行通信。

  对于 overlay 网络或者用户自定义插件,都可以支持多主机连接,容器连接到相同的多主机网络,但是通过不同引擎启动的也能通过这个方式通信。

  下面的例子是创建了一个网络,使用内置的bridge网络驱动,再启动一个容器并使用此网络

$ docker network create -d bridge my-net
$ docker run --network=my-net -itd --name=container3 busybox

管理 /etc/hosts文件

  生成的容器的 /etc/hosts 文件中定义了参数例如,localhost 还有一些其它常见的参数。 --add-host 参数可以用来修改 /etc/hosts文件。

$ docker run -it --add-host db-static:86.75.30.9 ubuntu cat /etc/hosts
172.17.0.22     09d03f76bf2c
fe00::0         ip6-localnet
ff00::0         ip6-mcastprefix
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters
127.0.0.1       localhost
::1             localhost ip6-localhost ip6-loopback
86.75.30.9      db-static

  如果 一个容器连接到了一个默认的bridge网络,而且有linked到了其它的容器,那么这个容器的hosts文件会修改为link到的那个容器的名字。

  注意: 由于docker可以实时的修改容器的 /etc/hosts文件,所以有时容器中的进程读取hosts文件会出现空读的情况,大多数情况,重复读取可以解决这个问题。

restart policies (--restart)

重启策略

  在docker run时,使用 --restart 参数可以指定重启策略,来设置容器在退出之后以何种情况重启。

  当容器中restart策略生效后,执行 docker ps,容器状态将只会以 up 或者 restarting 显示。还可以使用 docker events 命令来查看已经生效的重启策略。

  docker 已经支持的重启策略:

policy result
no do not automatically restart the container when it exits. this is the default.
on-failure[:max-retries] restart only if the container exits with a non-zero exit status. optionally, limit the number of restart retries the docker daemon attempts.
always always restart the container regardless of the exit status. when you specify always, the docker daemon will try to restart the container indefinitely. the container will also always start on daemon startup, regardless of the current state of the container.
unless-stopped always restart the container regardless of the exit status, including on daemon startup, except if the container was put into a stopped state before the docker daemon was stopped.

 

   在每次重启之前会添加一个持续增加的延时任务(100毫秒开始,每次以之前时间的两倍延时)以防止服务溢出。这就意味着docker守护进程将以100ms, 200ms,400,800,1600 以此类推,直到 on-failure 满足条件,或者 当你对容器执行了 docker stop 或 docker rm -f 。

  如果一个容器成功的重启了(必须正常运行10秒以上),延时任务会被重置为100毫秒的延时。

  当你使用 on-failure 策略时,可以手动指定最大重启尝试次数。默认docker会一直重启。容器重启尝试次数是可以通过命令docker inspect 查看。例如,查看容器“my-container”的最大重启次数:

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

  或者,取容器最后一次重启的时间:

$ docker inspect -f "{
  { .state.startedat }}" my-container
# 2015-03-04t23:47:07.691840179z

  结合 --restart (重启策略) 和 --rm (清空)会导致错误。当容器重启、已连接的客户端都会断开连接。文中稍后看一下使用了 --rm 的例子。

例子:

$ docker run --restart=always redis

  这个redis容器使用了 always 策略,确保如果容器退出了,docker就会重启它。

$ docker run --restart=on-failure:10 redis

  这个redis容器使用on-failure策略,而且最大重启次数是10次。如果redis容器以非0的状态码退出了,docker会最多尝试10次重启。只有 on-failure 策略可以指定最大重启次数。

 

退出状态(exit status)

  docker run 返回的退出状态码信息,显示了容器运行失败的原因或者退出的原因。当docker run退出并且退出状态码不是0的情况,错误码遵从 chroot 标准,如下:

  125: docker进程本身的错误

$ docker run --foo busybox; echo $?
# flag provided but not defined: --foo
  see 'docker run --help'.
  125

126:容器命令无法被成功调用

$ docker run busybox /etc; echo $?
# docker: error response from daemon: container command '/etc' could not be invoked.
  126

127:容器命令无法找到(使用了容器不支持的命令)

$ docker run busybox foo; echo $?
# docker: error response from daemon: container command 'foo' not found or does not exist.
  127

其它错误代码

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

clean up (--rm)

  默认情况,容器在退出之后,它的文件系统还会存在。这使调试非常容易(因为你可以inspect最终的状态)而且保留了所有用户默认数据。但是如果只是短期运行一个前端式的进程,这些容器文件会不断累积。如果你想让docker 自动清空已经退出了的容器,并且清空容器文件,就可以使用 --rm 命令:

--rm=false: automatically remove the container when it exits

  注意:当你使用了--set,docker 也会删除所有与当前容器关联的匿名volume,这就类似运行 docker rm -v my-container。只有那些没有指定名字的volume会被删除。例如,docker run --rm -v /foo -v awesome:/bar busybox top,/foo 会被删除,但是/bar不会。volume 通过 --volumes-from  继承的,也会是同样逻辑删除,如果原始volume 指定了名称,就不会被删掉。

security configuration(安全配置)

--security-opt="label=user:user"     : set the label user for the container
--security-opt="label=role:role"     : set the label role for the container
--security-opt="label=type:type"     : set the label type for the container
--security-opt="label=level:level"   : set the label level for the container
--security-opt="label=disable"       : turn off label confinement for the container
--security-opt="apparmor=profile"    : set the apparmor profile to be applied to the container
--security-opt="no-new-privileges:true|false"   : disable/enable container processes from gaining new privileges
--security-opt="seccomp=unconfined"  : turn off seccomp confinement for the container
--security-opt="seccomp=profile.json": white listed syscalls seccomp json file to be used as a seccomp filter

  你可以通过指定 --security-opt 来重写默认label内容。在下面的命令中,指定级别允许容器之间共享相同的内容。

$ docker run --security-opt label=level:s0:c100,c200 -it fedora bash

注意:还不支持自动翻译mls标签。

  禁用当前容器 security label ,使用--privileged 标签,使用方法:

$ docker run --security-opt label=disable -it fedora bash

  如果你想让容器内进程有一个严谨的安全策略,你可以为容器指定一个类型。你可以执行以下命令,使容器只允许监听apache的端口:

$ docker run --security-opt label=type:svirt_apache_t -it centos bash

注意:你必须先定义一个svirt_apache_t 类型的策略。

  如果你想防止容器进程获取额外的权限,可以执行以下命令:

$ docker run --security-opt no-new-privileges -it centos bash

这意味着,能提升权限的命令(例如: su、sudo) 都不会生效。这样会导致在后续操作中引入一些过滤器,在权限被降低后可能在过滤器方面有更严格的要求。更多细节:内核文档。 

指定一个初始化进程(specify an init process)

你可以使用 --init 命令来说明这是一个初始化进程,应该是pid 1的容器。要指定一个初始化进程需要此进程有一些常用的功能,比如,作为一个僵尸进程处理进程,在容器中运行。

网站地图