Docker 制作镜像Dockerfile和commit操作

 更新时间:2020-11-19 17:00:40   作者:佚名   我要评论(0)

构建镜像
构建镜像主要有两种方式:
使用docker commit命令从运行中的容器提交为镜像;
使用docker build命令从 Dockerfile 构建镜像。
首先介绍下如何从运行中的容

构建镜像

构建镜像主要有两种方式:

使用docker commit命令从运行中的容器提交为镜像;

使用docker build命令从 Dockerfile 构建镜像。

首先介绍下如何从运行中的容器提交为镜像。我依旧使用 busybox 镜像举例,使用以下命令创建一个名为 busybox 的容器并进入 busybox 容器。

$ docker run --rm --name=busybox -it busybox sh

执行完上面的命令后,当前窗口会启动一个 busybox 容器并且进入容器中。在容器中,执行以下命令创建一个文件并写入内容:

/ # touch hello.txt && echo "I love Docker. " > hello.txt

此时在容器的根目录下,已经创建了一个 hello.txt 文件,并写入了 "I love Docker. "。

下面,我们新打开另一个命令行窗口,运行以下命令提交镜像:

$ docker commit busybox busybox:hello

sha256:cbc6406aaef080d1dd3087d4ea1e6c6c9915ee0ee0f5dd9e0a90b03e2215e81c

然后使用上面讲到的docker image ls命令查看镜像:

$ docker image ls busybox
REPOSITORY     TAG         IMAGE ID      CREATED       SIZE
busybox       hello        cbc6406aaef0    2 minutes ago    1.22MB
busybox       latest       018c9d7b792b    4 weeks ago     1.22MB

此时我们可以看到主机上新生成了 busybox:hello 这个镜像。

通过对比显然使用Dockerfile的docker build更好。docker commit的缺点如下:

需要在容器内操作麻烦,效率低。

这一点也是最重要的,其他人或者过一段时间后自己也不知道这个镜像是怎么做出来的,但是使用Dockerfile构建的镜像,我们看到是执行了apt-get install命令。

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

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

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

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

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 命令设置工作目录。

看了这么多指令,感觉有点懵?别担心,我通过一个实例让你来熟悉它们。这是一个 Dockerfile:

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 文件到镜像内;

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

这里我的 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 夹下只存放了增量数据,如图 2 所示。

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

总结一下, Docker 镜像是静态的分层管理的文件组合,镜像底层的实现依赖于联合文件系统(UnionFS)。充分掌握镜像的原理,可以帮助我们在生产实践中构建出最优的镜像,同时也可以帮助我们更好地理解容器和镜像的关系。

总结

到此,相信你已经对 Docker 镜像这一核心概念有了较深的了解,并熟悉了 Docker 镜像的常用操作(拉取、查看、“重命名”、删除和构建自定义镜像)及底层实现原理。

镜像操作命令:

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

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

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

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

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

镜像的实现原理:

镜像是由一系列的镜像层(layer )组成,每一层代表了镜像构建过程中的一次提交,当我们需要修改镜像内的某个文件时,只需要在当前镜像层的基础上新建一个镜像层,并且只存放修改过的文件内容。分层结构使得镜像间共享镜像层变得非常简单和方便。

以上这篇Docker 制作镜像Dockerfile和commit操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
  • Docker Gitlab+Jenkins+Harbor构建持久化平台操作
  • Docker 容器监控原理及 cAdvisor的安装与使用说明
  • Docker重命名镜像名称和TAG操作
  • docker 打包本地镜像,并到其他机器进行恢复操作
  • Docker镜像的制作,上传,拉取和部署操作(利用阿里云)
  • Docker配置阿里云镜像加速pull的实现
  • Docker 配置阿里云容器服务操作

相关文章

  • Docker 制作镜像Dockerfile和commit操作

    Docker 制作镜像Dockerfile和commit操作

    构建镜像 构建镜像主要有两种方式: 使用docker commit命令从运行中的容器提交为镜像; 使用docker build命令从 Dockerfile 构建镜像。 首先介绍下如何从运行中的容
    2020-11-19
  • python实现文件分片上传的接口自动化

    python实现文件分片上传的接口自动化

    背景和目的: 利用python request 编写脚本测试公司系统的文件上传接口。前端读取文件的大小然后文件分片传给后端,后端将每一片数据重新组合成文件。大概的过程
    2020-11-19
  • Python爬虫如何破解JS加密的Cookie

    Python爬虫如何破解JS加密的Cookie

      通过Fiddler抓包比较,基本可以确定是JavaScript生成加密Cookie导致原来的请求返回521。 发现问题:   打开Fiddler软件,用浏览器打开目标站点(http://www.ku
    2020-11-19
  • Python并发爬虫常用实现方法解析

    Python并发爬虫常用实现方法解析

    在进行单个爬虫抓取的时候,我们不可能按照一次抓取一个url的方式进行网页抓取,这样效率低,也浪费了cpu的资源。目前python上面进行并发抓取的实现方式主要有以下几
    2020-11-19
  • Python类class参数self原理解析

    Python类class参数self原理解析

    1.self只有在类的方法中才会有,其他函数或方法是不必带self的。 2.在调用时不必传入相应的参数。 3.在类的方法中(如__init__),第一参数永远是self,表示创
    2020-11-19
  • vue-drawer-layout实现手势滑出菜单栏

    vue-drawer-layout实现手势滑出菜单栏

    本文实例为大家分享了vue-drawer-layout实现手势滑出菜单栏的具体代码,供大家参考,具体内容如下 文档链接地址 安装 npm install vue-drawer-layout --save ma
    2020-11-19
  • JavaScript实现无限轮播效果

    JavaScript实现无限轮播效果

    本文实例为大家分享了JavaScript实现无限轮播效果的具体代码,供大家参考,具体内容如下 效果展示 原理 图片说明原理 轮播顺序:1–>2–>3–>4–>5–>1的副本–>2
    2020-11-19
  • php操作redis命令及代码实例大全

    php操作redis命令及代码实例大全

    官方PHP Redis扩展文件下载 https://pecl.php.net/package/redis 选择与你PHP版本相应的文件下载后直接放到PHP目录下的ext文件夹里,然后修改php.ini配置文件如下
    2020-11-19
  • 如何用SpringBoot 进行测试

    如何用SpringBoot 进行测试

    普通测试 假设要测试一个工具类 StringUtil(com.rxliuli.example.springboottest.util.StringUtil) /** * 用于测试的字符串工具类 * * @author rxliuli
    2020-11-19
  • Java彻底消灭if-else的8种方案

    Java彻底消灭if-else的8种方案

    优化方案 1:提前 return,去除不必要的 else 如果 if-else 代码块包含 return 语句,可以考虑通过提前 return,把多余 else 干掉,使代码更加优雅。 优化前: if
    2020-11-19

最新评论