容器镜像制作
一.容器镜像制作
自己制作容器镜像,主要有两种方法:
- 制作快照方式获得镜像(偶尔制作的镜像):在基础镜像上(比如Ubuntu),先登录镜像系统并安装容器引擎软件,然后整体制作快照。
- Dockerfile方式构建镜像(经常更新的镜像):将软件安装的流程写成Dockerfile,使用docker build构建成容器镜像。
方法一:制作快照方式获得镜像
如果后续镜像没有变化,可采用方法一制作镜像。

具体操作如下:
找一台主机,安装容器引擎软件。
跳转到的地方启动一个空白的基础容器,并进入容器。
例如:启动一个CentOS的容器。
docker run -it centos
执行安装任务。
yum install XXX
git clone
cd bwa;make
请预先安装好Git,并检查本机是否有ssh key设置。
输入exit退出容器。
制作快照。
docker commit -m “xx” -a “test” container-id test/image:tag
- -a:提交的镜像作者。
- container-id:步骤2中的容器id。可以使用docker ps -a查询得到容器id。
- -m:提交时的说明文字。
- test/image:tag:仓库名/镜像名:TAG名。
执行docker images可以查看到制作完成的容器镜像。
方法二:使用Dockerfile方式构建
如果后续镜像经常变更(例如某个软件更新版本),则需要采用方法二制作镜像。若仍采用方法一制作镜像,则每次变更都需要重新执行方法一的命令,操作过程比较繁琐,所以建议使用自动化制作镜像的方法。
其实就是将方法一制作镜像的方法,用文件方式写出来(文件名为Dockerfile)。然后执行:**docker build -t test/image:tag.**命令(命令中“.”表示Dockerfile文件的路径),自动完成镜像制作。

