Docker 操作镜像

7/28/2019 Docker

# Docker 操作镜像

# 搜索镜像

在拉取镜像之前,可以先通过 docker search 命令在 Docker Hub 上搜索需要的镜像。

docker search [选项] <关键词>
1

比如搜索 nginx:

docker search nginx

# 输出如下
NAME                    DESCRIPTION                        STARS     OFFICIAL   AUTOMATED
nginx                   Official build of Nginx.           18000     [OK]
jwilder/nginx-proxy     Automated Nginx reverse proxy...   2000                 [OK]
...
1
2
3
4
5
6
7

各列含义:

  • NAME:镜像名称
  • DESCRIPTION:镜像描述
  • STARS:收藏数(可以粗略反映流行度)
  • OFFICIAL:是否为官方镜像
  • AUTOMATED:是否为自动构建

常用过滤参数:

# 只显示 star 数 >= 100 的镜像
docker search --filter=stars=100 nginx

# 只显示官方镜像
docker search --filter=is-official=true nginx

# 限制返回结果数量
docker search --limit=5 nginx
1
2
3
4
5
6
7
8

# 获取镜像

之前提到过,Docker Hub (opens new window) 上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像。

从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:

docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
1

具体的选项可以通过 docker pull --help 命令看到,这里我们说一下镜像名称的格式。

  • 镜像仓库地址: 地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。
  • 仓库名: 如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
docker pull nginx

# 输出如下
Using default tag: latest
latest: Pulling from library/nginx
fc7181108d40: Pull complete 
c4277fc40ec2: Pull complete 
780053e98559: Pull complete 
Digest: sha256:bdbf36b7f1f77ffe7bd2a32e59235dff6ecf131e3b6b5b96061c652f30685f3a
Status: Downloaded newer image for nginx:latest
1
2
3
4
5
6
7
8
9
10

# 列出镜像

要想列出已经下载下来的镜像,可以使用 docker image ls 命令。

docker image ls

# 输出如下
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
redis                latest              5f515359c7f8        5 days ago          183 MB
nginx                latest              05a60462f8ba        5 days ago          181 MB
mongo                3.2                 fe9198c04d62        5 days ago          342 MB
<none>               <none>              00285df0df87        5 days ago          342 MB
ubuntu               16.04               f753707788c5        4 weeks ago         127 MB
ubuntu               latest              f753707788c5        4 weeks ago         127 MB
ubuntu               14.04               1e0c3dd64ccd        4 weeks ago         188 MB
1
2
3
4
5
6
7
8
9
10
11

列表包含了 仓库名标签镜像 ID创建时间 以及 所占用的空间

其中仓库名、标签在之前的基础概念章节已经介绍过了。镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个标签。因此,在上面的例子中,我们可以看到 ubuntu:16.04ubuntu:latest 拥有相同的 ID,因为它们对应的是同一个镜像。

# 镜像体积

如果仔细观察,会注意到,这里标识的所占用空间和在 Docker Hub 上看到的镜像大小不同。比如,ubuntu:16.04 镜像大小,在这里是 127 MB,但是在 Docker Hub 显示的却是 50 MB。这是因为 Docker Hub 中显示的体积是压缩后的体积。在镜像下载和上传过程中镜像是保持着压缩状态的,因此 Docker Hub 所显示的大小是网络传输中更关心的流量大小。而 docker image ls 显示的是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和,因为镜像到本地后,查看空间的时候,更关心的是本地磁盘空间占用的大小。

另外一个需要注意的问题是,docker image ls 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。

你可以通过以下命令来便捷的查看镜像、容器、数据卷所占用的空间。

docker system df

# 输出如下
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              24                  0                   1.992GB             1.992GB (100%)
Containers          1                   0                   62.82MB             62.82MB (100%)
Local Volumes       9                   0                   652.2MB             652.2MB (100%)
Build Cache                                                 0B                  0B
1
2
3
4
5
6
7
8

# 虚悬镜像

上面的镜像列表中,还可以看到一个特殊的镜像,这个镜像既没有仓库名,也没有标签,均为 <none>

<none>               <none>              00285df0df87        5 days ago          342 MB
1

