六、dockerfile的使用及讲解

目录

 

一、Dockerfile的基本知识

1、什么是 Dockerfile?

2、指令语句

3、什么是上下文路径?

4、使用 Dockerfile 创建镜像的步骤

二、Dockerfile - 配置指令

1、FROM指令

2、ARG指令

3、LABEL指令

4、EXPOSE指令

5、ENV 指令

6、VOLUME指令

7、WORKDIR指令

8、USER指令

9、ENTRYPOINT指令

10、ONBUILD指令

11、STOPSIGNAL指令 - 不常用

12、HEALTHCHECK指令

13、SHELL指令 - 不常用

三、Dockerfile - 操作指令

​1、RUN 运行指定命令。

2、CMD 容器启动命令

3、COPY 复制指令

4、ADD 更高级的复制文件

四、docker  build 命令

1、使用 PATH 构建镜像。

1. 使用 上下文路径 构建镜像。

2. 使用 非上下文路径下的Dockerfile 构建镜像(不推荐)

2、支持从 URL 构建

3、用给定的 tar 压缩包构建

4、从标准输入中读取 Dockerfile 进行构建:

5、使用 .dockerignore文件

五、Docker多阶段构建入门(multi-stage builds)


一、Dockerfile的基本知识


1、什么是 Dockerfile?

Dockerfile 是一个用来构建自定义镜像的文本文件,它的文本内容由一行行指令语句组成,并且支持已 # 开头的注释行。

当命令较长时可以使用 \(反斜杠)符号来换行,使用 &&符号连接命令。

2、指令语句

指令语句可以大致分为两种:配置指令和操作指令

指令不区分大小写。但是,使用中我们约定大写,以便更轻松地将它们与参数区分开。

这些指令基本上都可以在 docker run命令中使用用相关参数来覆盖掉 Dockerfile相关的值,docker run 的参数优先级高。

指令语句的基础知识:

  • 每条保留字指令都必须是大写字母并且后面要跟随至少一个参数
  • 指令按照从上到下,顺序执行
  • # 表示注释
  • 每条指令的执行都会创建一个新的镜像层,注意:过多无意义的层,会造成镜像膨胀过大。
     

3、什么是上下文路径?

上下文路径:指 docker 在构建镜像时,如果需要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将该路径下的所有内容打包。

解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。

如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。

注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

 

4、使用 Dockerfile 创建镜像的步骤

使用起来很简单,关键指令 + 参数。灵活使用就得熟悉各种指令的含义和多练理解。大致流程如下:

1. 新建一个空目录作为上下文目录,(如:/root/Dockerfiletest)。

2. 在上下文目录中,新建一个名为 Dockerfile文件,并编写指令内容,一般我们默认把 Dockerfile文件放到上下文目录中。


[root@centos7 ~]# mkdir /root/Dockerfiletest
[root@centos7 ~]# cd /root/Dockerfiletest
[root@centos7 Dockerfiletest]# vim Dockerfile
[root@centos7 Dockerfiletest]# cat Dockerfile 
# 基础镜像
FROM centos:7
# 创建数据卷
VOLUME ["vdata"]
# 镜像被docker run命令创建并启动容器后执行的命令

 使用默认的Dockerfile文件文件名为Dockerfile,以及会将其置于镜像构建上下文目录中。

3. 使用 docker build命令构建/创建新镜像放到本地镜像仓库

[root@centos7 Dockerfiletest]# docker build -t build_image:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM centos:7
 ---> 7e6257c9f8d8
Step 2/3 : VOLUME ["vdata"]
 ---> Running in a3e2e87151f9
Removing intermediate container a3e2e87151f9
 ---> abc8515e4b91
Step 3/3 : CMD ["/bin/bash"]
 ---> Running in b4a931b41f0b
Removing intermediate container b4a931b41f0b
 ---> 1f2cfb33aaed
Successfully built 1f2cfb33aaed
Successfully tagged build_image:1.0
[root@centos7 Dockerfiletest]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
build_image         1.0                 1f2cfb33aaed        About a minute ago   203MB

-t 选项:表示给最终生成的镜像起个名称,“ name:tag”格式的标签

后面那个 . 点儿,表示将当前目录的上下文路径中使用Dockerfile构建,也可使用 -f /root/Dockerfiletest/Dockerfile 来指定

4. 使用 Dockerfile文件新建的镜像来创建并启动容器,run正常ok。

