Docker run 命令的使用方法详解
注意,本文基于最新的docker 1.4文档翻译。
docker会在隔离的容器中运行进程。当运行 docker run命令时,docker会启动一个进程,并为这个进程分配其独占的文件系统、网络资源和以此进程为根进程的进程组。在容器启动时,镜像可能已经定义了要运行的二进制文件、暴露的网络端口等,但是用户可以通过docker run命令重新定义(译者注:docker run可以控制一个容器运行时的行为,它可以覆盖docker build在构建镜像时的一些默认配置),这也是为什么run命令相比于其它命令有如此多的参数的原因。
命令格式
最基本的docker run
命令的格式如下:
$ sudo docker run [options] image[:tag] [command] [arg...]
如果需要查看[options]的详细使用说明,请参考docker关于options的章节。这里仅简要介绍run所使用到的参数。
options总起来说可以分为两类:
1.设置运行方式:
决定容器的运行方式,前台执行还是后台执行;
设置containerid;
设置网络参数;
设置容器的cpu和内存参数;- 设置权限和lxc参数;
2.设置镜像的默认资源,也就是说用户可以使用该命令来覆盖在镜像构建时的一些默认配置。
docker run [options]
可以让用户完全控制容器的生命周期,并允许用户覆盖执行docker build
时所设定的参数,甚至也可以修改本身由docker所控制的内核级参数。
operator exclusive options
当执行docker run
时可以设置以下参数:
detached vs foreground
detached (-d)- foreground
container identification
name (--name)- pid equivalent
ipc setting
network settings
clean up (--rm)
runtime constraints on cpu and memory
runtime privilege, linux capabilities, and lxc configuration
接下来我们依次进行介绍。
detached vs foreground
当我们启动一个容器时,首先需要确定这个容器是运行在前台还是运行在后台。
-d=false: detached mode: run container in the background, print new container id
detached (-d)
如果在docker run
后面追加-d=true
或者-d,那么容器将会运行在后台模式。此时所有i/o数据只能通过网络资源或者共享卷组来进行交互。因为容器不再监听你执行docker run
的这个终端命令行窗口。但你可以通过执行docker attach来重新附着到该容器的回话中。需要注意的是,容器运行在后台模式下,是不能使用--rm选项的。
foregroud
在前台模式下(不指定-d参数即可),docker会在容器中启动进程,同时将当前的命令行窗口附着到容器的标准输入、标准输出和标准错误中。也就是说容器中所有的输出都可以在当前窗口中看到。甚至它都可以虚拟出一个tty窗口,来执行信号中断。这一切都是可以配置的:
-a=[] : attach to `stdin`, `stdout` and/or `stderr` -t=false : allocate a pseudo-tty --sig-proxy=true : proxify all received signal to the process (non-tty mode only) -i=false : keep stdin open even if not attached
如果在执行run命令时没有指定-a参数,那么docker默认会挂载所有标准数据流,包括输入输出和错误,你可以单独指定挂载哪个标准流。
$ sudo docker run -a stdin -a stdout -i -t ubuntu /bin/bash
如果要进行交互式操作(例如shell脚本),那我们必须使用-i -t参数同容器进行数据交互。但是当通过管道同容器进行交互时,就不需要使用-t参数,例如下面的命令:
echo test | docker run -i busybox cat
容器识别
name(--name)
可以通过三种方式为容器命名:
1. 使用uuid长命名("f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778")
2. 使用uuid短命令("f78375b1c487")
3. 使用name("evil_ptolemy")
这个uuid标示是由docker deamon生成的。如果你在执行docker run时没有指定--name,那么deamon会自动生成一个随机字符串uuid。但是对于一个容器来说有个name会非常方便,当你需要连接其它容器时或者类似需要区分其它容器时,使用容器名称可以简化操作。无论容器运行在前台或者后台,这个名字都是有效的。
pid equivalent
如果在使用docker时有自动化的需求,你可以将containerid输出到指定的文件中(pidfile),类似于某些应用程序将自身id输出到文件中,方便后续脚本操作。
--cidfile="": write the container id to the file
image[:tag]
当一个镜像的名称不足以分辨这个镜像所代表的含义时,你可以通过tag将版本信息添加到run命令中,以执行特定版本的镜像。例如: docker run ubuntu:14.04
ipc settings
默认情况下,所有容器都开启了ipc命名空间。
--ipc="" : set the ipc mode for the container, 'container:<name|id>': reuses another container's ipc namespace 'host': use the host's ipc namespace inside the container
ipc(posix/sysv ipc)命名空间提供了相互隔离的命名共享内存、信号灯变量和消息队列。
共享内存可以提高进程数据的交互速度。共享内存一般用在数据库和高性能应用(c/openmpi、c++/using boost libraries)上或者金融服务上。如果需要容器中部署上述类型的应用,那么就应该在多个容器直接使用共享内存了。
network settings
默认情况下,所有的容器都开启了网络接口,同时可以接受任何外部的数据请求。
--dns=[] : set custom dns servers for the container --net="bridge" : set the network mode for the container 'bridge': creates a new network stack for the container on the docker bridge 'none': no networking for this container 'container:<name|id>': reuses another container network stack 'host': use the host network stack inside the container --add-host="" : add a line to /etc/hosts (host:ip) --mac-address="" : sets the container's ethernet device's mac address
你可以通过docker run --net none
来关闭网络接口,此时将关闭所有网络数据的输入输出,你只能通过stdin、stdout或者files来完成i/o操作。默认情况下,容器使用主机的dns设置,你也可以通过--dns来覆盖容器内的dns设置。同时docker为容器默认生成一个mac地址,你可以通过--mac-address 12:34:56:78:9a:bc来设置你自己的mac地址。
docker支持的网络模式有:
none。关闭容器内的网络连接
bridge。通过veth接口来连接容器,默认配置。
host。允许容器使用host的网络堆栈信息。 注意:这种方式将允许容器访问host中类似d-bus之类的系统服务,所以认为是不安全的。
container。使用另外一个容器的网络堆栈信息。
none模式
将网络模式设置为none时,这个容器将不允许访问任何外部router。这个容器内部只会有一个loopback接口,而且不存在任何可以访问外部网络的router。
bridge模式
docker默认会将容器设置为bridge模式。此时在主机上面将会存在一个docker0的网络接口,同时会针对容器创建一对veth接口。其中一个veth接口是在主机充当网卡桥接作用,另外一个veth接口存在于容器的命名空间中,并且指向容器的loopback。docker会自动给这个容器分配一个ip,并且将容器内的数据通过桥接转发到外部。
host模式
当网络模式设置为host时,这个容器将完全共享host的网络堆栈。host所有的网络接口将完全对容器开放。容器的主机名也会存在于主机的hostname中。这时,容器所有对外暴露的端口和对其它容器的连接,将完全失效。
container模式
当网络模式设置为container时,这个容器将完全复用另外一个容器的网络堆栈。同时使用时这个容器的名称必须要符合下面的格式:--net container:<name|id>.
比如当前有一个绑定了本地地址localhost的redis容器。如果另外一个容器需要复用这个网络堆栈,则需要如下操作:
$ sudo docker run -d --name redis example/redis --bind 127.0.0.1 $ # use the redis container's network stack to access localhost $ sudo docker run --rm -ti --net container:redis example/redis-cli -h 127.0.0.1
管理/etc/hosts
/etc/hosts文件中会包含容器的hostname信息,我们也可以使用--add-host这个参数来动态添加/etc/hosts中的数据。
$ /docker run -ti --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
clean up (--rm)
默认情况下,每个容器在退出时,它的文件系统也会保存下来,这样一方面调试会方便些,因为你可以通过查看日志等方式来确定最终状态。另外一方面,你也可以保存容器所产生的数据。但是当你仅仅需要短暂的运行一个容器,并且这些数据不需要保存,你可能就希望docker能在容器结束时自动清理其所产生的数据。
这个时候你就需要--rm这个参数了。 注意:--rm 和 -d不能共用!
--rm=false: automatically remove the container when it exits (incompatible with -d)
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
--secutity-opt="apparmor:profile" : set the apparmor profile to be applied to the container
你可以通过--security-opt修改容器默认的schema
标签。比如说,对于一个mls系统来说(译者注:mls应该是指multiple listing system),你可以指定mcs/mls级别。使用下面的命令可以在不同的容器间分享内容:
#docker run --security-opt label:level:s0:c100,c200 -i -t fedora bash
如果是mls系统,则使用下面的命令:
# docker run --security-opt label:level:topsecret -i -t rhel7 bash
使用下面的命令可以在容器内禁用安全策略:
# docker run --security-opt label:disable -i -t fedora bash
如果你需要在容器内执行更为严格的安全策略,那么你可以为这个容器指定一个策略替代,比如你可以使用下面的命令来指定容器只监听apache端口:
# docker run --security-opt label:type:svirt_apache_t -i -t centos bash
注意:此时,你的主机环境中必须存在一个名为svirt_apache_t
的安全策略。
runtime constraints on cpu and memory
下面的参数可以用来调整容器内的性能。
-m="": memory limit (format: <number><optional unit>, where unit = b, k, m or g) -c=0 : cpu shares (relative weight)
通过docker run -m可以调整容器所使用的内存资源。如果主机支持swap内存,那么可以使用-m可以设定比主机物理内存还大的值。
同样,通过-c可以调整容器的cpu优先级。默认情况下,所有的容器拥有相同的cpu优先级和cpu调度周期,但你可以通过docker来通知内核给予某个或某几个容器更多的cpu计算周期。
比如,我们使用-c或者--cpu-shares =0启动了c0、c1、c2三个容器,使用-c/--cpu-shares=512启动了c3容器。这时,c0、c1、c2可以100%的使用cpu资源(1024),但c3只能使用50%的cpu资源(512)。如果这个主机的操作系统是时序调度类型的,每个cpu时间片是100微秒,那么c0、c1、c2将完全使用掉这100微秒,而c3只能使用50微秒。
runtime privilege, linux capabilities, and lxc configuration --cap-add: add linux capabilities --cap-drop: drop linux capabilities --privileged=false: give extended privileges to this container --device=[]: allows you to run devices inside the container without the --privileged flag. --lxc-conf=[]: (lxc exec-driver only) add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
默认情况下,docker的容器是没有特权的,例如不能在容器中再启动一个容器。这是因为默认情况下容器是不能访问任何其它设备的。但是通过"privileged",容器就拥有了访问任何其它设备的权限。
当操作者执行docker run --privileged
时,docker将拥有访问主机所有设备的权限,同时docker也会在apparmor或者selinux做一些设置,使容器可以容易的访问那些运行在容器外部的设备。你可以访问docker博客来获取更多关于--privileged的用法。
同时,你也可以限制容器只能访问一些指定的设备。下面的命令将允许容器只访问一些特定设备:
$ sudo docker run --device=/dev/snd:/dev/snd ...
默认情况下,容器拥有对设备的读、写、创建设备文件的权限。使用:rwm来配合--device,你可以控制这些权限。
$ sudo docker run --device=/dev/sda:/dev/xvdc --rm -it ubuntu fdisk /dev/xvdc command (m for help): q $ sudo 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 $ sudo docker run --device=/dev/sda:/dev/xvdc:w --rm -it ubuntu fdisk /dev/xvdc crash.... $ sudo docker run --device=/dev/sda:/dev/xvdc:m --rm -it ubuntu fdisk /dev/xvdc fdisk: unable to open /dev/xvdc: operation not permitted
使用--cap-add
和--cap-drop
,配合--privileged,你可以更细致的控制人哦怒气。默认使用这两个参数的情况下,容器拥有一系列的内核修改权限,这两个参数都支持all值,如果你想让某个容器拥有除了mknod之外的所有内核权限,那么可以执行下面的命令:
$ sudo docker run --cap-add=all --cap-drop=mknod ...
如果需要修改网络接口数据,那么就建议使用--cap-add=net_admin,而不是使用--privileged。
$ docker run -t -i --rm ubuntu:14.04 ip link add dummy0 type dummy rtnetlink answers: operation not permitted $ docker run -t -i --rm --cap-add=net_admin ubuntu:14.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
如果docker守护进程在启动时选择了lxc lxc-driver(docker -d --exec-driver=lxc)
,那么就可以使用--lxc-conf来设定lxc参数。但需要注意的是,未来主机上的docker deamon有可能不会使用lxc,所以这些参数有可能会包含一些没有实现的配置功能。这意味着,用户在操作这些参数时必须要十分熟悉lxc。
特别注意:当你使用--lxc-conf修改容器参数后,docker deamon将不再管理这些参数,那么用户必须自行进行管理。比如说,你使用--lxc-conf修改了容器的ip地址,那么在/etc/hosts里面是不会自动体现的,需要你自行维护。
overriding dockerfile image defaults
当开发者使用dockerfile进行build或者使用commit提交容器时,开发人员可以设定一些镜像默认参数。
这些参数中,有四个是无法被覆盖的:from、maintainer、run和add,其余参数都可以通过docker run进行覆盖。我们将介绍如何对这些参数进行覆盖。
cmd (default command or options) entrypoint (default command to execute at runtime) expose (incoming ports) env (environment variables) volume (shared filesystems) user workdir cmd (default command or options) $ sudo docker run [options] image[:tag] [command] [arg...]
这个命令中的command部分是可选的。因为这个image在build时,开发人员可能已经设定了默认执行的命令。作为操作人员,你可以使用上面命令中新的command来覆盖旧的command。
如果镜像中设定了entrypoint,那么命令中的cmd也可以作为参数追加到entrypoint中。
entrypoint (default command to execute at runtime) --entrypoint="": overwrite the default entrypoint set by the image
这个entrypoint和command类似,它指定了当容器执行时,需要启动哪些进程。相对command而言,entrypoint是很难进行覆盖的,这个entrypoint可以让容器设定默认启动行为,所以当容器启动时,你可以执行任何一个二进制可执行程序。你也可以通过command为entrypoint传递参数。但当你需要在容器中执行其它进程时,你就可以指定其它entrypoint了。
下面就是一个例子,容器可以在启动时自动执行shell,然后启动其它进程。
$ sudo docker run -i -t --entrypoint /bin/bash example/redis #or two examples of how to pass more parameters to that entrypoint: $ sudo docker run -i -t --entrypoint /bin/bash example/redis -c ls -l $ sudo docker run -i -t --entrypoint /usr/bin/redis-cli example/redis --help
expose (incoming ports)
dockefile在网络方面除了提供一个expose之外,没有提供其它选项。下面这些参数可以覆盖dockefile的expose默认值:
--expose=[]: expose a port or a range of ports from the container without publishing it to your host -p=false : publish all exposed ports to the host interfaces -p=[] : publish a container᾿s port to the host (format: ip:hostport:containerport | ip::containerport | hostport:containerport | containerport) (use 'docker port' to see the actual mapping) --link="" : add link to another container (name:alias)
--expose可以让容器接受外部传入的数据。容器内监听的端口不需要和外部主机的端口相同。比如说在容器内部,一个http服务监听在80端口,对应外部主机的端口就可能是49880.
如果使用-p或者-p,那么容器会开放部分端口到主机,只要对方可以连接到主机,就可以连接到容器内部。当使用-p时,docker会在主机中随机从49153 和65535之间查找一个未被占用的端口绑定到容器。你可以使用docker port来查找这个随机绑定端口。
当你使用--link方式时,作为客户端的容器可以通过私有网络形式访问到这个容器。同时docker会在客户端的容器中设定一些环境变量来记录绑定的ip和port。
env (environment variables) home set based on the value of user hostname the hostname associated with the container path includes popular directories, such as : /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin term xterm if the container is allocated a psuedo-tty
当容器启动时,会自动在容器中初始化这些变量。
操作人员可以通过-e来设定任意的环境变量,甚至覆盖已经存在的环境变量,或者是在dockerfile中通过env设定的环境变量。
$ sudo docker run -e "deep=purple" --rm ubuntu /bin/bash -c export declare -x home="/" declare -x hostname="85bc26a0e200" declare -x oldpwd declare -x path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" declare -x pwd="/" declare -x shlvl="1" declare -x container="lxc" declare -x deep="purple"
操作人员可以通过-h来设定hostname。也可以使用"--link name:alias"来设定环境变量,当使用--link后,docker将根据后面提供的ip和port信息来连接服务端容器。下面就是使用redis的例子:
# start the service container, named redis-name $ sudo docker run -d --name redis-name dockerfiles/redis 4241164edf6f5aca5b0e9e4c9eccd899b0b8080c64c0cd26efe02166c73208f3 # the redis-name container exposed port 6379 $ sudo docker ps container id image command created status ports names 4241164edf6f $ dockerfiles/redis:latest /redis-stable/src/re 5 seconds ago up 4 seconds 6379/tcp redis-name # note that there are no public ports exposed since we didn᾿t use -p or -p $ sudo docker port 4241164edf6f 6379 2014/01/25 00:55:38 error: no public port '6379' published for 4241164edf6f
你使用--link后,就可以获取到关于redis容器的相关信息。
$ sudo docker run --rm --link redis-name:redis_alias --entrypoint /bin/bash dockerfiles/redis -c export declare -x home="/" declare -x hostname="acda7f7b1cdc" declare -x oldpwd declare -x path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" declare -x pwd="/" declare -x redis_alias_name="/distracted_wright/redis" declare -x redis_alias_port="tcp://172.17.0.32:6379" declare -x redis_alias_port_6379_tcp="tcp://172.17.0.32:6379" declare -x redis_alias_port_6379_tcp_addr="172.17.0.32" declare -x redis_alias_port_6379_tcp_port="6379" declare -x redis_alias_port_6379_tcp_proto="tcp" declare -x shlvl="1" declare -x container="lxc" #and we can use that information to connect from another container as a client: $ sudo docker run -i -t --rm --link redis-name:redis_alias --entrypoint /bin/bash dockerfiles/redis -c '/redis-stable/src/redis-cli -h $redis_alias_port_6379_tcp_addr -p $redis_alias_port_6379_tcp_port' 172.17.0.32:6379>
docker也会将这个alias的ip地址写入到/etc/hosts
文件中。然后你就可以通过别名来访问link后的容器。
$ sudo docker run -d --name servicename busybox sleep 30 $ sudo docker run -i -t --link servicename:servicealias busybox ping -c 1 servicealias
如果你重启了源容器(servicename),相关联的容器也会同步更新/etc/hosts。
volume (shared filesystems) -v=[]: create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. if "container-dir" is missing, then docker creates a new volume. --volumes-from="": mount all volumes from the given container(s)
关于volume参数,可以在managing data in containers查看详细说明,需要注意的是开发人员可以在dockerfile中设定多个volume,但是只能由运维人员设置容器直接的volume访问。
user
容器中默认的用户是root,但是开发人员创建新的用户之后,这些新用户也是可以使用的。开发人员可以通过dockerfile的user设定默认的用户,并通过"-u "来覆盖这些参数。
workdir
容器中默认的工作目录是根目录(/)。开发人员可以通过dockerfile的workdir来设定默认工作目录,操作人员可以通过"-w"来覆盖默认的工作目录。
以上所述是小编给大家介绍的docker run 命令的使用方法详解,希望对大家有所帮助
推荐阅读
-
对python 命令的-u参数详解
-
docker的高可用配置详解
-
详解Linux系统中rename命令的使用方法
-
sketchup怎么复制模型? sketchup复制命令的使用方法
-
举例详解Linux系统下Pure-ftpd的使用方法
-
详解HTML5中的Communication API基本使用方法
-
Docker的ubuntu镜像安装的容器无ifconfig和ping命令的解决
-
PHP启动windows应用程序、执行bat批处理、执行cmd命令的方法(exec、system函数详解),exec函数详解
-
深入Android MediaPlayer的使用方法详解
-
Python全栈入门必学知识:正确的input和print操作使用方法,案例详解!