这个镜像原本是有镜像名和标签的,原来为 mongo:3.2,随着官方镜像维护,发布了新版本后,重新 docker pull mongo:3.2 时,mongo:3.2 这个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了 <none>。除了 docker pull 可能导致这种情况,docker build 也同样可以导致这种现象。由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 <none> 的镜像。这类无标签镜像也被称为 虚悬镜像(dangling image) ,可以用下面的命令专门显示这类镜像:

docker image ls -f dangling=true

# 输出如下
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              00285df0df87        5 days ago          342 MB
1
2
3
4
5

一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除。

docker image prune
1

# 中间层镜像

为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像。所以在使用一段时间后,可能会看到一些依赖的中间层镜像。默认的 docker image ls 列表中只会显示顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加 -a 参数。

docker image ls -a
1

这样会看到很多无标签的镜像,与之前的虚悬镜像不同,这些无标签的镜像很多都是中间层镜像,是其它镜像所依赖的镜像。这些无标签镜像不应该删除,否则会导致上层镜像因为依赖丢失而出错。实际上,这些镜像也没必要删除,因为之前说过,相同的层只会存一遍,而这些镜像是别的镜像的依赖,因此并不会因为它们被列出来而多存了一份,无论如何你也会需要它们。只要删除那些依赖它们的镜像后,这些依赖的中间层镜像也会被连带删除。

# 删除镜像

如果要删除本地的镜像,可以使用 docker image rm 命令,其格式为:

docker image rm [选项] <镜像1> [<镜像2> ...]
1

# 用 ID、镜像名、摘要删除镜像

其中,<镜像> 可以是 镜像短 ID镜像长 ID镜像名 或者 镜像摘要

比如我们有这么一些镜像:

docker image ls

# 输出如下
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
centos                      latest              0584b3d2cf6d        3 weeks ago         196.5 MB
redis                       alpine              501ad78535f0        3 weeks ago         21.03 MB
docker                      latest              cf693ec9b5c7        3 weeks ago         105.1 MB
nginx                       latest              e43d811ce2f4        5 weeks ago         181.5 MB
1
2
3
4
5
6
7
8

我们可以用镜像的完整 ID,也称为 长 ID,来删除镜像。使用脚本的时候可能会用长 ID,但是人工输入就太累了,所以更多的时候是用 短 ID 来删除镜像。docker image ls 默认列出的就已经是短 ID 了,一般取前 3 个字符以上,只要足够区分于别的镜像就可以了。

比如这里,如果我们要删除 redis:alpine 镜像,可以执行:

docker image rm 501

# 输出如下
Untagged: redis:alpine
Untagged: redis@sha256:f1ed3708f538b537eb9c2a7dd50dc90a706f7debd7e1196c9264edeea521a86d
Deleted: sha256:501ad78535f015d88872e13fa87a828425117e3d28075d0c117932b05bf189b7
Deleted: sha256:96167737e29ca8e9d74982ef2a0dda76ed7b430da55e321c071f0dbff8c2899b
Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23
Deleted: sha256:127227698ad74a5846ff5153475e03439d96d4b1c7f2a449c7a826ef74a2d2fa
Deleted: sha256:1333ecc582459bac54e1437335c0816bc17634e131ea0cc48daa27d32c75eab3
Deleted: sha256:4fc455b921edf9c4aea207c51ab39b10b06540c8b4825ba57b3feed1668fa7c7
1
2
3
4
5
6
7
8
9
10
11

我们也可以用镜像名,也就是 <仓库名>:<标签>,来删除镜像。

docker image rm centos

# 输出如下
Untagged: centos:latest
Untagged: centos@sha256:b2f9d1c0ff5f87a4743104d099a3d561002ac500db1b9bfa02a783a46e0d366c
Deleted: sha256:0584b3d2cf6d235ee310cf14b54667d889887b838d3f3d3033acd70fc3c48b8a
Deleted: sha256:97ca462ad9eeae25941546209454496e1d66749d53dfa2ee32bf1faabd239d38
1
2
3
4
5
6
7

当然,更精确的是使用 镜像摘要 删除镜像。

docker image ls --digests

# 输出如下
REPOSITORY                  TAG                 DIGEST                                                                    IMAGE ID            CREATED             SIZE
node                        slim                sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228   6e0c4c8e3913        3 weeks ago         214 MB