[root@centos7 Dockerfiletest]# docker run -it build_image:1.0 
[root@962e7ea2ad26 /]# ls
anaconda-post.log  dev  home  lib64  mnt  proc  run   srv  tmp  var
bin                etc  lib   media  opt  root  sbin  sys  usr  vdata

二、Dockerfile - 配置指令


具体指令查看官方文档:https://docs.docker.com/engine/reference/builder/#usage

1、FROM指令

FROM指令:指定所创建镜像的基础镜像。

基本语法:

FROM  <image> [AS <name>]

FROM  <image>[:<tag>] [AS <name>]

FROM  <image>[@<digest>] [AS <name>]

其中:

<tag>和<digest> 是可选项,如果没有选择,那么默认值为 latest。
AS <name> 可选的名称。该名称可以在多阶段构建FROM时,COPY --from=<name>说明中使用,以引用此阶段中构建的映像。

一般情况下,Dockerfile文件中的第一条指令就是FROM指令。同时意味着接下来所写的指令将作为镜像的第一层开始。

在 Docker Store 上有非常多的高质量的官方镜像,都可以直接拿来作为我们创建的镜像的基础镜像,服务镜像,如 nginx、redis、mongo、mysql、httpd、php、tomcat 等;方便开发、构建、运行各种编程语言的镜像,如 node、openjdk、python、ruby、golang 等。基础的操作系统镜像,如 ubuntu、debian、centos、fedora、alpine 等等。

Docker 还存在一个特殊的镜像,名为 scratch 空白的镜像。这个镜像是虚拟的概念,并不实际存在。

如果你以 scratch 为基础镜像的话,表示你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。不以任何系统为基础,直接将可执行文件(所需的一切库都已经在可执行文件里)复制进镜像的做法并不罕见,比如centos,ubuntu等等。可以让镜像体积更加小巧。

2、ARG指令

ARG指令:定义创建镜像过程中使用的环境变量。

基本语法:ARG <name> [=<default value>] 。

在执行docker build命令时, 可以通过 --build-arg <参数名>=<值>来覆盖Dockerfile中定义的变量值,Dockerfile 文件中 ${变量名}来取值。

ARG 设置的环境变量仅对 Dockerfile 内有效,docker build构建成功后,构建好的镜像内不存在此环境变量。


[root@centos7 Dockerfiletest]# cat Dockerfile
ARG version=7
# 基础镜像
FROM centos:${version}
# 创建数据卷
VOLUME ["vdata1","vdata2"]
# 镜像被docker run命令创建并启动容器后执行的命令
CMD ["/bin/bash"]
[root@centos7 Dockerfiletest]# docker build --build-arg version=6 -t build_arg:1.0 .
[root@877dc4bf58ae /]# docker run -it build_arg:1.0
[root@06dfd4359482 /]# cat /etc/issue
CentOS release 6.10 (Final)
Kernel \r on an \m

3、LABEL指令

LABEL指令:可以添加元数据标签信息到为生成的镜像。

基本语法:

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

LABEL是键值对。如果LABEL值中包含空格,请使用引号或反斜杠包裹。

一个镜像可以有多个标签。可以指定多行标签,也可以在一行上指定多个标签。

示例:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \


注意:

1、键值对中等号两边不能有空格
2、每条指令的执行都会创建一个新的镜像层,所以,最好把多个标签合并成一个LABEL指令。
 

4、EXPOSE指令

EXPOSE指令:指定当前容器对外暴露出的端口。

通知 Docker容器在运行时监听指定的网络端口。可以指定端口是侦听TCP还是UDP,如果未指定协议,则默认值为TCP。例如:EXPOSE 80/tcp 8008/udp 8888

基本语法:

EXPOSE <port> [<port>/<protocol>...]

注意:

EXPOSE指令仅仅只是声明端口,并不会自动完成端口映射。
如果要映射端口出来,在启动容器时可以使用 -P或 -p参数来映射一个或多个端口。
查看 tomcat,redis等官方容器的Dockerfile文件:

5、ENV 指令

ENV 指令:用来在构建镜像过程中设置环境变量。在镜像生成过程中会被后续RUN指令使用,并且通过镜像启动的容器中也会存在。

基本语法:

ENV <key> <value>

ENV <key>=<value> ...

