基于Dockerfile创建镜像 和 镜像的导入导出

目录

一、镜像的创建

1、基于已有镜像创建

2、基于 Dockefile 创建镜像

2.1、镜像加载原理介绍

2.2、指令详解

2.2.1、FROM

2.2.2、RUN

2.2.3、CMD

2.2.4、ENTRYPOINT

扫描二维码关注公众号,回复: 16021905 查看本文章

2.2.5、ENV

2.2.6 、ARG

2.2.7、LABEL

2.2.8、VOLUME

2.2.9、EXPOSE

2.2.10、WORKDIR

2.2.11、USER

2.2.12、HEALTHCHECK

2.2.13、ONBUILD

2.2.14、ADD

2.2.15、COPY

2.2.17、ARG DEBIAN_FRONTEND=noninteractive作用说明

二、导入导出镜像、导入导出容器

1、导出镜像(docker save)与导入镜像(docker load)

适用场景

导出容器(docker export)与导入容器(docker import):


一、镜像的创建

1、基于已有镜像创建

基于已有容器构建镜像主要是通过docker commit命令来构建新的镜像。

dockercommit构建进行主要有三步:

  • 创建和运行容器
  • 修改容器
  • 将容器保存为新的镜像

比如在 ubuntu 镜像中安装vim编辑器并存为新的镜像

1、首先本地要有镜像或者需要从Docker Hub上下载所需的基础镜像:

docker pull ubuntu:18.04

2、创建并运行容器:

# 根据 unbuntu 镜像创建一个容器,容器名docker 默认给 
docker run -it ubuntu
# 根据 unbuntu 镜像创建一个容器,容器名为 test
docker run -it --name test ubuntu  

3、进入该容器,并且确认没有 vim 编辑器。

# 在 docker 容器中,有的需要先安装 pip 工具才能使用 pip 安装库
docker exec -it container_name /bin/bash    # 进入docker
apt-get update && apt-get install -y python3-pip  

# 安装 vim 工具
apt-get install vim   

4、使用commit, 将修改后的容器存为新的镜像

docker commit 容器id/容器名  新镜像名

然后就可以使用新的镜像进行容器的创建

2、基于 Dockefile 创建镜像

Pytorch Docker镜像构建教程(不同系统、CUDA、Python版本)

Pytorch Docker镜像构建教程(不同系统、CUDA、Python版本) - 知乎 (zhihu.com)

2.0、dockerfile 创建镜像命令

示例:
docker build -t nginx:test .  
 
#基于dockerfile文件构建镜像命令
完整的写法: docker build -f dockerfile -t nginx:new . 
docker build : 基于dockerfile 构建镜像
-f :指定dockerfile 文件(默认不写的话指的是当前目录)
-t :(tag) 打标签 ——》nginx:new 
.  :专业说法:指的是构建镜像时的上下文环境,简单理解:指的当前目录环境中的文件

2.1、镜像加载原理介绍

联合文件系统:

  • UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。AUFS、OverlayFS 及 Devicemapper 都是一种 UnionFS。
  •  Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
  •  特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
  •  我们下载的时候看到的一层层的就是联合文件系统。

镜像加载原理

  • Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是UnionFS。
  • bootfs主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统。
  • 在Docker镜像的最底层是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
  • rootfs,在bootfs之上。包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

 
我们可以理解成一开始内核里什么都没有,操作一个命令下载debian,
这时就会在内核上面加了一层基础镜像;再安装一个emacs,会在基础镜像上叠加一层image;
接着再安装一个apache,又会在images上面再叠加一层image。
最后它们看起来就像一个文件系统即容器的rootfs。在Docker的体系里把这些rootfs叫做Docker的镜像。
但是,此时的每一层rootfs都是read-only的,我们此时还不能对其进行操作。
当我们创建一个容器,也就是将Docker镜像进行实例化,系统会在一层或是多层read-only的rootfs之上分配一层空的read-write的rootfs。

Dockerfile 是什么

  1. Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
  2.  镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
  3. Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成 image 即可, 省去了敲命令的麻烦。
  4. 除了手动生成Docker镜像之外,可以使用Dockerfile自动生成镜像。Dockerfile是由多条的指令组成的文件,其中每条指令对应 Linux 中的一条命令,Docker 程序将读取Dockerfile 中的指令生成指定镜像。

驱动程序overlay2

Dockerfile结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#“号开头的注释。

Docker 镜像结构的分层