docker image rm node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228

# 输出如下
Untagged: node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
1
2
3
4
5
6
7
8
9
10

# 用 docker image ls 命令来配合

像其它可以承接多个实体的命令一样,可以使用 docker image ls -q 来配合使用 docker image rm,这样可以成批的删除希望删除的镜像。我们在“镜像列表”章节介绍过很多过滤镜像列表的方式都可以拿过来使用。

比如,我们需要删除所有仓库名为 redis 的镜像:

docker image rm $(docker image ls -q redis)
1

或者删除所有在 mongo:3.2 之前的镜像:

docker image rm $(docker image ls -q -f before=mongo:3.2)
1

充分利用你的想象力和 Linux 命令行的强大,你可以完成很多非常赞的功能。

# 给镜像打标签

有些时候,我们需要为镜像加一个新的标签,比如推送到私有仓库前,需要按仓库的命名规则打 tag。这个操作使用 docker tag 命令:

docker tag <源镜像>[:tag] <目标镜像>[:tag]
1

例如:

# 给 nginx:latest 打一个新标签 my-nginx:v1
docker tag nginx:latest my-nginx:v1

# 打上私有仓库地址的 tag,以便后续推送
docker tag nginx:latest registry.example.com/myteam/nginx:v1
1
2
3
4
5

注意: docker tag 并不会复制镜像文件,只是给同一个镜像 ID 添加一个新的引用。因此打完 tag 后,docker image ls 里会看到两条记录,但 IMAGE ID 是相同的。

# 导入和导出镜像

在没有镜像仓库的环境下(比如内网离线服务器),可以将镜像打包成 tar 文件传递到目标机器再加载。

# 导出镜像

# 将镜像保存为 tar 包
docker save -o <文件名.tar> <镜像名>[:tag]

# 例:
docker save -o nginx.tar nginx:latest

# 同时导出多个镜像
docker save -o images.tar nginx:latest redis:alpine
1
2
3
4
5
6
7
8

# 导入镜像

# 从 tar 包加载镜像
docker load -i <文件名.tar>

# 或者用重定向
docker load < nginx.tar
1
2
3
4
5

save/loadexport/import 的区别:

  • docker save / docker load 操作的是 镜像,会保留完整的镜像层、构建历史、元数据。
  • docker export / docker import 操作的是 容器,导出的是文件系统的一份快照,会丢失所有分层信息,导入后是一个新的单层镜像。

一般备份/迁移镜像用前者,只想拿到容器内的文件系统时才用后者。

# 扩展阅读

# 列出部分镜像

不加任何参数的情况下,docker image ls 会列出所有顶级镜像,但是有时候我们只希望列出部分镜像。docker image ls 有好几个参数可以帮助做到这个事情。

根据仓库名列出镜像

docker image ls ubuntu

# 输出如下
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              16.04               f753707788c5        4 weeks ago         127 MB
ubuntu              latest              f753707788c5        4 weeks ago         127 MB
ubuntu              14.04               1e0c3dd64ccd        4 weeks ago         188 MB
1
2
3
4
5
6
7

列出特定的某个镜像,也就是说指定仓库名和标签

docker image ls ubuntu:16.04

# 输出如下
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              16.04               f753707788c5        4 weeks ago         127 MB
1
2
3
4
5

除此以外,docker image ls 还支持强大的过滤器参数 --filter,或者简写 -f。之前我们已经看到了使用过滤器来列出虚悬镜像的用法,它还有更多的用法。比如,我们希望看到在 mongo:3.2 之后建立的镜像,可以用下面的命令:

docker image ls -f since=mongo:3.2

# 输出如下
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
redis               latest              5f515359c7f8        5 days ago          183 MB
nginx               latest              05a60462f8ba        5 days ago          181 MB
1
2
3
4
5
6

想查看某个位置之前的镜像也可以,只需要把 since 换成 before 即可。

此外,如果镜像构建时,定义了 LABEL,还可以通过 LABEL 来过滤。

docker image ls -f label=com.example.version=0.1
1

# 以特定格式显示

