参考文章:[Docker 技术入门与实战]
容器是 Docker 的另一个核心概念。简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层,同时,容器中的应用进程处于运行状态。
如果认为虚拟机是模拟运行的一整套操作系统和跑在上面的应用。那么 Docker 容器就是独立运行的一个(或一组)应用,以及它们必须的运行环境。
创建容器
本节主要介绍 Docker 容器的 create
,start
,run
,wait
和 logs
子命令。
新建容器
可以使用 docker [container] create
命令新建一个容器,例如:
1 | $ docker create -it ubuntu:latest |
使用 docker [container] create
命令建立的容器处于停止状态,可以使用 docker [container] start
命令来启动它。
由于容器是整个 Docker 技术栈的核心,create
命令和后续的 run
命令支持的选项都十分复杂。
选项主要包括如下几大类:与容器运行模式相关,与容器环境配置相关,与容器资源限制和安全保护相关,如下表:
create 命令与容器运行模式相关的选项
选项 | 说明 |
---|---|
-a, –attach=[] | 是否绑定到标准输入,输出和错误 |
-d, –detach=true | false |
–detach-keys=”” | 从 attach 模式退出的快捷键 |
–entrypoint=”” | 镜像存在入口命令时,覆盖为新的命令 |
–expose=[] | 指定容器会暴露出来的端口或端口范围 |
–group-add=[] | 运行容器的用户组 |
-i, –interactive=true | false |
–ipc=”” | 容器 IPC 命名空间,可以为其他容器或主机 |
–isolation=”default” | 容器使用的隔离机制 |
–log-driver=”json-file” | 指定容器的日志驱动类型,可以为 json-file, syslog, journald,gelf, fluentd, awslogs, splunk, etwlogs, gcplogs 或 none |
–log-opt=[] | 传递给日志驱动的选项 |
–net=”bridge” | 指定容器网络模式,包括 bridge,none,其他容器内网络,host 的网络或某个现有网络 |
–net-alias=[] | 容器在网络中的别名 |
-P, –publish-all=true | false |
-p, –publish=[] | 指定如何映射到本地主机端口,例如 -p 11234-11234:1234-2234 |
–pid=host | 容器的 PID 命名空间 |
–userns=”” | 启用 userns-remap 时配置用户命名空间的模式 |
–uts=host | 容器的 UTS 命名空间 |
–restart=”no” | 容器的重启策略,包括 no, on-failure[:max-retry],always,unless-stopped 等 |
–rm=true | false |
-t, –tty=true | false |
–tmpfs=[] | 挂载临时文件系统到容器 |
-v, –volume[=[[HOST-DIR:]CONTAINER-DIR[:OPTIONS]]] | 挂载主机上的文件卷到容器内 |
–volume-driver=”” | 挂载文件卷的驱动类型 |
–volume-from=[] | 从其他容器挂载卷 |
-w,–workdir=”” | 容器内的默认工作目录 |
create 命令与容器环境和配置相关的选项
选项 | 说明 |
---|---|
–add-host=[] | 在容器内添加一个主机名到 IP 地址的映射关系(通过 /etc/hosts 文件) |
–device=[] | 映射物理主机上的设备到容器内 |
–dns-search=[] | DNS 搜索域 |
–dns-opt=[] | 自定义的 DNS 选项 |
–dns=[] | 自定义的 DNS 服务器 |
-e, –env=[] | 指定容器内的环境变量 |
–env-file=[] | 从文件中读取环境变量到容器内 |
-h, –hostname=”” | 指定容器内的主机名 |
–ip=”” | 指定容器的 IPv4 地址 |
–ip6=”” | 指定容器的 IPv6 地址 |
–link=[<name or id>:alias] | 连接到其他容器 |
–link-local-ip=[]: | 容器的本地链接地址列表 |
–mac-address=”” | 指定容器的 Mac 地址 |
–name=”” | 指定容器的别名 |
create 命令与容器资源限制和安全保护相关的选项
选项 | 说明 |
---|---|
–blkio-weight=10~1000 | 容器读写块设备的 I/O 性能权重,默认为 0 |
–blkio-weight-device=[DEVICE_NAME:WEIGHT] | 指定各个块设备的 I/O 性能权重 |
–cpu-shares=0 | 允许容器使用 CPU 资源的相对权重,默认为一个容器能用满一个核的 CPU |
–cap-add=[] | 增加容器的 Linux 指定安全能力 |
–cap-drop=[] | 移除容器的 Linux 指定安全能力 |
–cgroup-parent=”” | 容器 cgroups 限制的创建路径 |
–cidfile=”” | 指定容器的进程 ID 号写到文件 |
–cpu-period=0 | 限制容器在 CFS 调度器下的 CPU 占用时间片 |
–cpuset-cpus=”” | 限制容器能使用哪些 CPU 核心 |
–cpuset-mems=”” | NUMA 架构下使用哪些核心的内存 |
–cpu-quota=0 | 限制容器在 CFS 调度器下的 CPU 配额 |
–device-read-bps=[] | 挂载设备的读吞吐率限制(以bps为单位) |
–device-write-bps=[] | 挂载设备的写吞吐率限制(以 bps 为单位) |
–device-read-iops=[] | 挂在设备的读速率限制(以每秒 i/o 次数为单位) |
–device-write-iops=[] | 挂载设备的写速率限制(以每秒 i/o 次数为单位) |
–health-cmd=”” | 指定检查容器健康状态的命令 |
–health-interval=0s | 执行健康检查的间隔时间,单位可以为 ms,s,m 或 h |
–health-retries=int | 健康检查失败重试次数,超过则认为不健康 |
–health-start-period=0s | 容器启动后进行健康检查的等待时间,单位可以为 ms,s,m 或 h |
–health-timeout=0s | 健康检查的执行超时,单位可以为 ms,s, m 或 h |
–no-healthcheck=true | false |
–init | 在容器中执行一个 init 进程,来负责响应信号和处理僵尸状态子进程 |
-kernel-memory=”” | 限制容器使用内核的内存大小,单位可以是 b,k,m 或 g |
-m, –memory=”” | 限制容器内应用使用的内存, 单位可以是 b,k,m 或 g |
–memory-reservation=”” | 当系统中内存过低时,容器会被强制限制内存到给定值,默认情况下等于内存限制值 |
–memory-swap=”LIMIT” | 限制容器使用内存和交换区的总大小 |
–com-kill-disable=true | false |
–com-score-adj=”” | 调整容器的内存耗尽参数 |
–pids-limit=”” | 限制容器的 pid 个数 |
–privileged=true | false |
–read-only=true | false |
–security-opt=[] | 指定一些安全参数,包括权限,安全能力,apparmor 等 |
–stop-signal=SIGTERM | 指定停止容器的系统信号 |
–shm-size=”” | /dev/shm 的大小 |
–sig-proxy=true | false |
–memory-swappiness=”0~100” | 调整容器的内存交换区参数 |
-u, –user=”” | 指定在容器内执行命令的用户信息 |
–userns=”” | 指定用户命名空间 |
–ulimit=[] | 通过 ulimit 来限制最大文件数,最大进程数等 |
其他选项还包括:
-l, --label=[]
:以键值对的方式指定容器内的标签信息;--label-file=[]
:从文件中读取标签信息
启动容器
使用 docker [container] start
命令来启动一个已经创建的容器。例如,启动刚创建的 ubuntu 容器
1 | $ docker start d10ed0a376b1 |
此时,通过 docker ps
命令,可以看到一个运行中的容器
1 | $ docker ps |
新建并启动容器
除了创建容器后通过 start
命令启动,也可以直接新建并启动容器。
所需要的命令主要为 docker [container] run
等价于先执行 docker [container] create
命令,再执行 docker [container] start
命令.
例如,下面的命令输出一个 “Hello World”,之后容器自动终止:
1 | $ docker run ubuntu /bin/echo 'Hello World' |
这跟在本地直接执行 /bin/echo ‘Hello World’
相比几乎感觉不出任何区别。
当利用 docker [container] run
来创建并启动容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从共有仓库下载;
- 利用镜像创建一个容器,并启动该容器
- 分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层;
- 从宿主机配置的网桥接口中桥接一个虚拟接口道容器中;
- 从网桥的地址池配置一个IP地址给容器;
- 执行用户指定的应用程序;
- 执行完毕后容器被自动终止。
下面的命令启动一个 bash
终端,允许用户进行交互:
1 | $ docker run -it ubuntu:18.04 /bin/bash |
其中,-t
选项让 Docker 分配一个伪终端(pseudo-tty
)并绑定到容器的标准输入上,-i
则让容器的标准输入保持打开。更多的命令选项可以通过 man docker-run
命令来查看。
在交互模式下,用户可以通过所创建的终端来输入命令,例如:
1 | root@9f7a236ff64d:/# pwd |
在容器内用 ps
命令查看进程,可以看到,只运行了 bash
应用,并没有运行其他无关的进程。用户可以按 Ctrl+d
或输入 exit
命令来退出容器。
对于所创建的 bash
容器,当用户使用 exit
命令退出 bash
进程后,容器也会自动退出。这是因为对于容器来说,当其中的应用退出后,容器的使命完成,也就没有继续运行的必要了。
可以使用 docker container wait CONTAINER [CONTAINER...]
子命令来等待容器退出,并打印退出返回结果。
某些时候,执行 docker [container] run
的时候因为命令无法正常执行,容器会出错直接退出,此时可以查看退出的错误代码。
默认情况下,常见的错误代码包括:
- 125:Docker daemon 执行出错,例如指定了不支持的 Docker 参数;
- 125:所指定命令无法执行,例如权限出错;
- 127:容器内命令无法找到。
命令执行后出错,会默认返回命令的推出错误码。
守护态运行
更多的时候,需要让 Docker 容器在后台以守护态形式运行。此时,可以通过添加参数 -d
来实现。
例如,下面的命令会在后台运行容器:
1 | $ docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done" |
容器启动后会返回一个唯一的 id
,也可以通过 docker ps
或 docker container ls
命令来查看容器信息:
1 | $ docker ps |
查看容器输出
要获取容器的输出信息,可以通过 docker [container] logs
命令
该命令支持的选项包括:
- –details: 打印详细信息
- -f, –follow: 持续保持输出;
- –since string: 输出从某个时间开始的日志;
- –tail string: 输出最近的若干日志;
- -t, –timestamps: 显示时间戳信息;
- –until string: 输出某个时间之前的日志。
例如, 查看某容器的输出可以使用如下命令:
1 | $ docker logs 1b4b98e5f754 |
停止容器
本节主要介绍 Docker 容器的 pause/unpause
, stop
和 prune
子命令
暂停容器
可以使用 docker [container] pause CONTAINER [CONATINER...]
命令来暂停一个运行中的容器。
例如,启动一个容器,并将其暂停:
1 | $ docker run --name test --rm -it ubuntu bash |
处于 paused
状态的容器,可以使用 docker [container] unpause CONTAINER [CONTAINER...]
命令来恢复到运行状态。
终止容器
可以使用 docker [container] stop
来终止一个运行中的容器。该命令的格式为:
1 | docker [container] stop [-t|--time [=10]] [CONTAINER...] |
该命令会首先向容器发送 SIGTERM
信号,等待一段超时时间后(默认为10秒),再发送 SIGKILL
信号来终止容器。
1 | $ docker stop 1b4b98e5f754 |
此时,执行 docker container prune
命令,会自动清除掉所有处于停止状态的容器。
此外,还可以通过 docker [container] kill
直接发送 SIGKILL
信号来强行终止容器。
docker [container] restart
命令会将一个运行状态的容器先终止,然后再重新启动
进入容器
在使用 -d
参数时,容器启动后会进入后台,用户无法看到容器中的信息,也无法进行操作。这个时候如果需要进入容器操作,推荐使用官方的 attach
或 exec
命令。
attach 命令
attach
是 Docker 自带的命令,命令格式为:
1 | docker [container] attach [--detach-keys[=[]]] [--no-stdin] [--sig-proxy[=true]] CONTAINER |
这个命令支持三个主要选项:
--detach-keys[=[]]
: 指定退出attach
模式的快捷键序列,默认是CTRL-p
CTRL-q
;--no-stdin=true|false
: 是否关闭标准输入,默认是保持打开;--sig-proxy=true|false
: 是否代理收到的系统信号给应用程序,默认为true
。
下面示例如何使用该命令:
1 | $ docker run -itd ubuntu |
然而使用 attach
命令有时候并不方便。当多个窗口同时 attach
到一个容器的时候,所有窗口都会同步显示;当某个窗口因命令阻塞时,其他窗口也无法执行操作了。
exec 命令
从 Docker 的 1.3.0 版本起,Docker 提供了一个更加方便的工具 exec
命令,可以在运行中容器内直接执行任意命令。
该命令的基本格式为:
1 | docker [container] exec [-d|--detach] [--detach-keys[=[]]] [-i|--interactive] [--privileged] [-t|--tty] [-u|--user[=USER]] CONTAINER COMMAND [ARG...] |
比较重要的参数有:
-d, --detach
: 在容器中后台执行命令;--detach-keys=""
: 指定将容器切回后台的按键;-e, --env=[]
: 指定环境变量列表;-i, --interactive=true|false
: 打开标准输入接收用户输入命令,默认值为 false;--privileged=true|false
: 是否给执行命令以最高权限,默认为 false;-t, --tty=true|false
: 分配伪终端,默认值为 false;-u, --user=""
: 执行命令的用户名或 ID。
例如,进入刚刚创建的容器中,并启动一个 bash:
1 | $ docker exec -it 2fd13fdc17a5 /bin/bash |
删除容器
可以使用 docker [container] rm
命令来删除处于终止或退出状态的容器,命令格式为:
1 | docker [container] rm [-f|--force] [-l|--link] [-v|--volumes] CONTAINER [CONTAINER...] |
主要支持的选项包括:
-f, --force=true|false
: 是否强行终止并删除一个运行中的容器;-l, --link=false
: 删除容器的连接,但保留容器;-v, --volumes=false
: 删除容器挂载的数据卷。
例如,查看处于终止状态的容器,并删除:
1 | $ docker ps -a |
默认情况下,docker rm
命令只能删除已经处于终止或退出状态的容器,并不能删除还处于运行状态的容器。
如果要直接删除一个运行中的容器,可以添加 -f
参数。Docker 会先发送 SIGKILL
信号给容器,终止其应用,之后强行删除:
1 | $ docker rm 66e3cd440694 |
导入和导出容器
某些时候,需要将容器从一个系统迁移到另外一个系统,此时可以使用 Docker 的导入和导出功能,这也是 Docker 自身提供的一个重要特性。
导出容器
导出容器是指,导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态。
可以使用 docker [container] export
命令,格式为:
1 | docker [container] export [-o|--output[=""]] CONTAINER |
其中,可以通过 -o
选项来指定导出的 tar
文件名,也可以直接通过重定向来实现。
首先,查看所有的容器,如下所示:
1 | $ docker ps -a |
分别导出 9f7a236ff64d 容器和 d10ed0a376b1 容器到文件 test_for_run.tar
文件和 test_for_stop.tar
文件:
1 | $ docker export -o test_for_run.tar d10ed0a376b1 |
之后可以将导出的 tar 文件传输到其他机器上,然后通过导入命令导入到系统中,实现容器的迁移。
导入容器
导出的文件又可以使用 docker [container] import
命令导入镜像,该命令格式为:
1 | docker import [-c|--change[=[]]] [-m|--message[=MESSAGE]] file|URL| -- [REPOSITORY[:TAG]] |
用户可以通过 -c, --change=[]
选项在导入的同时执行对容器进行修改的 Dockerfile
指令。
下面将导出的 test_for_run.tar 文件导入到系统中:
1 | $ docker import test_for_run.tar -- test/ubuntu:v1.0 |
之前有介绍过使用 docker load
命令来导入一个镜像文件,与 docker [container] import
命令十分类似。
实际上,既可以使用 docker load
命令来导入镜像存储文件到本地镜像库,也可以使用 docker import
命令来导入一个容器快照到本地镜像库。这两者的区别在于:容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积更大。此外,从容器快照文件导入时可以重新制定标签等元数据信息。
查看容器
本节主要介绍 Docker 容器的 inspect
,top
和 stats
子命令。
查看容器详情
查看容器详情可以使用 docker container inspect [OPTIONS] CONTAINER [CONTAINER...]
子命令。
例如,查看某容器的具体信息,会以 json 格式返回包括容器 ID,创建时间,路径,状态,镜像,配置等在内的各项信息:
1 | $ docker container inspect heuristic_curran |
查看容器内进程
查看容器内进程可以使用 docker [container] top [OPTIONS] CONTAINER [CONTAINER...]
子命令。
这个子命令类似于 Linux 系统中的 top
命令,会打印出容器内的进程信息,包括 PID,用户,时间,命令等。
例如,查看某容器内的进程信息,命令如下:
1 | $ docker top heuristic_curran |
查看状态信息
查看统计信息可以使用 docker [container] stats [OPTIONS] [CONTAINER…] 子命令,该命令会显示 CPU,内存,存储,网络等使用情况的统计信息。
支持的选项包括:
- -a, –all: 输出所有容器统计信息,默认仅在运行中;
- –format string: 格式化输出信息;
- –no-stream: 不持续输出,默认会自动更新持续更新实时结果;
- –no-trunc: 不截断输出信息。
例如,查看当前运行中容器的系统资源使用统计:
1 | $ docker stats heuristic_curran |
其他容器命令
本节主要介绍 Docker 的 cp
, diff
, port
和 update
子命令。
复制文件
docker [container] cp
命令支持在容器和主机之间复制文件。命令格式为:
1 | docker [container] cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- |
支持的选项包括:
-a, --archive
: 打包模式,复制文件会带有原始的uid/gid
信息;-L, --follow-link
: 跟随软连接,当原路径为软连接时,默认只复制连接信息,使用该选项会复制链接的目标内容;
例如,将本地的路径 data
复制到 test
容器的 /tmp
路径下:
1 | $ docker cp data test:/tmp/ |
查看变更
docker [container] diff
查看容器内文件系统的变更。命令格式为:
1 | docker [container] diff CONTAINER |
例如,查看 test
容器内的数据修改:
1 | $ docker container diff test |
查看端口映射
docker [container] port
命令可以查看容器的端口映射情况。命令格式为:
1 | docker container port CONTAINER [PRIVATE_PORT[/PROTO]] |
例如,查看 test
容器的端口映射情况:
1 | $ docker container port test |
更新配置
docker [container] update
命令可以更新容器的一些运行时配置,主要是一些资源限制份额。命令格式为:
1 | docker [container] update [OPTIONS] CONTAINER [CONTAINER...] |
支持的选项包括:
--blkio-weight uint16
: 更新块 IO 限制,10~1000, 默认为 0,代表无限制;--cpu-period int
: 限制 CPU 调度器 CFS 使用时间,单位为微秒,最小 1000;--cpu-quota int
: 限制 CPU 调度器 CFS 配额,单位为微秒, 最小 1000;--cpu-rt-period int
: 限制 CPU 调度器的实时周期,单位为微秒;--cpu-rt-runtime int
: 限制 CPU调度器的实时运行时,单位为微秒;-c, --cpu-shares int
: 限制 CPU 使用份额;--cpus decimal
: 限制 CPU 个数;--cpuset-cpus string
: 允许使用的 CPU 核,如 0-3, 0,1;--cpuset-mems string
: 允许使用的内存块,如 0-3,0,1;--kernel-memory bytes
: 限制使用的内核内存;-m,--memory bytes
: 限制使用的内存;--memory-reservation bytes
: 内存软限制;--memory-swap bytes
: 内存加上缓存区的限制,-1 表示对缓存区无限制;--restart string
: 容器退出后的重启策略。
例如,限制总配额为1秒,容器 test
所占用时间为 10%,代码如下:
1 | $ docker update --cpu-quota 1000000 test |