Docker命令解读-一

来源:互联网 发布:日本讨厌韩国知乎 编辑:程序博客网 时间:2024/06/06 09:29

title: Docker命令解读(一)
date: 2015-11-19 18:15:05
tags: docker

categories: Docker Commands

Docker命令解读系列文章将系统讲解Docker使用的命令,方便大家学习Docker的基本操作。在写这个系列文章的时候,主要参考了Docker官方的文档,有些内容是直接的翻译。原文档地址 Docker Docs
转载请注明出处

首先从docker run 命令开始解读,这是我们使用最多的命令。当我们需要从镜像创建一个容器来运行我们的应用或提供某种服务时,就要使用docker run命令。
官方文档链接:docker run
可以运行docker run --help来查看所有的参数和使用方法
格式:

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

从格式可以看出,docker run命令必须指定一个IMAGE来运行容器。容器中有些默认配置和行为,如:
- 后台还是前台运行
- 容器标识
- 容器运行的CPU,内存等限制
- 权限等

使用[OPTIONS]选项可以改变这些默认值,使用这种方法几乎可以改变容器的所有默认行为,这也是为什么docker run命令有如此多选项的原因。
更多关于[OPTIONS]的内容可以参考Option Types
Note: 你可能需要使用sudo来运行docker run命令,如果你不想使用sudo来运行它,你可以将你的用户加入到你本机的docker组下(注意,这会影响你的系统的安全性)。
下面讲解如下几个方面的[OPTIONS]:
* 前台模式VS后台模式
* 容器标识
* PID设置
* UTS设置
* IPC设置
* 网络模式设置
* 重启策略 --restart
* 清除标识 --rm
* 安全设置
* 自定义cgroups
* 运行时资源约束
* 运行时特权,Linux Capabilities和LXC配置
* 日志驱动器(logging driver)
* 改变Dockerfile设定的默认行为

前台模式VS后台模式

使用docker run命令运行一个容器时,我们可以选择是让他后台运行(detached模式)或者前台运行(foreground模式【默认】)

后台模式

使用detached模式运行容器,需要在docker run 命令中指定-d=true(或-d)选项。使用detached模式运行起来的容器停止时不会自动移除,也就是说,在使用了-d(或-d=true)选项的docker run命令中不能指定--rm选项。
不要将类似于下面的命令传递给一个以detached模式运行起来的容器:

service XXX start

例如下面的命令试图在容器中启动nginx,运行时指定了-d选项:

docker run -d -p 80:80 nginx_image service nginx start

这确实启动了容器中的nginx服务,但是容器却没有保持运行。因为容器中的祖先进程(在这个例子中就是service nginx start)执行完返回,按照容器的设计,容器中的祖先进程返回后容器就停止了。结果,nginx服务启动了但不能使用。
在这个例子中,我们应该使用这样的命令:

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

要与使用detached模式运行起来的容器交换信息,需要使用网络或共享卷(shared volumes),因为在detached模式下docker run命令执行完后,容器就不再监听命令行了。
要重新定位到容器可以使用docker attach命令(参考attach)。

前台模式

前台模式下,docker run命令会在新的容器中启动一个进程,并将这个进程的标准输入,标准输出和标准出错绑定到控制台上(甚至是一个伪TTY客户端)。这些都是可以配置的。

-a=[]            : 绑定'STDIN', 'STDOUT'和/或'STDERR'-t=false         : 分配一个伪TTY终端--sig-proxy=true :传递所有的信号给容器中的进程(仅在非tty模式下有效)-i=false         :使STDIN保持打开,即使容器没有被连上(not attached)

如果你没有指明-a标识,默认会绑定所有的三个标准IO流。你也可以像下面这样绑定三个中的一个或多个:

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

如果要开启一个交互式的容器,必须同时指定-i-t标识,以分配一个tty终端。-i-t标识经常一起写作-it,在接下来的例子中我们经常这样使用。
当标准输出流被重置的时候,-t标识不能指定。
Note:在Linux系统中,PID值为1的进程是被特殊对待的:它屏蔽一切信号的默认行为。也就是说,除非进程被编写成要停止进程,SIGINTSIGTERM信号不会停止进程。

容器标识

用户可以通过三种放式识别一个容器:
- 长识别码(Long ID),如:“f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778”
- 短识别码(Short ID),如:“f78375b1c487”
- 名字(Name),如:“myapp”

识别码是由docker daemon自动生成的,如果你没有通过--name标识为容器指定命令,docker会为你生成一个随机的名称。但建议你给自己的容器指定一个名称,这样可以使容器的名称更明确。指定了名称后,你可以使用它来定位到你的容器。detached模式和foreground模式运行的容器都可以指定名称。
Note:默认网桥上的容器相互之间的通信也是靠名字标识的。
你可以使用--cid-file标识指定将容器的ID写入到一个文件里。

