theboyaply
theboyaply
发布于 2020-03-09 / 619 阅读
0
0

Docker镜像

Docker镜像

参考:

https://vuepress.mirror.docker-practice.com/image/

搜索仓库镜像

docker 支持使用关键字从 Docker Hub 查找镜像

docker search [options] item

OPTIONS说明:

  • --automated:只列出 automated build类型的镜像
  • --no-trunc:显示完整的镜像描述
  • -s:列出收藏数不小于指定值的镜像

例如查找所有镜像名包含 jdk,并且收藏数大于5的镜像:

docker search -s 5 jdk

docker_search_jdk

结果列说明:

  • NAME:镜像仓库源的名称
  • DESCRIPTION:镜像的描述
  • OFFICIAL:是否 docker 官方发布
  • stars:类似 Github 里面的 star
  • AUTOMATED: 自动构建

拉取镜像

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

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

其中的 [选项] 可通过 docker pull --help 查看。下面详细介绍 [选项]后面的镜像名称格式:

  • Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。
  • 仓库名:就是使用 docker search 搜索出来的镜像NAME。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。

比如我们使用以下命令拉取 nginx 镜像:

[root@localhost ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
68ced04f60ab: Pull complete 
28252775b295: Pull complete 
a616aa3b0bf2: Pull complete 
Digest: sha256:2539d4344dd18e1df02be842ffc435f8e1f699cfc55516e2cf2cb16b7a9aea0b
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

我们没有指定标签 tag ,默认拉取latest。没有指定用户名,默认拉取 library

同时可以看到,在拉取镜像的过程中,是一层一层拉取的,每一层都会给出对应的前12位ID,下载完成后会显示完整的 sha256 摘要。同一镜像的不同版本摘要是不同的。

查看镜像

查看本地有哪些镜像,可以使用 docker image lsdocker images 命令。

[root@localhost ~]# docker images 
REPOSITORY   TAG      IMAGE ID            CREATED         SIZE
nginx        latest   6678c7c2e56c        4 days ago      127MB

# --digests 可以将镜像摘要一起显示出来
docker images --digests

结果列说明:

  • REPOSITORY: 用户名/仓库名。默认的library不显示,因此我们只看见了 nginx
  • TAG:标签,相当于镜像的版本。默认为 latest
  • IMAGE ID:镜像ID,镜像的唯一标识。这里只显示前12位
  • CREATED:镜像创建时间
  • SIZE:镜像占用空间大小

如果镜像过多,我们还可以通过一些筛选方式来查看镜像。

# 根据仓库名列出镜像,tag可选
docker images [images-name]:[tag]

# 使用 --filter 或者 -f 筛选

# 筛选 nginx:latest 之前/后创建的镜像
docker images -f before=nginx:latest
docker images -f since=nginx:latest

# 如果创建镜像时定义了 LABEL,还可以通过 LABEL 筛选
docker images -f label=com.example.version=0.1

以特定格式显示镜像结果

# -q 可以只显示镜像的前12位ID,通常与 -f 配合使用删除指定镜像
docker images -q

# 仅显示ID和仓库名,去掉 table 不显示列名
docker images --format "table {{.ID}}: {{.Repository}}

镜像体积

这里的体积分为两部分:

  • 一个是镜像仓库的镜像体积拉取到本地的镜像体积

镜像仓库中的镜像大小,可能要小于我们拉取到本地之后的镜像大小。比如我们拉取的 nginx 镜像在 Docer Hub 上的大小仅为 40MB+,但是拉取到本地后为 127MB

这是因为 Docker Hub 中显示的体积是压缩后的体积。在镜像下载和上传过程中镜像是保持着压缩状态的,因此 Docker Hub 所显示的大小是网络传输中更关心的流量大小。而 docker image ls 显示的是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和,因为镜像到本地后,查看空间的时候,更关心的是本地磁盘空间占用的大小。

  • 一个是 本地镜像体积总和本地镜像实际占用硬盘大小

也就是 docker images 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。

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

我们可以通过 docker system df 来查看实际消耗的硬盘大小。

[root@localhost ~]# docker system df
TYPE            TOTAL     ACTIVE    SIZE       RECLAIMABLE
Images          1         0         126.8MB    126.8MB (100%)
Containers      0         0         0B         0B
Local Volumes   0         0         0B         0B
Build Cache     0         0         0B         0B

虚悬镜像

有些时候我们使用 docker images 查看镜像的时候,可能会出现镜像名称、标签等都为 <none> 的镜像。这种镜像我们称为 虚悬镜像

虚悬镜像 可能会来自下列情况,该镜像原来是有镜像名称、标签等值的,但是后来官方发布了新版本,我们重新 pull 相同 tag 的镜像时,这个镜像的名称就转移到了新镜像身上,因此原来的镜像就变为 <none>了。docker build 也同样可以导致这种现象。由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 <none> 的镜像。

使用以下命令可以专门查看虚悬镜像。

docker images -f dangling=true

因为虚悬镜像一般都是新版本发布后导致的,所以虚悬镜像可以弃之不用。使用以下命令删除虚悬镜像。

 docker image prsune

删除镜像

我们可以使用镜像的ID、名称以及摘要删除镜像。其语法为:

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

比如使用 ID 删除 nginx 镜像(如果存在使用当前镜像创建的容器,那么这个镜像不能删除,除非先删除容器)

[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              6678c7c2e56c        4 days ago          127MB
[root@localhost ~]# docker rmi 6678
Untagged: nginx:latest
Untagged: nginx@sha256:2539d4344dd18e1df02be842ffc435f8e1f699cfc55516e2cf2cb16b7a9aea0b
Deleted: sha256:6678c7c2e56c970388f8d5a398aa30f2ab60e85f20165e101053c3d3a11e6663
Deleted: sha256:3105dd416ca73edaeedb5c15a853bc5aed51045a250cb544b0e936c94932dfcf
Deleted: sha256:1541955a517830d061b79f2b52b1aed297d81c009ce7766a15527979b6e719c4
Deleted: sha256:f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da

使用 ID 删除镜像时,不需要输入完整的镜像 ID,只要能够区别其它镜像即可,一般输入前4位。

Untagged 和 Deleted

上面删除 nginx 时我们发现,有 UntaggedDeleted 两种标记。

我们需要了解到,一个镜像可以有多个标签,也就是版本。我们使用上面的删除命令时,删除的只是满足这个条件的标签而已,也就是Untagged,如果删除之后这个镜像没有其它标签的话,那么 Deleted 行为才会产生。

删除满足条件的多个镜像

查看镜像 时我们提到 docker images -q仅返回镜像的ID。那么我们可以结合 -q-f 来批量删除满足指定条件的镜像

# 删除所有 nginx 镜像
docker image rmi $(docker images -q nginx)

# 删除所有 nginx:latest 之前的镜像
docker image rmi $(docker images -q -f before=nginx:latest)

制作镜像

除了从官方仓库拉取镜像之外,我们还可以自定义镜像,自定义镜像必须以另一个镜像作为基础。下面介绍三种自定义镜像的方式。

  • 使用commit制作镜像:docker commit 仅在一些特殊的应用场合,比如被入侵后保存现场等
  • 使用Dockerfile制作镜像:一般自定义的镜像都是使用这种方式
  • 其他方式制作镜像:从 rootfs 压缩包导入、docker save 和 docker load

使用 commit 制作镜像

自定义镜像不建议使用 docker commit,因为每一次 commit 都不会影响之前的层级,仅仅只是修改了当前层而已。如果 commit 次数过多,会导致镜像过于臃肿。

自定义镜像建议使用 Dockerfile

从仓库拉取一个 nginx 镜像,使用下面的命令启动:

docker run --name nginx -d -p 80:80 nginx

这里简单介绍下 docker run 启动命令:

  • rum:表示启动一个镜像(创建一个容器)
  • --name nginx:指定容器名称
  • -d:后台启动
  • -p 80:80:将容器内部 80 端口映射到宿主机的 80 端口。格式:宿主机端口:容器端口
  • nginx:表示基于这个镜像创建容器
# 启动镜像,创建一个容器,输出的一串字符是容器的ID
[root@localhost ~]# docker run --name nginx -d -p 80:80 nginx
cd584a9352cf06db3ebc3f2e3e17b13dfeab3bed20a6a7fc9a5e5fee27a95d80

# 查看创建的容器
[root@localhost ~]# docker ps -a

接下来我们可以使用宿主机IP+80端口访问 nginx 了。

docker_nginx

现在我们来修改这个主页文字。

使用 docker exec 命令表示在运行的容器中执行命令,-it 表示分配一个持续连接的伪终端, nginx 表示需要进入的容器,/bin/bash 表示分配的终端类型

# 进入容器终端
[root@localhost ~]# docker exec -it nginx /bin/bash

# 修改 nginx 主页文字
root@cd584a9352cf:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

# 退出容器
root@cd584a9352cf:/# exit
exit

我们再次访问,发现页面已经改变了

docker_nginx_hello

可以使用 docker diff 查看具体的改动。

我们已经改变了 nginx 容器的内容,现在我们希望将其保存下来。

要知道,当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个 docker commit 命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。

docker commit 格式为:

docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

我们使用以下命令保存镜像:

[root@localhost ~]# docker commit \
>     --author "Tom" \
>     --message "修改了默认网页" \
>     nginx \
>     nginx:v1.0
sha256:c1eb7d0150201f80cdacf320f9b5969b32e04c26a1b6a14df8d31060ebdb699f

其中 --author 表示本次提交人名称,--message 表示本次提交备注。

可以在镜像列表看见新的镜像:

[root@localhost ~]# docker images
REPOSITORY          TAG      IMAGE ID            CREATED              SIZE
nginx               v1.0     c1eb7d015020        About a minute ago   127MB
nginx               latest   6678c7c2e56c        4 days ago           127MB

可以使用命令 docker history nginx:v1.0 查看修改内容。

下面我们启动 nginx:v1.0

docker run --name nginx-v1 -d -p 81:80 nginx:v1.0

访问 81 端口发现确实已经是改变后的页面。

使用 Dockerfile 制作镜像

Dockerfile 请阅读这篇文章。点我直达

其它方式制作镜像

从 rootfs 压缩包导入

docker import [选项] <文件>|<URL>|- [<仓库名>[:<标签>]]

压缩包可以是本地文件、远程 Web 文件,甚至是从标准输入中得到。压缩包将会在镜像 / 目录展开,并直接作为镜像第一层提交。

docker save 和 docker load

使用docker save 命令将镜像保存为归档文件,其语法格式为为:

docker save [OPTIONS] IMAGE [IMAGE...]

OPTIONS 说明:

  • **-o:**输出到的文件。

比如我们将 nginx:latest 保存为归档文件:

[root@localhost ~]# ls
anaconda-ks.cfg
[root@localhost ~]# docker save -o nginx.tar nginx:latest
[root@localhost ~]# ls
anaconda-ks.cfg  nginx.tar
[root@localhost ~]# file nginx.tar 
nginx.tar: POSIX tar archive

使用 docker load 将归档文件加载为 docker 镜像,其语法格式为:

docker load [OPTIONS]

OPTIONS 说明:

  • --input , -i : 指定导入的文件,代替 STDIN。
  • --quiet , -q : 精简输出信息。

比如将 nginx.tar 加载到 docker 镜像中:

docker load -i nginx.tar

如果我们结合这两个命令以及 ssh 甚至 pv 的话,利用 Linux 强大的管道,我们可以写一个命令完成从一个机器将镜像迁移到另一个机器,并且带进度条的功能:

docker save <镜像名> | bzip2 | pv | ssh <用户名>@<主机名> 'cat | docker load'

-- end --


评论