DockerFile使用与自定义镜像详解
【1】DockerFile是什么简单来说,Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。构建的三个步骤:编写Dockerfile文件docker build生成镜像docker run创建容器运行这里以我们熟悉的Centos为例 ,查看DockerFile大致文件结构FROM scratchADD CentOS-8-Container...
【1】DockerFile是什么
简单来说,Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
构建的三个步骤:
- 编写Dockerfile文件
- docker build 生成镜像
- docker run 创建容器运行
这里以我们熟悉的Centos为例 ,查看DockerFile大致文件结构
FROM scratch
ADD CentOS-8-Container-8.1.1911-20200113.3-layer.x86_64.tar.xz /
LABEL org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20200114" \
org.opencontainers.image.title="CentOS Base Image" \
org.opencontainers.image.vendor="CentOS" \
org.opencontainers.image.licenses="GPL-2.0-only" \
org.opencontainers.image.created="2020-01-14 00:00:00-08:00"
CMD ["/bin/bash"]
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
- Dockerfile是软件的原材料
- Docker镜像是软件的交付品
- Docker容器则可以认为是软件的运行态
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像。当运行 Docker镜像时,会创建Docker容器,容器是直接提供服务的。
【2】DockerFile构建过程解析
① Dockerfile内容基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层,并对镜像进行提交
② Docker执行Dockerfile的大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
③ DockerFile体系结构(保留字指令)
-
FROM:基础镜像,当前新镜像是基于哪个镜像的
-
MAINTAINER:镜像维护者的姓名和邮箱地址
-
RUN:容器构建时需要运行的命令
-
EXPOSE:当前容器对外暴露出的端口
-
WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
-
ENV:用来在构建镜像过程中设置环境变量
ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量,比如:WORKDIR $MY_PATH -
ADD:将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
-
COPY:类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中
<源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径>
位置。实例如COPY src dest 或者 COPY ["src", "dest"]
//src dest均为目录,表示把src下的文件拷贝到dest目录下
COPY server /usr/local/server/
//src为文件,dest为目录,表示把src这个文件拷贝到dest目录下
COPY run.sh /usr/local/sbin/ -
VOLUME:容器数据卷,用于数据保存和持久化工作
-
CMD:指定一个容器启动时要运行的命令。Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换。
CMD ["/usr/local/apache-tomcat-8.5.42/bin/catalina.sh",“run”]
CMD /usr/local/apache-tomcat-8.5.42/bin/startup.sh && tail -f /usr/local/apache-tomcat-8.5.42/logs/catalina.out
cmc命令的三种格式
CMD ["executable","param1","param2"] (exec格式)
CMD ["param1","param2"] (参数列表格式,作为ENTRYPOINT的默认参数)
CMD command param1 param2 (shell格式)
#实例
CMD echo "hello cmd!"
CMD ["/bin/bash", "-c", "echo 'hello cmd!'"]
- ENTRYPOINT :指定一个容器启动时要运行的命令。ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。
ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred)
ENTRYPOINT command param1 param2 (shell form)
- ONBUILD:子镜像继承父镜像,子镜像运行时,父镜像ONBUILD被触发。
BUILD | BOTH | RUN |
---|---|---|
FROM | WORKDIR | CMD |
MAINTAINER | USER | ENV |
COPY | EXPOSE | |
ADD | VOLUME | |
RUN | ENTRYPOINT | |
ONBUILD |
④ ONBUILD测试
两个DockerFile文件:DockerFile3与DockerFile4。
DockerFile3内容如下:
FROM centos
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "https://ip.cn" ]
ONBUILD RUN echo "now ,dockerfile3 is execute..."
生成镜像myip:
docker build -f DockerFile3 -t myip .
DockerFile4内容如下:
FROM myip
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "https://ip.cn" ]
生成镜像myip4:
【3】案例之自定义镜像mycentos
首先需要了解一个Base(scratch)镜像。Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。
① 编写DockerFile文件
目标: 默认centos镜像是不支持登陆后的默认路径、 vim编辑器、查看网络配置ifconfig的,这里自定义DockerFile使其支持。
在自定义目录下创建DockerFile文件,如/mydocker/
下,内容如下:
##使用的时候注意去掉注释 可以在vim窗口模式下使用dd命令快速删除一行
#继承自centos镜像
FROM centos
#作者与邮箱
MAINTAINER jane<jane@qq.com>
#设置环境
ENV MYPATH /usr/local
#容器启动后的落脚路径
WORKDIR $MYPATH
#运行安装命令
RUN yum -y install vim
RUN yum -y install net-tools
#暴露80端口
EXPOSE 80
CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
② 构建生成镜像
在当前路径下/mydocker/执行如下格式命令:
docker build -f DockFile路径 -t 新镜像名字:TAG .
会看到 docker build 命令最后有一个 .
,其表示当前目录。
实例如下:
docker build -f DockerFile -t mycentos:2.0 .
检测镜像:
[root@localhost mydocker]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
mycentos 2.0 df8160eb077f About a minute ago 314.3 MB
jane/centos latest b3a32e0a2930 14 hours ago 237.1 MB
badtomcat 1.0 4c900ee6d6e3 19 hours ago 528.7 MB
tomcat latest dd7dc39599b6 37 hours ago 528.6 MB
centos latest 495a24dc98e8 3 weeks ago 237.1 MB
hello-world latest 9f5834b25059 13 months ago 1.84 kB
③ 创建容器并运行
命令格式如下:
docker run -it 新镜像名字:TAG [/bin/bash]
实例如下:
docker run -it df8160eb077f /bin/bash
结果如下:
④ 列出镜像的变更历史
命令格式如下:
docker history 镜像ID
【4】CMD/ENTRYPOINT 镜像案例
二者相似之处都是都是指定一个容器启动时要运行的命令。
① CMD命令
The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable, or they can omit the executable, in which case you must specify an ENTRYPOINT instruction as well.
cmd主要用于提供给容器一个默认的可执行脚本命令。也就是容器启动以后,默认的执行的命令。也就是意味着如果docker run没有指定任何的执行命令或者dockerfile里面也没有entrypoint,那么,就会使用cmd指定的默认的执行命令执行。
三种格式
The CMD instruction has three forms:
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
shell格式
命令默认是在“/bin/sh -c”
下执行的。实例如下
FROM centos
CMD echo "I'm janus"
命令格式
FROM centos
CMD ["/bin/bash", "-c", "echo 'I'm janus'"]
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。另外,如果docker run后面跟了自定义命令,那么CMD 会被 docker run 之后的参数替换。
实例如下:
docker run -it -p 8888:8080 tomcat ls -l
那么DockerFile中的最后一个CMD会被ls -l
替换,如下图所示:
② ENTRYPOINT
An ENTRYPOINT allows you to configure a container that will run as an executable.
也就是说entrypoint才是正统地用于定义容器启动以后的执行体的,其实我们从名字也可以理解,这个是容器的“入口”。
docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合。
ENTRYPOINT has two forms:
ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred)
ENTRYPOINT command param1 param2 (shell form)
① 命令行格式
也就是带中括号的,和cmd的中括号形式是一致的,但是这里是在shell的环境下执行的,与cmd有区别。
- 如果run命令后面有东西,那么后面的全部都会作为entrypoint的参数。
- 如果run后面没有额外的东西,但是cmd有,那么cmd的全部内容会作为entrypoint的参数,这同时是cmd的第二种用法。
- 如果要在run里面覆盖,使用
--entrypoint
即可。
② shell格式
在这种模式下,任何run和cmd的参数都无法被传入到entrypoint里。官网推荐命令行格式。
FROM centos
CMD ["I'm janus"]
ENTRYPOINT echo
③ CMD测试步骤
##新增DockerFile文件
[root@localhost mydocker]# vim DockerFile2
##build创建镜像
[root@localhost mydocker]# docker build -f DockerFile2 -t myip .
Sending build context to Docker daemon 4.096 kB
Sending build context to Docker daemon
Step 0 : FROM centos
---> 495a24dc98e8
Step 1 : RUN yum install -y curl
---> Running in 4fd0ea665eaf
CentOS-8 - AppStream 704 kB/s | 6.4 MB 00:09
CentOS-8 - Base 410 kB/s | 5.0 MB 00:12
CentOS-8 - Extras 2.2 kB/s | 2.1 kB 00:00
Package curl-7.61.1-11.el8.x86_64 is already installed.
Dependencies resolved.
Nothing to do.
Complete!
---> 58218afb3e20
Removing intermediate container 4fd0ea665eaf
Step 2 : CMD curl -s http://ip.cn
---> Running in 6d14169fb841
---> af6a8441dcc9
Removing intermediate container 6d14169fb841
Successfully built af6a8441dcc9
[root@localhost mydocker]# docker run af6a8441dcc9
{"ip": "114.244.77.52", "country": "北京市", "city": "联通"}
DockerFile文件内容如下:
FROM centos
RUN yum install -y curl
CMD [ "curl", "-s", "https://ip.cn" ]
如果我们希望显示 HTTP 头信息,就需要加上 -i
参数,但是就会报错。
[root@localhost mydocker]# docker run c18008dfcc35 -i
Error response from daemon: Cannot start container 42d9aaf8ffabde5b000bea14673b4d2be86fa8c66c16d3feccece3dc4d2d2b59: [8] System error: exec: "-i": executable file not found in $PATH
我们可以看到可执行文件找不到的报错,executable file not found
。之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。
因此这里的 -i
替换了原来的 CMD,而不是添加在原来的 curl -s http://ip.cn
后面。而 -i
根本不是命令,所以自然找不到。
那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:
$ docker run myip curl -s http://ip.cn -i
#小课堂:所以你还可以输入其他你想实现某个功能的命令
④ ENTRYPOINT测试步骤
复制并修改DockerFile文件为DockerFile3:
FROM centos
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "https://ip.cn" ]
重复上面构建、运行步骤,结果如下:
【5】自定义Tomcat镜像
① 在/mydocker/路径下创建路径mytomcat,并放入jdk与tomcat二进制压缩包
然后在该目录下创建文件c.txt:
#纯粹为了copy命令使用
touch c.txt
② 在mytomcat目录下新建DockerFile文件
内容如下:
FROM centos
MAINTAINER jane<jane@qq.com>
#把宿主机当前上下文的c.txt拷贝到容器/usr/local/路径下
COPY c.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中 ADD命令会自动处理URL和解压tar压缩包
ADD jdk-8u121-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.5.42.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问时候的WORKDIR路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_121
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.42
ENV CATALINA_BASE /usr/local/apache-tomcat-8.5.42
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-8.5.42/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-8.5.42/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-8.5.42/bin/startup.sh && tail -f /usr/local/apache-tomcat-8.5.42/logs/catalina.out
③ 构建生成镜像
命令如下:
docker build -f DockerFile -t mytomcat8.5 .
详细过程如下所示:
[root@localhost mytomcat]# docker build -f DockerFile -t mytomcat8.5 .
Sending build context to Docker daemon 193 MB
Sending build context to Docker daemon
Step 0 : FROM centos
---> 495a24dc98e8
Step 1 : MAINTAINER jane<jane@qq.com>
---> Using cache
---> b2c306367103
Step 2 : COPY c.txt /usr/local/cincontainer.txt
---> 30125b712727
Removing intermediate container e7ce454acc1b
Step 3 : ADD jdk-8u121-linux-x64.tar.gz /usr/local/
---> a60edc35c1dd
Removing intermediate container a7d37532c8ed
Step 4 : ADD apache-tomcat-8.5.42.tar.gz /usr/local/
---> 835ce1e40fbb
Removing intermediate container 74877ed67a66
Step 5 : RUN yum -y install vim
---> Running in 632fbb5d8fab
CentOS-8 - AppStream 475 kB/s | 6.4 MB 00:13
CentOS-8 - Base 249 kB/s | 5.0 MB 00:20
CentOS-8 - Extras 2.0 kB/s | 2.1 kB 00:01
Dependencies resolved.
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
vim-enhanced x86_64 2:8.0.1763-13.el8 AppStream 1.4 M
Installing dependencies:
gpm-libs x86_64 1.20.7-15.el8 AppStream 39 k
vim-common x86_64 2:8.0.1763-13.el8 AppStream 6.3 M
vim-filesystem noarch 2:8.0.1763-13.el8 AppStream 48 k
which x86_64 2.21-10.el8 BaseOS 49 k
Transaction Summary
================================================================================
Install 5 Packages
Total download size: 7.8 M
Installed size: 31 M
Downloading Packages:
(1/5): gpm-libs-1.20.7-15.el8.x86_64.rpm 297 kB/s | 39 kB 00:00
(2/5): vim-filesystem-8.0.1763-13.el8.noarch.rp 27 kB/s | 48 kB 00:01
(3/5): vim-enhanced-8.0.1763-13.el8.x86_64.rpm 667 kB/s | 1.4 MB 00:02
(4/5): which-2.21-10.el8.x86_64.rpm 170 kB/s | 49 kB 00:00
(5/5): vim-common-8.0.1763-13.el8.x86_64.rpm 524 kB/s | 6.3 MB 00:12
--------------------------------------------------------------------------------
Total 583 kB/s | 7.8 MB 00:13
warning: /var/cache/dnf/AppStream-02e86d1c976ab532/packages/gpm-libs-1.20.7-15.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
CentOS-8 - AppStream 1.3 MB/s | 1.6 kB 00:00
Importing GPG key 0x8483C65D:
Userid : "CentOS (CentOS Official Signing Key) <security@centos.org>"
Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : which-2.21-10.el8.x86_64 1/5
Installing : vim-filesystem-2:8.0.1763-13.el8.noarch 2/5
Installing : vim-common-2:8.0.1763-13.el8.x86_64 3/5
Installing : gpm-libs-1.20.7-15.el8.x86_64 4/5
Running scriptlet: gpm-libs-1.20.7-15.el8.x86_64 4/5
Installing : vim-enhanced-2:8.0.1763-13.el8.x86_64 5/5
Running scriptlet: vim-enhanced-2:8.0.1763-13.el8.x86_64 5/5
Running scriptlet: vim-common-2:8.0.1763-13.el8.x86_64 5/5
Verifying : gpm-libs-1.20.7-15.el8.x86_64 1/5
Verifying : vim-common-2:8.0.1763-13.el8.x86_64 2/5
Verifying : vim-enhanced-2:8.0.1763-13.el8.x86_64 3/5
Verifying : vim-filesystem-2:8.0.1763-13.el8.noarch 4/5
Verifying : which-2.21-10.el8.x86_64 5/5
Installed:
vim-enhanced-2:8.0.1763-13.el8.x86_64 gpm-libs-1.20.7-15.el8.x86_64
vim-common-2:8.0.1763-13.el8.x86_64 vim-filesystem-2:8.0.1763-13.el8.noarch
which-2.21-10.el8.x86_64
Complete!
---> e810859c3774
Removing intermediate container 632fbb5d8fab
Step 6 : ENV MYPATH /usr/local
---> Running in 6f29ac3aab57
---> 3046102d4b97
Removing intermediate container 6f29ac3aab57
Step 7 : WORKDIR $MYPATH
---> Running in d72543dcc1e5
---> 26216526ef34
Removing intermediate container d72543dcc1e5
Step 8 : ENV JAVA_HOME /usr/local/jdk1.8.0_121
---> Running in 043966dc5dd5
---> 31e881b878b2
Removing intermediate container 043966dc5dd5
Step 9 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
---> Running in 426decc562b0
---> d211b87e14b6
Removing intermediate container 426decc562b0
Step 10 : ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.42
---> Running in e7bd1fb680d3
---> 5e9d3b1a9842
Removing intermediate container e7bd1fb680d3
Step 11 : ENV CATALINA_BASE /usr/local/apache-tomcat-8.5.42
---> Running in 4751834bae65
---> 9a8f8a55f9db
Removing intermediate container 4751834bae65
Step 12 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
---> Running in abcd8a306cb4
---> e70a4215675b
Removing intermediate container abcd8a306cb4
Step 13 : EXPOSE 8080
---> Running in dd5ea962ca9e
---> f70b5c88c7b3
Removing intermediate container dd5ea962ca9e
Step 14 : CMD /usr/local/apache-tomcat-8.5.42/bin/startup.sh && tail -f /usr/local/apache-tomcat-8.5.42/bin/logs/catalina.out
---> Running in 2e86e232814e
---> 5234d0ef08ec
Removing intermediate container 2e86e232814e
Successfully built 5234d0ef08ec
如下所示,可以查看容器内Java环境:
[root@localhost test]# docker exec 9169df7aa44f java -version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
[root@localhost test]#
④ 创建容器实例并运行
命令如下:
docker run -d -p 9080:8080 --name mytomcat8 -v /mydocker/mytomcat/test:/usr/local/apache-tomcat-8.5.42/webapps/test -v /mydocker/mytomcat/tomcatlogs/:/usr/local/apache-tomcat-8.5.42/logs --privileged=true mytomcat8.5
可以使用命令查看容器日志:
docker logs -f -t --tail 10 712e7776a36e
使用浏览器访问如下,说明正确启动:
进入容器内部查看:
docker exec -it 9169df7aa44f /bin/bash
再次回到宿主机查看/mydocker/mytomcat下(会看到test/tomcatlogs已经创建):
⑤ test里面放入项目文件
在test项目里面放入WEB-INF/web.xml 、a.jsp,将会同步到容器内webapps/test里面。
宿主机如下:
容器内显示如下:
#9169df7aa44f 为容器ID
[root@9169df7aa44f test]# ls
WEB-INF a.jsp
[root@9169df7aa44f test]#
浏览器验证如下:
宿主机、容器、Dockerfile以及远程仓库关系操作如下图所示:
【6】build时文件过大
docker client会默认把Dockerfile同级所有文件发给docker Deamon中,故而如果Dockerfile同级别下有其他文件可能会导致build生成的镜像过大。
那么如何解决呢?
第一种解决方案
build时删除掉无用文件,比如logs
第二种解决方案
保证Dockerfile同级别下没有其他多余文件
第三种解决方案
其实可以参考.gitignore
的思想在Dockerfile同级别下创建一个.dockerignore
文件。
.dockerignore
匹配规则
符号 | 作用 |
---|---|
# | 注释 |
* | 匹配0或多个非/的字符 |
? | 匹配1个非/的字符 |
** | 0个或多个目录 |
! | 除...外 ,需结合上下文语义 |
#comment
#代表根目录(上下文环境目录中)中以abc开头的任意直接子目录或者直接子文件将被忽略
#如/abc abc.txt
/abc*
#代表根目录(上下文环境目录中)中任意直接子目录中以abc开头的任意直接子目录或者直接子文件将被忽略
#如 /file/abc /file/abc.txt
*/abc*
#代表根目录(上下文环境目录中)中任意两级目录下以abc开头的任意直接子目录或者直接子文件将被忽略
#如 /file1/file2/abc /file1/file2/abc.txt
*/*/abc*
#排除根目录中的文件和目录,其名称是单字符扩展名temp。例如,/tempa与/tempb被排除在外。
temp?
#Docker还支持一个**匹配任意数量目录(包括零)的特殊通配符字符串
**/abc*
#以!(感叹号)开头的行可用于对排除项进行例外处理,比如原本包含了README.md这个文件的过滤,但是加了如下一行后
#就不会再过滤README.md,依然会将其提交到守护进程。
!README.md
#异常规则的放置位置会影响行为
*.md
!README*.md
README-secret.md
#README-secret.md 仍然会被忽略
*.md
README-secret.md
!README*.md
#README-secret.md 不会被忽略
您甚至可以使用该.dockerignore文件来排除Dockerfile和.dockerignore文件。这些文件仍然发送到守护程序,因为它需要它们来完成它的工作。但是ADD和COPY命令不会将它们复制到镜像中。
更多推荐
所有评论(0)