镜像不是一个单一的文件,而是有多层构成。
容器其实是在镜像的最上面加了一层读写层,在运行容器里做的任何文件改动,都会写到这个读写层。 如果删除了容器,也就删除了其最上面的读写层,文件改动也就丢失了。
Docker使用存储驱动管理镜像每层内容及可读写层的容器层。
 

  • Dockerfile中的每一个指令都会创建一个新的镜像层(是一个临时的容器,执行完成后将不再存在,再往后进行重新的创建于操作)
  • 镜像层将被缓存复用(后续的镜像曾将基于前面的每一层,每一层都会由下几层的缓存)
  • 当Dockerfile的指令被修改了,复制的文件变化了,或构建镜像时指定的变量不同了,那么对应的镜像层缓存就会失效(因为后续的操作必然更改前面的镜像层)
  • 某一层的镜像缓存失效了之后,它之后的镜像层就会失效(第一层不成功,那么第二层也会失效)
  • 容器的修改并不会影响镜像,如果在某一层中添加一个文件,在下一层中删除它,镜像中依然会包含该文件

2.2、指令详解

Dockerfile 指令 说明
FROM

指定基础镜像,用于后续的指令构建。

MAINTAINER 指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令)
LABEL 添加镜像的元数据,使用键值对的形式。
RUN 在构建过程中在镜像中执行命令。在所基于的镜像上执行命令,并提交到新的镜像中
CMD 指定容器创建时的默认命令。(可以被覆盖)
ENTRYPOINT 设置容器创建时的主要命令。(不可被覆盖)
EXPOSE 声明容器运行时监听的特定网络端口。
ENV 在容器内部设置环境变量。
ADD 将文件、目录或远程URL复制到镜像中。
COPY 将文件或目录复制到镜像中。
VOLUME 为容器创建挂载点或声明卷。
WORKDIR 设置后续指令的工作目录。
USER 指定后续指令的用户上下文。
ARG 定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。
ONBUILD 当该镜像被用作另一个构建过程的基础时,添加触发器。
STOPSIGNAL 设置发送给容器以退出的系统调用信号。
HEALTHCHECK 定义周期性检查容器健康状态的命令。
SHELL 覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。

2.2.1、FROM

指定新镜像所基于的镜像,第一条指令必须为FROM指令每创建一个镜像就需要一条FROM指令。且在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令。

语法格式如下:

FROM <image> 
FROM <image>:<tag> 

其中<tag>是可选项,如果没有选择,那么默认值为latest

如果不以任何镜像为基础,那么写法为:FROM scratch

但是ARG可以放在FROM之前,例如

ARG CODE_VERSION=latest
FROM base:${CODE_VERSION} 

2.2.2、RUN

用于执行后面跟着的命令行命令。有以下俩种格式:

# shell格式:就像在命令行中输入的Shell脚本命令一样。
RUN <command> 

# exec格式:就像是函数调用的格式。
RUN ["executable", "param1", "param2"] 
# 例如:
RUN ["./test.php", "dev", "offline"]  # 等价于 RUN ./test.php dev offline

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz

以上执行会创建 3 层镜像。可简化为以下格式:

FROM centos
RUN yum -y install wget \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && tar -xvf redis.tar.gz

如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

2.2.3、CMD

类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

  • CMD 在docker run 时运行, CMD指令用于指定一个容器启动时所运行的命令
  • RUN 是在 docker build 构建时要运行的命令

作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

2.2.4、ENTRYPOINT

ENTRYPOINT 指令用于设置在启动容器时始终运行的可执行文件。类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

格式:

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

Docker ENTRYPOINT 指令支持 shell 和 exec 两种模式的写法:

  • Exec 模式: ENTRYPOINT ["executable", "parameter1", "parameter2"]
  • Shell 模式: ENTRYPOINT command parameter1 parameter2

参考: 使用exec模式与shell模式,执行ENTRYPOINT和CMD的区别 - 知乎 (zhihu.com)

2.2.5、ENV

设置环境变量,会被后面的RUN使用。定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

格式:

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

2.2.6 、ARG

LABEL <key>=<value> <key>=<value> <key>=<value> ...

构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。

格式:

ARG <参数名>[=<默认值>]

2.2.7、LABEL

LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

比如我们可以添加镜像的作者:

LABEL org.opencontainers.image.authors="runoob"

2.2.8、VOLUME

定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

作用:

  • 避免重要的数据,因容器重启而丢失,这是非常致命的。
  • 避免容器不断变大。

格式:

VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

2.2.9、EXPOSE

指定新镜像加载到Docker时要开启的端口,仅仅只是声明监听的端口,在监听是可以指定是TCP还是UDP协议,默认值为TCP

作用:

  • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
  • 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

格式:

EXPOSE <端口号>

# 默认情况下一般如果我们未指定协议的话,那么都是使用TCP协议,
# 当然也可以指定具体的协议,也可以同时指定TCP和UDP协议。
EXPOSE 80/tcp 
EXPOSE 80/udp

2.2.10、WORKDIR

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

格式:

WORKDIR <工作目录路径>