ENV指令有两种形式:

  • ENV <key> <value>会将一个变量设置为一个值。第一个空格之后的整个字符串将被视为<value>,包括空格字符。该值将为其他环境变量解释,因此如果不对引号字符进行转义,则将其删除。
  • ENV <key>=<value> ...允许一次设置多个变量。引号和反斜杠可用于在值中包含空格。

在执行docker run 命令时, 可以通过 --env <key>=<value> 来覆盖Dockerfile中定义的变量值。

例如:

ENV myName="John Doe" myDog=Rex\ The\ Dog \   myCat=fluffy
 
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy


注意:当一条ENV指令中同时为多个环境变量赋值并且值也是从环境变量读取时,会为变量都赋值后再更新。

例如:下面的指令:

ENV key1=value2
ENV key1=value1  key2=${key1}

最终结果为key1=value1  key2=value2

实例:

[root@centos7 Dockerfiletest]# cat Dockerfile 
ARG version=7
# 基础镜像
FROM centos:${version}
# 添加多个标签信息
LABEL version="1.0" author="赵云"  date="2020-09-20" description="Message ..."
# 环境变量
ENV APP_VERSION=1.0.0 APP_HOME=/usr/local/app author="赵云"
# 创建数据卷
VOLUME ["vdata1","vdata2"]
# 镜像被docker run命令创建并启动容器后执行的命令
CMD ["/bin/bash"]
 
// 省略构建和启动
[root@2b4be9773226 /]# echo $APP_HOME
/usr/local/app

6、VOLUME指令

VOLUME指令:创建具有指定名称的匿名数据卷挂载点。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

基本语法:

VOLUME ["<mountpoint>",...]

该值可以是JSON数组,也可以是VOLUME ["/var/log/"]具有多个参数的纯字符串,例如:VOLUME /var/log或VOLUME /var/log /var/db。

例如:

RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
# 创建数据卷
VOLUME ["vdata1","/myvol"]

该Dockerfile生成一个镜像,该镜像会在docker run启动时创建一个新的挂载点/myvol并将该greeting文件复制到新创建的卷中。

7、WORKDIR指令

WORKDIR指令:指定工作目录。指定在创建容器后,终端默认登陆进来的工作目录,一个落脚点。

基本语法:WORKDIR <工作目录路径>。

可以在 docker run命令中用 -w参数覆盖掉WORKDIR指令的设置。

作用:

使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),后面的指令工作的当前目录就是这个指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
使用docker run 启动容器后,默认进入的目录,也会是这个指定的目录。
示例:

[root@centos7 Dockerfiletest]# cat Dockerfile 
ARG version=7
# 基础镜像
FROM centos:${version}
# 添加多个标签信息
LABEL version="1.0" author="赵云"  date="2020-09-20" description="Message ..."
# 环境变量
ENV APP_VERSION=1.0.0 APP_HOME=/usr/local/app author="赵云"
 
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
# 创建数据卷
VOLUME ["vdata1","/myvol"]
 