--cid-file=""

PID设置

--pid=""    :给容器设置PID namespace      'host':容器使用主机的PID namespace

默认情况下,每个容器都有自己的PID namespace
PID命名空间(PID namespace)提供了进程之间的隔离,PID namespace屏蔽了系统进程的可见性,使进程ID可以复用(包括进程号1)。
在某些特殊情况下,你可能需要容器共享主机的进程空间,以使容器中的进程可以访问宿主机上的进程。例如,你可以创建一个带有stracegdb等调试工具的容器来调试容器中的程序:

docker run --pid=host rhel7 strace -p 1234

UTS设置

UTS namespace用来隔离容器的名称(hostname),域名(domain)空间。默认情况下,所有的容器,即便是设置了--net=host都有自己的域名空间。将其设置为host将使容器和宿主机共享域名空间。这样的话,容器的主机名将随着宿主机的主机名的改变而改变。也就是说,可以通过一个容器来更改宿主机的主机名。因为--uts=host给了容器更改宿主机名称的所有权限,所以在使用时要慎重考虑。

--uts=""    :为容器设置域名空间      'host':容器与宿主机共享域名空间

IPC设置

--ipc=""                    :为容器设置ipc模式      'container:<name|id>' :使用另一个容器的ipc命名空间      'host'                :容器使用宿主机的ipc命名空间

默认情况下,每个容器都有自己的可用IPC命名空间。
IPC命名空间提供容器间共享内存,信号量和消息队列的隔离。
共享内存是用来加速进程间通信的存储交换速度。

网络模式配置

--dns=[]  :为容器设置DNS服务器--net="bridge":为容器设置网络模式--add-host="" :在/etc/hosts中添加一行--mac-address :设置容器的网卡的MAC地址

默认情况下,容器都有访问外网的权限。用户可以通过docker run --net none关闭容器的网络连接,这同时关闭了容器访问外部和外部访问容器两个方向上的网络连接。如果进行了这样的设置,你就只能通过文件或标准IO来和容器通信了。
默认情况下,容器的DNS被设置成宿主机,你可以通过--dns=”“指定其他的DNS服务器
关于docker的四种网络模式,我在之前的文章中有过介绍,不再赘述,链接地址:Docker之四种网络模式

重启策略

docker run命令中使用--restart标识可以为容器指定重启策略,这可以决定容器在退出(exit)的时候是否重启。如果为容器设置了--restart标识,在运行docker ps命令时,该容器只会呈现两种状态,UpRestarting。可以通过docker events命令查看容器的--restart设置。
Docker支持如下的重启策略:

docker重启策略)

容器每次重启之间的时间间隔是指数递增的,初始值为100ms,这样做是为了防止服务器压力过大。也就是说,docker daemon第一次会等待100ms然后重启容器,第二次等待200ms,接下来是400ms,800ms…,直到on-failure的重启次数达到上限,或用户使用了docker stopdocker rm -f命令停止或删除了容器。
如果容器被成功重启,间隔时间(delay)会被重置为100ms。
Note:--restart-rm标识不能同时指定。

清除标识`–rm`

默认情况下,即使容器退出了,容器的文件系统和用户数据也会被保留下来,这一定程度上方便了调试。但是,如果你短暂的使用了一些前台运行的容器,这些容器的文件系统会占用很多空间,而且以后不会用到。以可以通过指定--rm标识来使容器退出时被自动删除。
Note:
- --rm标识和-d标识不能同时指定
- 如果给一个容器指定了--rm标识,当容器文件系统被删除时,它所使用的卷(volumes)也会被删除。也就是说,--rm标识等同于在容器停止后执行如下命令:

docker rm -m my_container

安全设置

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

<未完待续>

自定义cgroups

用户可以通过--cgroup-parent标识可以将一个容器放到特定的cgroup中运行。使用这种方式你可以根据自己的需要定义cgroup。

运行时资源约束

通过下面的选项用户也可以自定义容器的性能参数(资源约束)
容器性能参数

用户区内存约束

一共有四种方式限制容器中的进程使用的用户区内存的大小:
限制容器使用用户区内存大小的参数
举例:

docker run -it ubuntu /bin/bash

上面的命令没有指定任何内存限制,则默认情况下,容器中的进程可以使用任意多的内存。

docker run -it -m 300M ubuntu /bin/bash

上面仅指定了memory限制,默认情况下,总的虚拟内存大小被设置成memory的两倍,而虚拟内存(virtual memory)=momory+swap。也就是说,上面的容器中的进程可以使用300M memory和300M swap。

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

上面的命令限制了memory的大小,同时将swap memory限制设置为无效,意味着容器中的进程可以使用300M memory,且可以使用任意多的swap memory。

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