2.2.11、USER

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

格式:

USER <用户名>[:<用户组>]

2.2.12、HEALTHCHECK

用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

格式:

HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

2.2.13、ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:

ONBUILD <其它指令>

2.2.14、ADD

ADD指令是指将宿主机的文件或目录复制到镜像文件系统中指定的路径,源文件复制到镜像中,源文件要与 Dockerfile 位于相同目录中,或者是一个 URL 。

注意:如果源文件是个归档文件(压缩文件),则docker会自动帮解压。但是URL下载和解压特性不能一起使用。任何压缩文件通过URL拷贝,都不会自动解压。

其语法格式有两种:

ADD <src>... <dest>

2.2.15、COPY

复制文件或者目录到容器里指定路径。COPY 只是复制,不会进行解压。COPY指令只能从执行docker build所在的主机上读取资源并复制到镜像中。而ADD指令还支持通过URL从远程服务器读取资源并复制到镜像中

2.2.17、ARG DEBIAN_FRONTEND=noninteractive作用说明

在Dockerfile中使用ARG指令定义变量并为其指定一个默认值。ARG指令用于在构建过程中传递变量的值。

对于DEBIAN_FRONTEND=noninteractive,它定义了一个名为DEBIAN_FRONTEND的变量,并将其默认值设置为noninteractive。在这个上下文中,noninteractive用于禁用任何交互式提示。

作用:

在这个Dockerfile中,设置DEBIAN_FRONTEND=noninteractive是为了避免在安装过程中出现交互式提示。
默认情况下会在终端上显示交互式提示,例如要求用户确认安装某个软件包、选择配置选项等。但在Docker容器中构建镜像时,没有终端可以显示这些提示,因此需要禁用交互提示。

通过将DEBIAN_FRONTEND设置为noninteractive,在安装过程中使用默认选项而不提示用户。
这样可以确保在构建Docker镜像时,整个过程是自动化的,不需要人工干预。

二、导入导出镜像、导入导出容器

通过导入和导出镜像文件的方式可以将镜像从一个Docker宿主机迁移到另一个Docker宿主机。首先,在源Docker宿主机上使用以下命令导出镜像文件:

1、导出镜像(docker save)与导入镜像(docker load)

这是一对操作,用于处理 Docker 镜像。这个操作会将所有的镜像层以及元数据打包到一个 tar 文件中。然后,你可以使用 docker load 命令将这个 tar 文件导入到任何 Docker 环境中。例如:

导出:docker save -o <保存路径>/myimage.tar myimage:latest
导入:docker load -i <路径>/myimage.tar

这种方式主要用于分享或迁移整个镜像,包括所有版本、标签和历史。

-o 参数表示输出的文件路径和名称,后面紧跟着要保存的镜像名称。例如,docker save -o /pathtosave/myimage.tar myimage:tag

-i 参数表示输入的文件路径和名称。例如,docker load -i /pathtoload/myimage.tar

适用场景

假设你在你的开发环境中创建了一个新的 Docker 镜像,这个镜像包含了你的应用和所有依赖项,你已经测试了这个镜像,并且打了一个标签,称其为 “myapp:1.0”。现在你想要将这个镜像移到生产环境。这个场景中,你应该使用 docker save 和 docker load 命令。具体操作如下:

在开发环境中,你运行 docker save -o myapp_1.0.tar myapp:1.0。这将创建一个名为 “myapp_1.0.tar” 的 tar 文件,其中包含了 “myapp:1.0” 镜像的所有层和元数据。
你可以将这个 tar 文件复制到你的生产环境,然后在那里运行 docker load -i myapp_1.0.tar。这将导入 “myapp:1.0” 镜像,你可以立即在生产环境中使用它。

导出容器(docker export)与导入容器(docker import):

这也是一对操作,用于处理 Docker 容器。docker export 命令可以将运行中的容器的文件系统导出为一个 tar 文件。然后,你可以使用 docker import 命令将这个 tar 文件作为一个新的镜像导入。例如:

导出:docker export <容器ID> > mycontainer.tar
导入:docker import mycontainer.tar 

这种方式主要用于分享或迁移容器的当前状态。这不包括容器的历史或元数据,如环境变量,所以它常常用于对容器进行快照。

docker export 命令后直接跟容器的 ID 或名称

docker import 的参数包括输入的文件路径和名称,以及新镜像的名称和标签。例如docker import /path/to/import/mycontainer.tar newimage:tag

总的来说,如果你想要保存整个镜像,包括它的所有历史和标签,那么你应该使用 docker save 和 docker load命令。而如果你只是想要保存一个容器的当前状态,那么你应该使用 docker export 和 docker import 命令。

猜你喜欢

转载自blog.csdn.net/ytusdc/article/details/131863463