简单的Dockerfile示例:
如果依赖外部网络,请搭建网络环境,并保证网络可用。
1 | #Version 1.0.1 |
Dockerfile基本语法
FROM:
指定待扩展的父级镜像(基础镜像)。除注释之外,文件开头必须是一个FROM指令,后面的指令便在这个父级镜像的环境中运行,直到遇到下一个FROM指令。通过添加多个FROM命令,可以在同一个Dockerfile文件中创建多个镜像。
MAINTAINER:
声明创建镜像的作者信息:用户名、邮箱,非必须参数。
RUN:
修改镜像的命令,常用来安装库、安装程序以及配置程序。一条RUN指令执行完毕后,会在当前镜像上创建一个新的镜像层,接下来的指令会在新的镜像上继续执行。RUN 语句有两种形式:
- RUN yum update:在**/bin/sh**路径中执行的指令。
- RUN [“yum”, “update”]:直接使用系统调用exec来执行。
- RUN yum update && yum install nginx:使用&&符号将多条命令连接在同一条RUN语句中。
EXPOSE:
指明容器内进程对外开放的端口,多个端口之间使用空格隔开。
运行容器时,通过设置参数**-P**(大写)即可将EXPOSE里所指定的端口映射到主机上其他的随机端口,其他容器或主机可以通过映射后的端口与此容器通信。
您也可以通过设置参数**-p**(小写)将Dockerfile中EXPOSE中没有列出的端口设置成公开。
ADD:
向新镜像中添加文件,这个文件可以是一个主机文件,也可以是一个网络文件,也可以是一个文件夹。
- 第一个参数:源文件(夹)。
- 如果是相对路径,必须是相对于Dockerfile所在目录的相对路径。
- 如果是URL,会将文件先下载下来,然后再添加到镜像里。
- 第二个参数:目标路径。
- 如果源文件是主机上的zip或者tar形式的压缩文件,容器引擎会先解压缩,然后将文件添加到镜像的指定位置。
- 如果源文件是一个通过URL指定的网络压缩文件,则不会解压。
- 第一个参数:源文件(夹)。
VOLUME:
在镜像里创建一个指定路径(文件或文件夹)的挂载点,这个容器可以来自主机或者其它容器。多个容器可以通过同一个挂载点共享数据,即便其中一个容器已经停止,挂载点也仍可以访问。
WORKDIR:
为接下来执行的指令指定一个新的工作目录,这个目录可以是绝对目录,也可以是相对目录。根据需要,WORKDIR可以被多次指定。当启动一个容器时,最后一条WORKDIR指令所指的目录将作为容器运行的当前工作目录。
ENV:
设置容器运行的环境变量。在运行容器的时候,通过设置**-e**参数可以修改这个环境变量值,也可以添加新的环境变量。
例如:
docker run -e WEBAPP_PORT=8000 -e WEBAPP_HOST=www.example.com …
CMD:
用来设置启动容器时默认运行的命令。
ENTRYPOINT:
用来指定容器启动时的默认运行的命令。区别在于:运行容器时添加在镜像之后的参数,对ENTRYPOINT是拼接,CMD是覆盖。
若在Dockerfile中指定了容器启动时的默认运行命令为
ls -l
,则运行容器时默认启动命令为
ls -l
,例如:
- ENTRYPOINT [ “ls”, “-l”]:指定容器启动时的程序及参数为ls -l。
- docker run centos:当运行centos容器时,默认执行的命令是docker run centos ls -l
- docker run centos -a:当运行centos容器时拼接了-a参数,则默认运行的命令是docker run centos ls -l -a
若在Dockerfile中指定了容器启动时的默认运行命令为
–entrypoint
,则在运行容器时如果需要替换默认运行命令,可以通过添加
–entrypoint
参数来替换Dockerfile中的指定。例如:
docker run gutianlangyu/test –entrypoint echo “hello world”
USER:
为容器的运行及RUN、CMD、ENTRYPOINT等指令的运行指定用户或UID。
ONBUILD:
触发器指令。构建镜像时,容器引擎的镜像构建器会将所有的ONBUILD指令指定的命令保存到镜像的元数据中,这些命令在当前镜像的构建过程中并不会执行。只有新的镜像使用FROM指令指定父镜像为当前镜像时,才会触发执行。
使用FROM以这个Dockerfile构建出的镜像为父镜像,构建子镜像时:
ONBUILD ADD . /app/src:自动执行ADD . /app/src
二.docker镜像的导入和导出
1、docker镜像的导出 docker load|save
涉及到的命令:
1 | docker save [options] images [images...] |
我们使用上面的镜像来演示镜像的导出:
1 | docker save -o dockerdemo.tar dockerdemo |
如下图所示:

这里导出的时候指定了导出后文件的路径,如果不指定路径,默认是当前文件夹。
或者也可以使用下面的命令导出:
1 | docker save > dockerdemo.tar dockerdemo |
其中-o和>表示输出到文件,dockerdemo.tar为导出的目标文件,dockerdemo为源镜像名。
我们查看本地是否有了导出后的文件:
可以看到目录下面已经有了刚才导出的文件。
2、docker镜像的导入
我们首先使用XFtp把上面导出的镜像文件上传到阿里云服务器

然后进入文件所在的目录

我们查看阿里云服务器上面有哪些镜像:

从上图中看出:现在阿里云服务器上面没有任何的镜像。
涉及到的导入命令load
1 | docker load [options] |
接下来我们导入刚才上传的镜像。
1 | docker load -i dockerdemo.tar |
如下图所示:

或者也可以使用下面的命令
1 | docker load < dockerdemo.tar |
其中-i(i即imput)和<表示从文件输入。上面的两个命令都会成功导入镜像以及相关元数据,包括tag信息。
导入后查看镜像:

可以看到有了我们刚才导入的镜像。导入了镜像以后就可以根据镜像运行容器,最后运行应用程序。
三.docker容器的导入和导出
1、docker容器的导出 docker export|import
涉及到的命令export。
1 | docker export [options] container |
我们把上面生成的容器导出:
1 | docker export -o D:\containers\dockerdemocontainer.tar dockerdemo |
如下图所示:

其中,-o表示输出的文件,这里指定了输出的路径,如果没有指定路径,则默认生成到当前文件夹。dockerdemocontainer.tar为目标文件,dockerdemo为源容器名。
我们查看目录下面是否生成了导出的容器:

2、docker容器的导入
我们首先把导出的容器使用XFTP上传到阿里云服务器。

涉及到的导入命令import。
1 | docker import [options] file|URL|- [REPOSITORY[:TAG]] |
如下图所示
我们导入刚才上传的容器
1 | docker import dockerdemocontainer.tar dockerdemo:imp |
dockerdemocontainer.tar表示要导入的容器,dockerdemo:imp表示导入后的镜像名称,imp表示给导入的镜像打tag。
如下图所示

然后我们查看镜像:

可以看到这时有我们刚才导入的镜像了,导入的镜像tag为imp。 但因为通过export导出的容器文件,再使用import导入后,SIZE是要比源镜像小的。这是因为export导出的是容器,并没有源镜像的全部内容,比如会丢失构建历史记录和元数据信息等文件,相当于仅保存容器当时的快照状态,这会导致export导出的文件无法直接通过run命令运行,解决方法:
运行时通过-it选项,给容器分配一个伪终端。
1 | docker run -dit container sh |
推荐使用commit来保存容器,然后再使用save保存,能避免上述问题。
docker commit命令用于将容器的当前状态保存为一个新的 Docker 镜像。
docker commit命令通常用于创建镜像来保存容器的状态,以便在将来可以重用或分发该镜像。语法
1 docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]OPTIONS说明:
**-a :**提交的镜像作者。
**-c :**使用 Dockerfile 指令来创建镜像。
**-m :**提交时的说明文字。
**-p :**提交镜像前暂停容器(默认为 true)。
将容器保存为新镜像:
1 docker commit my_container my_new_image将名为 my_container 的容器保存为一个名为 my_new_image 的新镜像。
指定标签:
1 docker commit my_container my_new_image:latest将容器保存为带有 latest 标签的镜像。
添加作者信息和提交信息:
1 docker commit -a "John Doe" -m "Added new features" my_container my_new_image将容器保存为新镜像,并添加作者信息和提交信息。
在不暂停容器的情况下提交镜像:
1 docker commit --pause=false my_container my_new_image在不暂停容器的情况下,将其保存为新镜像。
实例
启动一个容器:
1 docker run -d -it --name my_container ubuntu bash进行一些更改:
1
2 docker exec my_container apt-get update
docker exec my_container apt-get install -y nginx提交容器为新镜像:
1 docker commit -a "Your Name" -m "Installed nginx" my_container my_new_image查看新镜像:
1 docker images常用场景
- 保存工作进度: 在开发或测试过程中,将容器的当前状态保存为镜像,以便稍后可以恢复。
- 创建基础镜像: 为特定应用程序或环境配置创建自定义基础镜像。
- 分发配置: 将特定配置或应用程序状态保存为镜像,以便分发给其他团队成员或在不同环境中使用。
docker commit命令是一个强大的工具,允许用户将容器的当前状态保存为新的 Docker 镜像。通过使用该命令,用户可以创建自定义镜像,以便在将来重用或分发。添加适当的作者和提交信息,有助于跟踪镜像的历史和变化。
四、总结
下面我们来总结一下镜像和容器导入导出的区别:
- 镜像导入是一个复制的过程,容器导入是将当前容器变成一个新的镜像。
- docker save命令保存的是镜像(image),docker export命令保存的是容器(container)。
- export命令导出的tar文件略小于save命令导出的。
- 因为export导出的是容器,export导出的文件在import导入时,无法保留镜像所有的历史(即每一层layer信息),不能进行回滚操作。而save是根据镜像来的,所以导入时可以完整保留下每一层layer信息。如下图所示:dockerdemo:latest是save导出load导入的,dockerdemo:imp是export导出import导入的。

- docker load不能对导入的镜像重命名,而docker import导入可以为镜像指定新名称。例如,上面导入的时候指定dockerdeom:imp。
对于是使用镜像导入导出还是使用容器导入导出该如何选择呢?有下面两点建议:
- 若是只想备份image,使用save和load。
- 若是在启动容器后,容器内容有变化,需要备份,则使用export和import。