同时指定了-m--memory-swap选项,此时容器中的进程可以使用300M的memory和700M的swap memory
Note:--memory-swap事实上是指定总的虚拟内存的大小,也就是memory+swap memory
memory-reservation标识指定的内存限制是一种软限制,使用了这种限制之后容器中的进程仍然可以使用硬限制(-m, –memory指定的内存数量)之内的任意多的内存,但当内存资源不足发生争夺的时候,Docker会限制容器中的进程只能使用不超过reservation限定的内存数量。
一定要在-m,--memory之后再指定-memory-reservation,否则会不起作用。将其设为0意味着不设置软限制,默认情况下,软限制被设为和硬限制一样的值。
换句话说 ,--memory-reservation试图确保当内存资源竞争激烈时,每个容器中的进程会使用不超过其通过--memory-reservation设定的值。
例如:

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

上面的命令设置容器中进程的内存硬限制为500M,软限制为200M。容器中的进程可以使用小于500M的内存,但当下一次系统资源回收时会强制将容器中进程使用的内存缩小为不大于200M。
再比如:

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

这条命令设置了容器中进程的内存软限制为1G内存,没有设置硬限制。此时容器中的进程可以使用任意多的内存。直到资源回收使其减小到不大于1G。
--memory-reservation使一个容器中的进程不会占用太多内存太长时间。
默认情况下,Docker会杀死容器中那些超过了内存限制的进程,可以使用--oom-kill-disable标识改变这种行为。要确保此标识仅在你使用了-m--memory标识的容器中使用。

内核内存约束

与用户区内存不同的是,内核区内存不能被换出(swap out),这意味着系统服务可能会因为使用了太多的内核区内存而被阻塞。
你可以通过--kernel-memory标识指定内核内存限制,这可以阻止当内核内存使用过多时再创建新的进程。
事实上,内核区和用户区内存不是独立的,内核区内存限制包含在用户区限制中,也就是说下面的命令:

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

限制了容器中的进程使用的总内存大小不大于500M,其中内核区内存不大于50M。

内核区内存限制和用户区内存限制之间的关系如下:U表示用户区内存,K表示内核区内存
内核区和用户区内存限制的关系

CPU时间比例约束

默认情况下,所有的容器以相同的比例占用CPU时间,可以通过-c--cpu-shares来改变容器占用CPU的相对权重。默认情况下,这个值被设为1024,如果它被设为0,Docker会忽略这个值,仍然使用默认的1024.
Note:值越大,获得的CPU时间比例越高。
--cpu-shares标识只适用于容器中运行的是CPU繁忙型的进程,当其它进程不占用CPU时,这些CPU繁忙型的进程可以更多的使用CPU。具体使用的CPU的比例随系统中容器数量的变化而改变。
比如:考虑有三个容器的系统,第一个容器的--cpu-shares值被设为1024,另外两个设为512。则第一个容器会获得50%的CPU时间,另外两个各获得25%(不考虑其他进程的消耗)。如果再有第四个进程,其--cpu-shares值也被设为1024,那么第一和第四各获得33%的CPU时间,第二和第三各获得16.5%的CPU时间。
Note:在多CPU核心的系统中,容器占用的CPU时间是被分配到所有的核心中的,也就是说,一个分配比例小于100%的容器有可能占用某个核心100%的CPU时间。

CPU周期约束

默认情况下,CPU的周期大小为100ms,用户可以通过--cpu-period标识设置CPU周期,单位为us(微秒)通常情况下,--cpu-period要和--cpu-quota标识一起使用。
看下面的例子:

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

这意味着容器每50ms可以获得50%的CPU时间。

CPU约束

我们可以通过--cpuset-cpus标识设置容器运行在哪个CPU上,这只适合与多CPU环境中。
例如:

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

容器可以运行在CPU1或CPU3上。

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

容器可以运行在CPU0,1,2上。

IO带宽约束

默认情况下,所有的容器占有IO带宽的权重相同,都是500。可以通过--bikio-weight来改变一个容器相对于其他容器在占用IO带宽方面的权重。
--blkio-weight可以被设定为10到1000之间的值,值越大权重越大。

运行时特权,Linux Capabilities和LXC配置

--cap-add         :添加Linux Capabilities--cap-drop        :移除Linux Capabilities--privileged=false:标记容器拥有特权--device=[]       :允许容器在非privileged下在内部运行设备--lxc-conf=[]     :添加自定义的lxc选项

默认情况下,Docker容器是没有特权的,也就是说Docker容器不能在容器内部运行像Docker daemon这样的进程。这是因为,默认情况下,容器没有获取设备的权限。但是一个“特权”(privileged)容器可以获取所有的设备。
如果用户执行了docker run --privileged,Docker容器会获得宿主机上所有设备的访问权限,并且可以在AppArmor或SElinux上写入一些配置信息。此时,容器中的进程就像运行在宿主机上一样。
更多关于--privileged的信息请参考Docker Blog
如果你想限制某个或某些设备的访问权限,可以使用--device标识,使用它你可以指定在容器内部允许访问的一些设备。例如:

docker run --device=/dev/snd:/dev/snd...默认情况下,容器对使用`--device`添加的容器可以进行`read`,`write`和`mknod`操作,你可以通过给每一个`--device`指定的设备添加`:rwm`标识改变这些默认行为。例如:```bashdocker run --device=/dev/sda:/dev/xvdc:r --rm --it ubuntu fdisk /dev/xvdc<div class="se-preview-section-delimiter"></div>

在使用--privileged标识的时候,用户可以使用--cap-add--cap-drop来添加或移除某些”能力“(Linux Capabilities).
Note:所谓Linux Capabilities是为了将root用户的权限进行进一步细分而设计的,Linux将root用户的权限划分为多个组,每个组可以独立分配。这样,我们就可以给某个用户赋予某一部分超级权限。
Docker默认维护了一个可用的Linux Capabilities的table,下面是可以通过--cap-add--cap-drop添加或移除的Linux Capabilities的表:


更多关于Linux Capabilities的信息请查看capabilities(7)-Linux man page
两个标识都可以使用ALL来添加或移除所有capabilities,比如,用户希望拥有除mknod外的所有capabilities,可以使用如下的命令:

docker run --cap-add=ALL --cap-drop=MKNOD ...<div class="se-preview-section-delimiter"></div>

日志驱动器(logging driver)

容器可以使用docker daemon以外的日志logging driver,通过在docker 润命令中指定--logging-driver=VALUE用户可以指定自己的logging driver。
下面是支持的logging driver选项:

docker logs标识仅对json-filejournaldlogging driver有效。更多信息请参考Configure a logging driver

改变Dockerfile设定的默认行为

当使用Dockerfile创建一个镜像时,往往会在镜像中指定一些容器启动时的默认行为。
其中有四个Dockerfile指令的默认值是无法修改的,这四个指令是:FROM,MAINTAINER,RUNADD。所有其他指令的默认行为都可以在docker run命令中修改。
接下来分析以下几个命令:
* CMD
* ENTRYPOINT
* EXPOSE
* ENV
* VOLUME
* USER
* WORKDIR

关于Dockerfile指令,以前写过一篇文章,可以作为参考Dockerfile指令

CMD

CMD是镜像创建者在Dockerfile中指定的容器运行时默认启动的命令。用户可以通过在docker run中设定新的COMMAND值覆盖它。
如果Dockerfile中也指定了ENTRYPOINT,则CMD的值或docker runCOMMAND的值会作为参数传递给ENTRYPOINT指定的命令。

ENTRYPOINT

ENTRYPOINT指令和CMD指令相似,都是指定容器运行时要执行的命令,但它相对更难被覆盖,如果在Dockerfile中指定了ENTRYPOINT,则CMD的值和docker runCOMMAND的值会作为参数传递给ENTRYPOINT指定的命令。
要覆盖ENTRYPOINT中的命令,需要使用--entrypoint=""标识。
举例:

docker run -it --entrypoint /bin/bash example/redis<div class="se-preview-section-delimiter"></div>

上面的命令使用--entrypoint覆盖了example/redis镜像中原来的命令(比如:/usr/bin/redis-server)

EXPOSE

EXPOSE用于指定容器像外部暴露的端口,一般用于容器对外提供服务的情况(比如web服务使用EXPOSE 80)。
使用--expose选项可以添加暴露的端口。
EXPOSE相关的还有-p-P标识,这部分可直接参考官方的文档EXPOSE

ENV

容器创建时,Docker默认会设定如下的环境变量:

ENV指令用于添加环境变量。此外,也可以在docker run命令中使用-e标识添加环境变量,甚至覆盖原来已有的和ENV指定的环境变量。

docker run -it -e "deep=purple" --rm ubuntu /bin/bash -c export<div class="se-preview-section-delimiter"></div>

VOLUME

关于VOLUME已经提到过很多次了,除了参考上面的Dockerfile指令之外,还可以参考:Docker之数据管理
在此不再赘述

USER

默认情况下,容器中的用户是root用户,也可以添加其他的用户,用户之间以名字标识。
Dockerfile的创建者可以通过USER指令指定容器中运行第一个进程的user。当使用docker run启动容器时,可以通过-u标识改变USER的默认值。

-u="" Username or ID<div class="se-preview-section-delimiter"></div>

WORKDIR

容器中运行程序的默认工作目录是根目录/,可以使用WORKDIR指令在Dockerfile中指定其他的目录,WORKDIR的值可以使用如下的方法覆盖:

-w="" working dir inside the container
0 0
原创粉丝点击