有必定旅行经验的朋友都知道,即便在出发前制定了详细的出行计划,也会在路途中由于各式各样的情况而不得不从新修改计划。这个情况在咱们编写Dockerfile时同样存在。花了30分钟编写的Dockerfile在构建镜像的时候也会出现各式各样的情况。那么编写Dockerfile时有哪些能够优化的点呢?docker
在了解可优化点以前,先来了解下容器的分层文件系统。shell
分层文件系统是容器技术中的重要概念,当经过Dockerfile构建镜像时,每个可执行指令会被容器引擎一一执行,并造成临时的容器。最终叠加在一块儿成为新的镜像。这里有个名词,叫可执行指令,最经常使用的就是RUN指令,由于RUN指令会在构建时会造成新的镜像层。其它建立文件层的指令还有ADD和COPY。windows
对于如下的Dockerfile,能够经过 docker history 来查看分层文件系统的结构。各位须要注意的是docker history的输出结果和Dockerfile中指令的前后顺序。缓存
#escape=` FROM microsoft/windowsservercore:1803 SHELL [ "powershell", "-command" ] RUN $ErrorActionPreference = 'Stop'; ` $ProgressPreference = 'SilentlyContinue'; ` $null = New-Item -Path c:\apps -Type Directory RUN Invoke-WebRequest -Uri https://download.sysinternals.com/files/SysinternalsSuite.zip ` -UseBasicParsing -OutFile c:\apps\SysinternalsSuite.zip ` -Proxy http://192.168.0.124:1080; ` Expand-Archive -Path C:\apps\SysinternalsSuite.zip -DestinationPath C:\apps\sysinternals\ -Force; ` Remove-Item -Path c:\apps\SysinternalsSuite.zip ENTRYPOINT [ "powershell" ]
$ docker history greggu/sysinternals:20170516 IMAGE CREATED CREATED BY SIZE COMMENT 64b20b828374 2 weeks ago powershell -command #(nop) ENTRYPOINT ["pow… 41kB 5b6b75a8ed6c 2 weeks ago powershell -command Invoke-WebRequest -Uri h… 94.2MB 8cdde7fb6229 2 weeks ago powershell -command $ErrorActionPreference =… 39MB 214857b207fb 2 weeks ago powershell -command #(nop) SHELL [powershel… 41kB ad6116672030 6 weeks ago Install update 10.0.14393.2189 2.79GB <missing> 17 months ago Apply image 10.0.14393.0 7.68GB
首先针对如下Dockerfile构建镜像,请在构建过程当中观察输出,也可使用docker history查看。网络
FROM microsoft/windowsservercore:1803 SHELL [ "powershell", "-command" ] RUN $ErrorActionPreference = 'Stop' RUN $ProgressPreference = 'SilentlyContinue' RUN $null = New-Item -Path c:\apps -Type Directory
$ docker history greggu/test:0.0.1 IMAGE CREATED CREATED BY SIZE COMMENT 158b934a3b80 About a minute ago powershell -command $null = New-Item -Path c… 32.7MB e3b45ff79cc9 2 minutes ago powershell -command $ProgressPreference = 'S… 32.7MB a61529eb0225 2 minutes ago powershell -command $ErrorActionPreference =… 39.1MB 214857b207fb 2 weeks ago powershell -command #(nop) SHELL [powershel… 41kB ad6116672030 6 weeks ago Install update 10.0.14393.2189 2.79GB <missing> 17 months ago Apply image 10.0.14393.0 7.68GB
能够看到每一句RUN指令都新生成了一层镜像层,致使镜像大小变大。优化的方法就是使用;和`(换行符)将多条PowerShell语句合并成一条执行。也就是在本文最开始使用的例子。app
仍是本文最开始使用的例子,在这个例子中,首先从网络下载SysinternalsSuite.zip压缩包,随后执行了解压操做。最后执行Remove-Item操做把压缩包删除。而这个删除操做减少了镜像体积。这点你们很容易理解,再也不须要的文件删除便可。固然这里还有一个小点,为了让Dockerfile能在任意位置被使用,通常推荐经过网络下载所依赖的文件。因此Invoke-WebRequest的经常使用参数也是须要掌握的。优化
在以前的例子中,各位能够看到每一行RUN指令都生成了新的一层镜像,从而增长最终镜像的大小。那么是否是意味这把全部指令都写在一行内就完成了最佳优化实践呢?这个理解是不对的。为了在构建镜像时使用到Docker的缓存功能,须要对构建指令进行分组。请各位准备如下两个Dockerfile并执行构建操做,并特别留意构建第二个镜像时第3步的输出。ui
# escape=` FROM microsoft/windowsservercore:1803 SHELL [ "powershell", "-command" ] RUN $ErrorActionPreference = 'Stop'; ` $ProgressPreference = 'SilentlyContinue'; ` $null = New-Item -Path c:\demos -Type Directory RUN $null = New-Item -Path c:\demos\demo01 -Type Directory
# escape=` FROM microsoft/windowsservercore:1803 SHELL [ "powershell", "-command" ] RUN $ErrorActionPreference = 'Stop'; ` $ProgressPreference = 'SilentlyContinue'; ` $null = New-Item -Path c:\demos -Type Directory RUN $null = New-Item -Path c:\demos\demo02 -Type Directory
由于使用了两个Dockerfile,须要在docker build时指定具体的Dockerfile,具体构建命令能够放在一个批处理文件中日志
docker build -f Dockerfile.1 --rm --tag greggu/demo01:0.0.1 . docker build -f Dockerfile.2 --rm --tag greggu/demo02:0.0.1 .
构建日志code
PS C:\Users\greggu\repos\dow-playground\windows\demo02> .\build.ps1 Sending build context to Docker daemon 4.096kB Step 1/4 : FROM microsoft/windowsservercore:1803 ---> 7e2287b03e2e Step 2/4 : SHELL [ "powershell", "-command" ] ---> Running in cb5a6e633a04 Removing intermediate container cb5a6e633a04 ---> 8fc2f8b81b5b Step 3/4 : RUN $ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; $null = New-Item -Path c:\demos -Type Directory ---> Running in dce5d9150f26 Removing intermediate container dce5d9150f26 ---> 922a8037b585 Step 4/4 : RUN $null = New-Item -Path c:\demos\demo01 -Type Directory ---> Running in 69d0d0277786 Removing intermediate container 69d0d0277786 ---> 57bde82f4a6f Successfully built 57bde82f4a6f Successfully tagged greggu/demo01:0.0.1 Sending build context to Docker daemon 4.096kB Step 1/4 : FROM microsoft/windowsservercore:1803 ---> 7e2287b03e2e Step 2/4 : SHELL [ "powershell", "-command" ] ---> Using cache ---> 8fc2f8b81b5b Step 3/4 : RUN $ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; $null = New-Item -Path c:\demos -Type Directory ---> Using cache ---> 922a8037b585 Step 4/4 : RUN $null = New-Item -Path c:\demos\demo02 -Type Directory ---> Running in 295a54558ab5 Removing intermediate container 295a54558ab5 ---> 386e4f6cd28d Successfully built 386e4f6cd28d Successfully tagged greggu/demo02:0.0.1
因为Docker在处理Dockerfile时是自顶向下处理的,每行指令将和缓存的文件层进行对比。若是缓存中没有所需的文件层,Docker将按照Dockerfile的指令进行构建。为了合理利用缓存从而加快镜像构建速度,通常推荐将在多个镜像中共享的文件层的构建指令放在Dockerfile前部,而改变的部分放在Dockerfile尾部,具体的Dockerfile能够参考上一个优化建议。
在编写Dockerfile时,通常遵循如下两点。第一点,全部Docker指令在Dockerfile中须要大写,从而和具体的操做命令区分开来。第二点,对于过长的指令请合理使用换行符,从而增长Dockerfile的可阅读性。
本文总结了在构建Windows容器时,如何对Dockerfile进行优化,提升构建效率,在各位编写多个Dockerfile以后,相信会增长对本文的理解。