WORKDIR /mydir
RUN echo "hello dsfajflll" > hello.txt
# 镜像被docker run命令创建并启动容器后执行的命令
CMD ["/bin/bash"]
[root@centos7 Dockerfiletest]# docker run -it build_iamge:1.0   
[root@437b38a71a47 mydir]# ls
hello.txt
[root@437b38a71a47 mydir]# cat hello.txt 
hello dsfajflll
[root@437b38a71a47 mydir]# ls /  
anaconda-post.log  dev  home  lib64  mnt    myvol  proc  run   srv  tmp  var
bin                etc  lib   media  mydir  opt    root  sbin  sys  usr  vdata1
[root@437b3

执行命令 "hello dsfajflll" > hello.txt 时的当前目录就是 /mydir。

8、USER指令

USER指令:用于指定执行后续命令的用户和用户组。

基本语法:

USER <user>[:<group>]

USER <UID>[:<GID>]

USER指令设置运行映像时以及用于任何映像时使用的用户名(或UID)以及可选的用户组(或GID)这类命令的身份。

USER指令只是切换到后续命令执行的用户而已,这个用户必须是事先建存在,否则无法切换。

示例:推荐使用第三方的 gosu命令(需要下载 gosu)来切换用户。官方Redis镜像。

9、ENTRYPOINT指令

ENTRYPOINT指令:指定一个容器启动时要运行的命令。与 CMD 指令类似,目的都是在指定容器启动程序及参数。

基本语法:ENTRYPOINT有两种形式:

exec形式,这是优选的形式:ENTRYPOINT ["executable", "param1", "param2"]

shell形式:ENTRYPOINT command param1 param2

如果运行 docker run 时使用了 --entrypoint 选项,会覆盖Dockerfile中有ENTRYPOINT。

一般情况下ENTRYPOINT和CMD是结合起来用使用。当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令。

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

注意:和CMD一样,每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个起效。

例如:让镜像变成像命令一样使用

下面的Dockerfile可以写成这个命令:# docker run --entrypoint=/bin/ls centos:7 -l /tmp 

相当于在启动容器后执行了:/bin/ls -l /tmp

FROM  centos:7
ENTRYPOINT ["/bin/ls"]
CMD ["-l", "/tmp"]

例如:应用运行前的准备工作

启动容器就是启动主进程,但是,有时候启动主进程之前,需要做一些准备工作。

这些准备工作是和容器 CMD 无关的,无论 CMD 是什么,都需要事先进行预处理的工作。

这种情况下,可以写一个脚本,然后放入 ENTRYPOINT 中去执行,而这个脚本会将接到的参数(也就是 <CMD>)放在最后执行,CMD的参数是主进程。

查看 官方Reids镜像:

可以看到其中为了 redis 服务创建了 redis 用户,并在最后指定了 ENTRYPOINT 为 docker-entrypoint.sh 脚本。

假设启动容器的命令是:自己可以分析下那些准备工作

docker run --name myredis -idt  -v /root/redis/:/usr/local/etc/redis/ redis:6 redis-server /usr/local/etc/redis/redis.conf

10、ONBUILD指令

ONBUILD指令:用于延迟构建命令的执行。

基本语法:ONBUILD <其它指令>

ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在本次构建镜像的过程中不会被执行。只有当使用本次构建的镜像作为基础镜像,去构建下一个新的镜像的时才会被执行。

简单来说,Dockerfile 文件中,所有指令都是为了定制当前镜像而准备的(除了ONBUILD指令),只有 ONBUILD指令是为了帮助别人定制镜像而准备的。

示例:

ONBUILD RUN mkdir /dir222
 
[root@centos7 Dockerfiletest]# docker build -t build_iamge:1.0 .
[root@centos7 Dockerfiletest]# docker run -it build_iamge:1.0  
[root@904eb0379bfa mydir]# ls /
anaconda-post.log  dev  home  lib64  mnt    myvol  proc  run   srv  tmp  var
bin                etc  lib   media  mydir  opt    root  sbin  sys  usr  vdata1

dir222 目录是没有被创建的,然后使用  build_iamge:1.0作为基础镜像在构建镜像,在FROM指令执行之后,就会执行ONBUILD指令指定的命令。

[root@centos7 Dockerfiletest]# cat Dockerfile 
FROM build_iamge:1.0  
[root@centos7 Dockerfiletest]# docker build -t build_iamge:2.0 . 
[root@centos7 Dockerfiletest]# docker run -it build_iamge:2.0   
[root@de18dd0f9073 mydir]# ls /
anaconda-post.log  dev     etc   lib    media  mydir  opt   root  sbin  sys  usr  vdata1
bin                dir222  home  lib64  mnt    myvol  proc  run   srv   tmp  var

11、STOPSIGNAL指令 - 不常用

STOPSIGNAL指令:设置将被发送到容器退出的系统调用信号(默认信号值是SIGTERM)。该信号可以是与内核syscall表中的位置匹配的有效无符号数字(例如9),也可以是格式为SIGNAME的信号名称(例如:STOPSIGNAL SIGKILL)。

基本语法:STOPSIGNAL 信号

这个指令和执行 docker stop命令有点类似,执行docker stop命令时,docker首先会向容器内的当前主程序发送一个SIGTERM信号,用于容器内程序的退出。容器在收到SIGTERM后不会马上退出, 而 stop命令会在等待一段时间(默认是10s)后,再向容器发送SIGKILL信号,将容器杀死,变为退出状态。

 

12、HEALTHCHECK指令

HEALTHCHECK指令:健康检查,用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

基本语法:有两种形式:

HEALTHCHECK  [OPTIONS]  CMD <命令>:设置检查容器健康状况的命令

HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以禁用从基本映像继承的任何运行状况检查

支持下列选项:

--interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
--timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
--retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。
HEALTHCHECK指令用于告诉Docker如何测试容器以检查其是否仍在正常工作。

这样可以检测到诸如Web服务器陷入无限循环并且无法处理新连接的情况,即使服务器进程仍在运行。

指定容器的运行状况检查后,除了其正常状态外,它还具有运行状况。此状态最初为starting。只要运行状况检查通过,它将变为healthy。如果在一定数量的连续失败之后,它变为unhealthy。

注意

HEALTHCHECK指令只可以出现一次,如果写了多个,只有最后一个生效。

CMD后面的命令,格式分为两种: shell 格式 和 exec 格式。

命令退出的返回值(状态),决定了该次容器健康检查的状态。可能的值为:

  • 0:成功-容器健康且可以使用
  • 1:失败/不健康-容器无法正常工作
  • 2:保留-请勿使用此退出代码

示例:

[root@centos7 Dockerfiletest]# cat Dockerfile 
FROM nginx:1.19.0
RUN apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1
[root@centos7 Dockerfiletest]# docker build -t build_iamge:1.0 . 


设置每5秒检查一次,健康检查命令超过3秒没响应就视为失败,并使用 curl -fs http://localhost/ || exit 1 作为健康检查命令。

curl 命令的:-f参数将不输出错误信息。-s不输出内容。

&&:用来执行条件成立后执行的命令 

||:用来执行条件不成立后的执行命令

[root@centos7 Dockerfiletest]# docker run -d --name "nginxweb" -p 80:80 build_iamge:1.0   
2848e4bc93d57c3a8128ee9602f9bcfc3e36df27ba8748708f0eb6070f4f6d4e
[root@centos7 Dockerfiletest]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS                NAMES
2848e4bc93d5        build_iamge:1.0     "/docker-entrypoint.…"   4 seconds ago      Up 54 seconds (starting)   0.0.0.0:80->80/tcp   nginxweb
[root@centos7 Dockerfiletest]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS                NAMES
2848e4bc93d5        build_iamge:1.0     "/docker-entrypoint.…"   15 seconds ago      Up 54 seconds (healthy)   0.0.0.0:80->80/tcp   nginxweb


13、SHELL指令 - 不常用

SHELL指令:指定其他命令使用 shell形式时的默认 shell类型。

基本语法:SHELL ["executable", "parameters"]

注意:在Linux上,默认值是["/bin/sh", "-c"]。在Windows 上,默认值["cmd", "/S", "/C"]。

 

三、Dockerfile - 操作指令


1、RUN 运行指定命令。

RUN指令:容器构建时需要运行的命令,实际上运行命令并提交结果。

基本语法:有2种形式:

RUN <command>(shell形式,命令在shell中运行,默认情况,Linux在/bin/sh -c或Windows在cmd /S /C上运行)

RUN ["executable", "param1", "param2"]( exec 格式,必须使用双引号(“),不要使用单引号('))

指定使用其他shell终端类型时可以使用 shell形式实现。

每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像层。

当命令较长时可以使用 \(反斜杠)符号来换行,使用 &&符号连接命令

例如:RUN ["/bin/bash","-c","echo hello"] 

例如:

RUN  apt-get install -y libsnappy-dev zliblg-dev libbz2-dev \
    && rm -rf /var/cache/apt \
    && rm -rf /var/lib/apt/lists/*


2、CMD 容器启动命令

CMD指令:用于指定默认的容器主进程的启动的命令。

简单来理解CMD 相当于启动docker时候后面添加的参数。如:docker run -it centos:7 /bin/bash

基本语法:有三种形式:

CMD ["可执行文件", "参数1", "参数2"...](exec形式,这是首选形式)

CMD ["param1","param2" ...](作为ENTRYPOINT的默认参数)

CMD <命令>(shell形式)

CMD指令只可以出现一次,如果写了多个,只有最后一个生效。

shell格式和Exec格式区别:

  • Exec格式使用exec执行,不会启动shell环境。Exec格式指令会被解析一个JSON数组,因此必须使用双引号(“)不能使用单引号(')。
  • shell格式,默认将在shell 终端中运行命令,实际的命令会被包装为 sh -c 的参数的形式进行执行。

比如:CMD echo $HOME    在实际执行中,会将其变更为:CMD [ "sh", "-c", "echo $HOME" ]

RUN实际上运行命令并提交结果;CMD在生成时不执行任何操作,但是指定映像的预期命令。

3、COPY 复制指令

COPY指令:从上下文目录中复制文件或者目录到容器里的指定路径中。

基本语法:

COPY [--chown=<user>:<group>] <src>... <dest>

COPY [--chown=<user>:<group>] ["<src1>",... "<dest>"]

 

[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<src>:源文件或者源目录,可以指定多个资源,但是必须在构建上下文路径内。
可以包含通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/

COPY hom?.txt /mydir/

<dest>:容器内的指定路径,必须以斜杠结尾/。
可以是容器中内的绝对路径(推荐),也可以是相对于工作目录的相对路径(工作目录是用 WORKDIR 指令来指定)。路径不存在时会自动创建。

注意:

  • 源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。
  • 目录本身不被复制,仅其内容被复制。
[root@centos7 Dockerfiletest]# tree
.
├── abc.txt
├── dir1
│   └── dd.txt
└── Dockerfile


实例:复制文件

[root@centos7 Dockerfiletest]# docker build -t copyimage:1 .
[root@centos7 Dockerfiletest]# docker run -it copyimage:1
[root@657c464192cd /]# ls
anaconda-post.log  dev  home  lib64  mnt    opt   root  sbin  sys  usr
bin                etc  lib   media  mydir  proc  run   srv   tmp  var
[root@657c464192cd /]# cat /mydir/abc.txt 
hello

实例:复制目录 

[root@centos7 Dockerfiletest]# cat Dockerfile 
FROM centos:7
RUN mkdir /mydir
COPY dir1 /mydir
CMD ["/bin/bash"]
[root@centos7 Dockerfiletest]# docker build -t copyimage:1 .
[root@centos7 Dockerfiletest]# docker run -it copyimage:1   
[root@20dab72ef433 /]# ls
anaconda-post.log  dev  home  lib64  mnt    opt   root  sbin  sys  usr
bin                etc  lib   media  mydir  proc  run   srv   tmp  var
[root@20dab72ef433 /]# cat /mydir/dd.txt 
adfaf

可以直接一次复制:

[root@centos7 Dockerfiletest]# cat Dockerfile 
FROM centos:7
RUN mkdir /mydir
COPY ["abc.txt","dir1","/mydir/"]
CMD ["/bin/bash"]
 
[root@fd3273cd7528 /]# cd /mydir/
[root@fd3273cd7528 mydir]# ll
total 8
-rw-r--r-- 1 root root 6 Sep 20 06:36 abc.txt
-rw-r--r-- 1 root root 6 Sep 20 06:36 dd.txt


4、ADD 更高级的复制文件

ADD指令:ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。

基本语法:有两种形式:

ADD [--chown=<user>:<group>] <src>... <dest>

ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

 

[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<src>:源文件或者源目录,可以指定多个资源,但是必须在构建上下文路径内。
支持远程文件URL,Docker 引擎会试图去下载这个链接的文件放到 <dest> 中。

可以包含通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/

COPY hom?.txt /mydir/

<dest>:容器内的指定路径,必须以斜杠结尾/。
可以是容器中内的绝对路径(推荐),也可以是相对于工作目录的相对路径(工作目录是用 WORKDIR 指令来指定)。路径不存在时会自动创建。

注意:

  • 源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。
  • 目录本身不被复制,仅其内容被复制。

如果 <src>为远程文件 URL时,

下载后的文件权限自动设置为 600,可以增加一层 RUN 指令进行权限调整。

ADD指令不支持身份验证。如果你的URL文件受身份验证保护,可以使用 RUN wget, RUN curl或从容器中使用其他工具。

如果下载的是个压缩包,需要解压缩时,同样需要添加一层 RUN 指令进行解压缩。我们还不如直接使用 RUN 指令方便,然后使用 wget 或者 curl 工具下载,处理权限、解压缩、然后清理无用文件更合理。

因此,这个功能其实并不实用,而且不推荐使用。其他复制文件的情况时,推荐使用 COPY指令,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。

 

如果 <源路径> 为一个宿主机上的 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。在某些情况下,这个自动解压缩的功能非常有用,比如官方镜像 ubuntu centos等:

  

四、docker  build 命令


具体查看官方文档:https://docs.docker.com/engine/reference/commandline/build/

docker build 命令用于使用 Dockerfile 文件来创建镜像。如果创建镜像成功,会返回最终镜像的ID。

基本语法:docker build [OPTIONS] PATH | URL | -

选项:

名称,简写默认描述
--add-host 添加自定义主机到IP的映射(host:ip)
--build-arg 设置构建时变量
--cache-from 视为缓存源的图像
--cgroup-parent 容器的可选父cgroup
--compress 使用gzip压缩构建上下文
--cpu-period 限制CPU CFS(完全公平的调度程序)期限
--cpu-quota 限制CPU CFS(完全公平的调度程序)配额
--cpu-shares , -c CPU份额(相对重量)
--cpuset-cpus 允许执行的CPU(0-3,0,1)
--cpuset-mems 允许执行的MEM(0-3,0,1)
--disable-content-trusttrue跳过图像验证
--file , -f Dockerfile的名称(默认为“ PATH / Dockerfile”)
--force-rm 始终取出中间容器
--iidfile 将图像ID写入文件
--isolation 集装箱隔离技术
--label 设置图像的元数据
--memory , -m 内存限制
--memory-swap 交换限制等于内存加交换:“-1”以启用无限交换
--network 在构建过程中为RUN指令设置网络模式
--no-cache 构建映像时不要使用缓存
--output , -o 输出目的地(格式:type = local,dest = path)
--platform 如果服务器支持多平台,则设置平台
--progressauto设置进度输出的类型(自动,普通,tty)。使用普通显示容器输出
--pull 始终尝试提取图像的较新版本
--quiet , -q 禁止生成输出并成功打印图像ID
--rmtrue成功构建后删除中间容器
--secret 公开给构建的秘密文件(仅在启用BuildKit的情况下):id = mysecret,src = / local / secret
--security-opt 安全选项
--shm-size / dev / shm的大小
--squash 将新构建的层压缩为一个新层
--ssh SSH代理套接字或要公开给构建的密钥(仅在启用BuildKit的情况下)(格式:default |[=|[,]])
--stream 流附加到服务器以协商构建上下文
--tag , -t 名称以及“ name:tag”格式的标签(可选)
--target 设置要构建的目标构建阶段。
--ulimit Ulimit选项


docker build命令从Dockerfile和“上下文”中构建Docker映像。

构建的上下文是位于指定PATH或 URL。

URL参数可以引用三种资源:Git存储库,预打包的tarball上下文和纯文本文件。

1、使用 PATH 构建镜像。

-tag , -t        名称以及“ name:tag”格式的标签(可选)
--file , -f        Dockerfile的名称(默认为“ PATH 为上下文路径”)

1. 使用 上下文路径 构建镜像。

默认情况下, Dockerfile放在上下文目录里。指定PATH为 . 符号代表上下文路径。上面示例使用过了。

2. 使用 非上下文路径下的Dockerfile 构建镜像(不推荐)

[root@centos7 Dockerfiletest]# cp ./Dockerfile /root/abc/
[root@centos7 Dockerfiletest]# docker build -t copyimage:1 -f /root/abc/Dockerfile .

2、支持从 URL 构建

比如:可以直接从 Git repo 中构建,注意这个需要依赖git工具,确保Linux安装好git工具。

[root@centos7 git-2.9.5]# docker build https://github.com/twang2218/gitlab-ce-zh.git#:11.0


这行命令指定了构建所需的 Git repo,#后面不写,默认指定的 master 分支,构建目录为 /11.0/,

然后 Docker 就会自己去 git clone 这个项目、切换到指定分支、并进入到指定目录后开始构建。
 

3、用给定的 tar 压缩包构建

如果所给出的 URL 不是一个 Git仓库,而是个 tar 压缩包归档文件,那么 Docker 引擎会下载这个包,并将其用作构建上下文,自动解压缩构建。

# docker build http://server/context.tar.gz


4、从标准输入中读取 Dockerfile 进行构建:

docker build - < Dockerfile
或
cat Dockerfile | docker build -

如果标准输入传入的是文本文件,则将其视为 Dockerfile,并开始构建。

这种形式由于直接从标准输入中读取 Dockerfile 的内容,任何-f,--file 选项被忽略。在这种情况下,没有上下文。

因此不可以像其他方法那样可以将本地文件 COPY 进镜像之类的事情。

如果标准输入是读取上下文压缩包进行构建:

$ docker build - < context.tar.gz


如果发现标准输入的文件格式是 gzip、bzip2 以及 xz 的话,将会使其为上下文压缩包,直接将其展开并视为上下文,然后开始构建。

重点在1和2 两种形式,后面几个构建方式了解即可。

 

5、使用 .dockerignore文件

.dockerignore文件:排除从上下文中不需要上传到容器的文件或者目录。

使用 Dockerfile 构建镜像时最好是将 Dockerfile 放置在一个新建的空目录(上下文路径)下,然后将构建镜像所需要的文件添加到该目录中。

在上下文路径下新建一个 .dockerignore 文件来排除与其中的模式匹配的文件和目录。为了匹配,上下文的根被认为是工作目录和根目录。

示例:

[root@centos7 Dockerfiletest]# tree
.
├── aa.file
├── abc.txt
├── dir1
│   ├── a.file
│   └── dd.txt
└── Dockerfile
 
1 directory, 5 files
[root@centos7 Dockerfiletest]# cat .dockerignore 
/dir1*
!*.txt
[root@centos7 Dockerfiletest]# cat Dockerfile 
FROM centos:7
COPY [".","/mydir/"]
CMD ["/bin/bash"]
[root@centos7 Dockerfiletest]# docker build -t bulidimage1:1 .
[root@centos7 Dockerfiletest]# docker run -it bulidimage1:1
[root@ef823e49026f /]# ls /mydir/
Dockerfile  aa.file  abc.txt


五、Docker多阶段构建入门(multi-stage builds)


具体查看官方文档:https://docs.docker.com/develop/develop-images/multistage-build/

从17.05版本以后,新增了Dockerfile多阶段构建。通过多阶段构建,可以在一个Dockerfile 中使用多个 FROM 指令。

每个FROM指令可以使用不同的基础镜像,并且每个指令都开始构建的新阶段,多条 FROM 指令就是多阶段构建。

多个 FROM 指令并不是为了生成多根的层关系,而最后生成的镜像,仍然是以最后一条 FROM 指令生成的镜像为准。

 

如果把全部构建指令放入在一个 Dockerfile 中,包括项目及其依赖库的编译、测试、打包等流程,可能会带来的一些问题:

  • Dockerfile 特别长,可维护性降低
  • 镜像层次多,镜像体积较大,部署时间变长
  • 源代码存在泄露的风险

        多阶段构建可以很方便地将多个彼此依赖的项目通过一个Dockerfile就可轻松构建出期望的容器镜像,而不用担心镜像太大、源码泄露等风险。还可以的构建环境和运行环境进行分离,从而减少镜像层次多,镜像体积较大,部署时间变长,可维护性降低等问题。

示例:以安装nginx做演示

1、使用一个FROM,未优化

[root@centos7 Dockerfiletest]# mkdir /usr/local/nginx
[root@centos7 Dockerfiletest]# ls
Dockerfile  nginx-1.18.0.tar.gz
[root@centos7 Dockerfiletest]# cat Dockerfile 
FROM centos:7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
ADD nginx-1.18.0.tar.gz /mnt
RUN yum install -y gcc pcre-devel zlib-devel make
WORKDIR /mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx
RUN make
RUN make install
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@centos7 Dockerfiletest]# docker build -t buildnginx:v1 .
[root@centos7 Dockerfiletest]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
buildnginx          v1                  4225534fe92d        7 seconds ago       365MB


2、优化:清理中间缓存并尽量减少镜像层数

[root@centos7 Dockerfiletest]# cat Dockerfile 
FROM centos:7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN yum install -y gcc pcre-devel zlib-devel make \ 
        && yum clean all \
        &&  ./configure --prefix=/usr/local/nginx \
        && make \
        && make install
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@centos7 Dockerfiletest]# docker build -t buildnginx:v2 .
[root@centos7 Dockerfiletest]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
buildnginx          v2                  486ef7b26ac2        7 seconds ago      297MB


3、多条 FROM 指令:多阶段构建

[root@centos7 Dockerfiletest]# cat Dockerfile 
# nginx安装编译
FROM centos:7 as build_nginx
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN yum install -y gcc pcre-devel zlib-devel make \ 
        && yum clean all \
        &&  ./configure --prefix=/usr/local/nginx \
        && make \
        && make install \
        && rm -rf /mnt/nginx-1.18.0
 
# 创建镜像,将编译好的文件直接拿过来用
FROM centos:7   
# 把上面阶段的安装文件复制到本阶段目录中
COPY --from=build_nginx  /usr/local/nginx /usr/local/nginx
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@centos7 Dockerfiletest]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
buildnginx          v3                  049fa454801c        6 seconds ago       207MB
<none>              <none>              8451d367293d        7 seconds ago       285MB

可以发现,文件大小有了变化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值