默认情况下,docker image ls 会输出一个完整的表格,但是我们并非所有时候都会需要这些内容。比如,刚才删除虚悬镜像的时候,我们需要利用 docker image ls 把所有的虚悬镜像的 ID 列出来,然后才可以交给 docker image rm 命令作为参数来删除指定的这些镜像,这个时候就用到了 -q 参数。

docker image ls -q

# 输出如下
5f515359c7f8
05a60462f8ba
fe9198c04d62
00285df0df87
f753707788c5
f753707788c5
1e0c3dd64ccd
1
2
3
4
5
6
7
8
9
10

--filter 配合 -q 产生出指定范围的 ID 列表,然后送给另一个 docker 命令作为参数,从而针对这组实体成批的进行某种操作的做法在 Docker 命令行使用过程中非常常见,不仅仅是镜像,将来我们会在各个命令中看到这类搭配以完成很强大的功能。因此每次在文档看到过滤器后,可以多注意一下它们的用法。

另外一些时候,我们可能只是对表格的结构不满意,希望自己组织列;或者不希望有标题,这样方便其它程序解析结果等,这就用到了 Go 的模板语法 (opens new window)

比如,下面的命令会直接列出镜像结果,并且只包含镜像 ID 和仓库名:

docker image ls --format "{{.ID}}: {{.Repository}}"

# 输出如下
5f515359c7f8: redis
05a60462f8ba: nginx
fe9198c04d62: mongo
00285df0df87: <none>
f753707788c5: ubuntu
f753707788c5: ubuntu
1e0c3dd64ccd: ubuntu
1
2
3
4
5
6
7
8
9
10

或者打算以表格等距显示,并且有标题行,和默认一样,不过自己定义列:

docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"

# 输出如下
IMAGE ID            REPOSITORY          TAG
5f515359c7f8        redis               latest
05a60462f8ba        nginx               latest
fe9198c04d62        mongo               3.2
00285df0df87        <none>              <none>
f753707788c5        ubuntu              16.04
f753707788c5        ubuntu              latest
1e0c3dd64ccd        ubuntu              14.04
1
2
3
4
5
6
7
8
9
10
11

# Docker 操作容器

# 启动容器

所需要的命令主要为 docker run。例如,下面的命令输出一个 “Hello World”,之后终止容器。

docker run ubuntu:16.04 /bin/echo 'Hello world'
Hello world
1
2

当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定的镜像,不存在就从公有仓库下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
  • 从地址池配置一个 ip 地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被终止

# docker run 常用参数

docker run 的参数非常多,下面列出日常使用中最常用的一批。

参数 说明
-d 后台运行容器(detach)
-i 保持 STDIN 打开(interactive),配合 -t 使用
-t 分配一个伪终端(tty)
-it 交互式 + 伪终端,常用于进入容器 shell
--name 指定容器名称,方便后续管理
-p 端口映射,格式为 宿主端口:容器端口
-P 随机映射所有 EXPOSE 端口到宿主机
-v 挂载数据卷,格式为 宿主路径:容器路径[:ro]
-e 设置环境变量
--network 指定容器加入的网络
--restart 设置容器重启策略
--rm 容器退出后自动删除,适合临时调试
-w 指定容器内工作目录
-u 指定运行容器的用户名或 UID

# 端口映射

将容器内的服务暴露给宿主机访问,需要通过 -p 参数进行端口映射。

# 将宿主机 8080 端口映射到容器的 80 端口
docker run -d -p 8080:80 nginx

# 只绑定到宿主机指定 IP
docker run -d -p 127.0.0.1:8080:80 nginx

# 同时映射多个端口
docker run -d -p 80:80 -p 443:443 nginx

# 随机映射(宿主机端口由 Docker 自动分配)
docker run -d -P nginx
1
2
3
4
5
6
7
8
9
10
11

映射完成后可以用 docker port <容器名> 查看具体的映射情况。

# 挂载数据卷

容器内的数据默认会随容器删除而丢失,如果需要持久化,就要通过 -v 参数挂载数据卷。

# 绑定挂载:将宿主机目录挂载到容器内
docker run -d -v /host/data:/container/data nginx

# 只读挂载(容器内无法修改)
docker run -d -v /host/conf/nginx.conf:/etc/nginx/nginx.conf:ro nginx

