Docker镜像详解 【Docker系列 (3)】

镜像 镜像操作 镜像的操作可分为: 拉取镜像,使用docker pull命令拉取远程仓库的镜像到本地 ; 重命名镜像,使用docker tag命令“重命名”镜像 ; 查看镜像,使用docker image ls或docker images命令查看本地已经存在的镜像 ; 删除镜像,使用docker r

镜像

镜像操作

镜像的操作可分为:

  • 拉取镜像,使用docker pull命令拉取远程仓库的镜像到本地 ;

  • 重命名镜像,使用docker tag命令“重命名”镜像 ;

  • 查看镜像,使用docker image lsdocker images命令查看本地已经存在的镜像 ;

  • 删除镜像,使用docker rmi命令删除无用镜像 ;

  • 构建镜像,构建镜像有两种方式。第一种方式是使用docker build命令基于 Dockerfile 构建镜像,也是我比较推荐的镜像构建方式;第二种方式是使用docker commit命令基于已经运行的容器提交为镜像。

最重要也是最常用的镜像构建方式:Dockerfile。Dockerfile 是一个包含了用户所有构建命令的文本。通过docker build命令可以从 Dockerfile 生成镜像。

使用 Dockerfile 构建镜像具有以下特性:

  • Dockerfile 的每一行命令都会生成一个独立的镜像层,并且拥有唯一的 ID;

  • Dockerfile 的命令是完全透明的,通过查看 Dockerfile 的内容,就可以知道镜像是如何一步步构建的;

  • Dockerfile 是纯文本的,方便跟随代码一起存放在代码仓库并做版本管理。

Dockerfile 指令

指令简介

FROM

Dockerfile 除了注释第一行必须是 FROM ,FROM 后面跟镜像名称,代表我们要基于哪个基础镜像构建我们的容器。

RUN

RUN 后面跟一个具体的命令,类似于 Linux 命令行执行命令。

ADD

拷贝本机文件或者远程文件到镜像内

COPY

拷贝本机文件到镜像内

USER

指定容器启动的用户

ENTRYPOINT

容器的启动命令

CMD

CMD 为 ENTRYPOINT 指令提供默认参数,也可以单独使用 CMD 指定容器启动参数

ENV

指定容器运行时的环境变量,格式为 key=value

ARG

定义外部变量,构建镜像时可以使用 build-arg = 的格式传递参数用于构建

EXPOSE

指定容器监听的端口,格式为 [port]/tcp 或者 [port]/udp

WORKDIR

为 Dockerfile 中跟在其后的所有 RUN、CMD、ENTRYPOINT、COPY 和 ADD 命令设置工作目录。

举例:

FROM centos:7
COPY nginx.repo /etc/yum.repos.d/nginx.repo
RUN yum install -y nginx
EXPOSE 80
ENV HOST=mynginx
CMD ["nginx","-g","daemon off;"]
  • 第一行表示我要基于 centos:7 这个镜像来构建自定义镜像。这里需要注意,每个 Dockerfile 的第一行除了注释都必须以 FROM 开头。

  • 第二行表示拷贝本地文件 nginx.repo 文件到容器内的 /etc/yum.repos.d 目录下。这里拷贝 nginx.repo 文件是为了添加 nginx 的安装源。

  • 第三行表示在容器内运行yum install -y nginx命令,安装 nginx 服务到容器内,执行完第三行命令,容器内的 nginx 已经安装完成。

  • 第四行声明容器内业务(nginx)使用 80 端口对外提供服务。

  • 第五行定义容器启动时的环境变量 HOST=mynginx,容器启动后可以获取到环境变量 HOST 的值为 mynginx。

  • 第六行定义容器的启动命令,命令格式为 json 数组。这里设置了容器的启动命令为 nginx ,并且添加了 nginx 的启动参数 -g ‘daemon off;’ ,使得 nginx 以前台的方式启动。

镜像的实现原理

其实 Docker 镜像是由一系列镜像层(layer)组成的,每一层代表了镜像构建过程中的一次提交。下面以一个镜像构建的 Dockerfile 来说明镜像是如何分层的。

FROM busybox
COPY test /tmp/test
RUN mkdir /tmp/testdir

上面的 Dockerfile 由三步组成:

第一行基于 busybox 创建一个镜像层;

第二行拷贝本机 test 文件到镜像内;

第三行在 /test 文件夹下创建一个目录 testdir。

为了验证镜像的存储结构,我们使用docker build命令在上面 Dockerfile 所在目录构建一个镜像:

$ docker build -t mybusybox .

这里我的 Docker 使用的是 overlay2 文件驱动,进入到/var/lib/docker/overlay2目录下使用tree .命令查看产生的镜像文件:

$ tree .
# 以下为 tree . 命令输出内容
|-- 3e89b959f921227acab94f5ab4524252ae0a829ff8a3687178e3aca56d605679
|   |-- diff  # 这一层为基础层,对应上述 Dockerfile 第一行,包含 busybox 镜像所有文件内容,例如 /etc,/bin,/var 等目录
... 此次省略部分原始镜像文件内容
|   `-- link 
|-- 6591d4e47eb2488e6297a0a07a2439f550cdb22845b6d2ddb1be2466ae7a9391
|   |-- diff   # 这一层对应上述 Dockerfile 第二行,拷贝 test 文件到 /tmp 文件夹下,因此 diff 文件夹下有了 /tmp/test 文件
|   |   `-- tmp
|   |       `-- test
|   |-- link
|   |-- lower
|   `-- work
|-- backingFsBlockDev
|-- bec6a018080f7b808565728dee8447b9e86b3093b16ad5e6a1ac3976528a8bb1
|   |-- diff  # 这一层对应上述 Dockerfile 第三行,在 /tmp 文件夹下创建 testdir 文件夹,因此 diff 文件夹下有了 /tmp/testdir 文件夹
|   |   `-- tmp
|   |       `-- testdir
|   |-- link
|   |-- lower
|   `-- work
...

通过上面的目录结构可以看到,Dockerfile 的每一行命令,都生成了一个镜像层,每一层的 diff 夹下只存放了增量数据

分层的结构使得 Docker 镜像非常轻量,每一层根据镜像的内容都有一个唯一的 ID 值,当不同的镜像之间有相同的镜像层时,便可以实现不同的镜像之间共享镜像层的效果。

LICENSED UNDER CC BY-NC-SA 4.0
Comment