# 命名卷:由 Docker 管理,跨容器共享更方便
docker run -d -v mydata:/var/lib/mysql mysql:8

# 匿名卷(一般不推荐直接使用)
docker run -d -v /var/lib/mysql mysql:8
1
2
3
4
5
6
7
8
9
10
11

绑定挂载 vs 命名卷:

  • 绑定挂载:路径由用户指定,直接映射宿主机文件系统。灵活,但依赖宿主机路径。
  • 命名卷:由 Docker 统一管理(存放在 /var/lib/docker/volumes/),更方便备份和迁移,推荐使用。

# 设置环境变量

许多镜像通过环境变量来传递配置,比如 MySQL 的初始密码:

# 单个环境变量
docker run -d -e MYSQL_ROOT_PASSWORD=123456 mysql:8

# 多个环境变量
docker run -d \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -e MYSQL_DATABASE=mydb \
  -e MYSQL_USER=admin \
  -e MYSQL_PASSWORD=admin123 \
  mysql:8

# 从文件读取环境变量
docker run -d --env-file ./mysql.env mysql:8
1
2
3
4
5
6
7
8
9
10
11
12
13

# 重启策略

通过 --restart 参数可以设置容器的自动重启策略,生产环境非常常用。

策略 说明
no 默认值,容器退出后不自动重启
on-failure[:max-retries] 非 0 退出码时自动重启,可指定最大重试次数
always 容器退出后总是重启,Docker 守护进程启动时也会拉起
unless-stopped always 类似,但容器被手动 stop 后,Docker 重启后不会自动拉起
# 生产环境常用
docker run -d --restart=always --name my-web nginx

# 最多重试 3 次
docker run -d --restart=on-failure:3 my-app
1
2
3
4
5

# 综合示例

以下示例综合了大部分常用参数:

docker run -d \
  --name my-mysql \
  --restart=always \
  -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -v /host/mysql/data:/var/lib/mysql \
  -v /host/mysql/conf:/etc/mysql/conf.d \
  --network=my-net \
  mysql:8
1
2
3
4
5
6
7
8
9

# 终止容器

可以使用 docker container stop 来终止一个运行中的容器。此外,当 Docker 容器中指定的应用终结时,容器也自动终止。

例如对于只启动了一个终端的容器,用户通过 exit 命令或 ctrl + d 来退出终端时,所创建的容器立刻终止。终止状态的容器可以用 docker container ls -a 命令看到。例如

docker container ls -a

# 输出如下
CONTAINER ID        IMAGE                    COMMAND                CREATED             STATUS                          PORTS               NAMES
ba267838cc1b        ubuntu:14.04             "/bin/bash"            30 minutes ago      Exited (0) About a minute ago                       trusting_newton
98e5efa7d997        training/webapp:latest   "python app.py"        About an hour ago   Exited (0) 34 minutes ago                           backstabbing_pike
1
2
3
4
5
6

# 启动已终止容器

处于终止状态的容器,可以通过 docker container start 命令来重新启动。此外,docker container restart 命令会将一个运行态的容器终止,然后再重新启动它。

docker container start [container ID or NAMES]
1

# 守护态运行

更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d 参数来实现。如果不使用 -d 参数运行容器。

docker run ubuntu:16.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"

# 输出如下
hello world
hello world
hello world
hello world
1
2
3
4
5
6
7

容器会把输出的结果 (STDOUT) 打印到宿主机上面,如果使用了 -d 参数运行容器。

docker run -d ubuntu:17.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"

# 输出如下
77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a
1
2
3
4

此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面(输出结果可以用 docker logs 查看)。

注意: 容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关。

# 容器日志

要获取容器的输出信息,可以通过 docker container logs 命令。

docker container logs [container ID or NAMES]

# 输出如下
hello world
hello world
hello world
1
2
3
4
5
6

# 进入容器

在使用 -d 参数时,容器启动后会进入后台。某些时候需要进入容器进行操作,docker exec 命令能让我们以交互的方式进入容器。

docker exec 后边可以跟多个参数,这里主要说明 -i -t 参数。只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。当 -i -t 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。

docker exec -it 69d1 bash
root@69d137adef7a:/#
1
2

如果从这个 stdin 中 exit,不会导致容器的停止。更多参数说明请使用 docker exec --help 查看。

# 查看容器详情

docker inspect 可以查看容器的完整配置和运行状态信息,返回内容为 JSON 格式。

docker inspect <container-id | container-name>
1

由于输出内容非常庞大,实际使用中一般配合 --format 提取需要的字段:

# 查看容器 IP
docker inspect --format='{{.NetworkSettings.IPAddress}}' <container-id>

# 查看容器挂载情况
docker inspect --format='{{json .Mounts}}' <container-id>

# 查看容器启动命令
docker inspect --format='{{.Config.Cmd}}' <container-id>

# 查看容器状态
docker inspect --format='{{.State.Status}}' <container-id>
1
2
3
4
5
6
7
8
9
10
11

# 查看容器资源占用

docker stats 可以实时查看容器的 CPU、内存、网络、磁盘 IO 使用情况,类似 Linux 上的 top

# 查看所有正在运行的容器
docker stats

# 查看指定容器
docker stats <container-id>

# 只打印一次,不持续刷新(常用于脚本采集)
docker stats --no-stream

# 自定义显示列
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
1
2
3
4
5
6
7
8
9
10
11

# 查看容器进程

类似宿主机上的 ps,可以查看容器内运行的进程:

docker top <container-id>
1

# 查看端口映射

# 查看容器所有端口映射
docker port <container-id>

# 查看指定容器端口的映射
docker port <container-id> 80
1
2
3
4
5

# 文件复制

在宿主机和容器之间复制文件,使用 docker cp 命令。

# 从宿主机复制到容器内
docker cp <宿主机路径> <container-id>:<容器内路径>

# 例:将本地 nginx.conf 复制到容器
docker cp ./nginx.conf my-nginx:/etc/nginx/nginx.conf

# 从容器复制到宿主机
docker cp <container-id>:<容器内路径> <宿主机路径>

# 例:将容器日志复制到本地
docker cp my-nginx:/var/log/nginx/access.log ./
1
2
3
4
5
6
7
8
9
10
11

该操作对已停止的容器同样有效,不需要启动容器。

# 提交容器为镜像

如果在容器中做了一些改动(比如安装了某些工具),可以通过 docker commit 将当前容器的状态保存为一个新的镜像。

docker commit [选项] <container-id> <新镜像名>[:tag]
1

常用选项:

  • -a 指定作者
  • -m 提交说明
  • -p 在提交时暂停容器

例:

docker commit -a "西瓜猿" -m "安装了 vim 和 curl" my-container my-image:v1
1

注意: docker commit 生成的镜像属于"黑盒",缺乏可追溯性,实际项目中更推荐使用 Dockerfile 来构建镜像。commit 一般只用于快速保存调试状态。

# 重命名容器

docker rename <old-name> <new-name>
1

# 删除容器

可以使用 docker container rm 来删除一个处于终止状态的容器。例如

docker container rm trusting_newton
trusting_newton
1
2

如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。

# 清理所有处于终止状态的容器

docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。

docker container prune
1

# 导出和导入容器

前面介绍过 docker save/docker load 用于导出导入镜像,与之对应地,docker export/docker import 用于导出导入容器(本质是容器文件系统的快照)。

# 导出容器

# 将容器的文件系统导出为 tar 包
docker export -o <文件名.tar> <container-id | container-name>

# 例:
docker export -o my-container.tar my-nginx

# 也可以使用重定向
docker export my-nginx > my-container.tar
1
2
3
4
5
6
7
8

# 导入容器快照为镜像

# 从 tar 包导入为镜像
docker import <文件名.tar> <新镜像名>[:tag]

# 例:
docker import my-container.tar my-nginx:snapshot

# 从 URL 导入
docker import http://example.com/container.tar my-nginx:snapshot
1
2
3
4
5
6
7
8

export/importsave/load 的区别再次强调:

  • save/load 保留镜像的完整分层结构和历史记录,适合备份镜像。
  • export/import 只是文件系统的快照,会丢失所有历史层信息,导入后是一个新的单层镜像。适合"打包当前容器状态"的场景。