前言
在有了Docker相关的基础知识后,就可以开始指定出行计划了(Dockerfile),计划里将记录我们的出发点(FROM),需要购买的物品(COPY/ADD),在预定的景点拍照(RUN)。当然本身Dockerfile其实也可以在被发明的那个时候称为Recipe的,只是这个单词在计算机领域被用到太广泛了,没有Dockerfile来得特立独行。下面就来简单说说Dockerfile.
Dockerfile简介
Dockerfile是用来构建镜像的文本文件,其中记录了如何构建镜像的命令。按照最新的文档,目前可以在Dockerfile中使用FROM, RUN, CMD, LABEL, MAINTAINER, EXPOSE, ENV, ADD, COPY, ENTRYPOINT, VOLUME, USER, WORKDIR, ARG, ONBUILD, STOPSIGNAL, HEALTHCHECK, SHELL共18个指令。其中MAINTAINER已经不推荐使用,可以使用LABEL替代。
下面就是一个IIS镜像的例子。这里需要注意的是ENTRYPOINT指令中的使用的ServiceMonitor.exe, 这是专为ENTRYPOINT设计的应用,目前已在Github上开源。
# escape=`
FROM microsoft/windowsservercore:1709
RUN powershell -Command `
Add-WindowsFeature Web-Server; `
Invoke-WebRequest -UseBasicParsing -Uri "https://dotnetbinaries.blob.core.windows.net/servicemonitor/2.0.1.3/ServiceMonitor.exe" -OutFile "C:\ServiceMonitor.exe"
EXPOSE 80
ENTRYPOINT ["C:\\ServiceMonitor.exe", "w3svc"]
其中FROM指令用于指定在构建新镜像时将使用的基础镜像, 通用用途的Windows容器一般可以选择则 microsoft/windowsservercore 或者 microsoft/nanoserver。如果镜像是用来运行ASP.NET或者ASP.NET Core应用,那么可以使用 microsoft/aspnet 或者 microsoft/aspnetcore 镜像。
接下来的RUN指令则是执行PowerShell的Invoke-WebRequest命令下载ServiceMonitor.exe应用。EXPOSE则是用来通知Docker当容器运行时监听的端口。
命令格式
在重点介绍ENTRYPOINT指令前,先来谈谈Dockerfile中的命令格式,直白的表达就是什么时候用中括号([])。在Docker的官方文档说明中,使用中括号的被称为exec格式,反之则称为shell格式。两者的区别可以用以下两个Dockerfile来对比区分。一句话的解释就是使用exec格式的话,将按照exec中指定的命令运行。使用shell格式化的话,将使用默认命令行执行。
exec form
FROM microsoft/windowservercore:1709
RUN ["powershell", "New-Item", "c:/test"]
shell form
FROM microsoft/windowservercore:1709
RUN powershell New-Item c:/test
ENTRYPOINT 指令
ENTRYPOINT指令的作用是将容器配置成可执行程序,或者说设置默认执行的程序,而CMD指令只指定了程序默认执行时使用的参数。在Docker的官方文档中有一张非常好的表格罗列各种情况。现摘录如下。
No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT [“exec_entry”, “p1_entry”] | |
---|---|---|---|
No CMD | error, not allowed | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD [“exec_cmd”, “p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd |
CMD [“p1_cmd”, “p2_cmd”] | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry p1_cmd p2_cmd |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
这张表格里混合了好几种情况,可以按照纵向列的方式来阅读。当没有指定ENTRYPOINT时,以CMD中指定的命令和参数为准(第一列)。当ENTRYPOINT和CMD同时存在,且ENTRYPOINT以shell格式存在时,以ENTRYPOINT中指定的命令为准(第二列)。当ENTRYPOINT和CMD同时存在,且都以exec格式存在,则合并ENTRYPOINT和CMD中指定的命令和参数。
PowerShell及转义符号
PowerShell 首次出现在2006年,它的出现统一了Windows下命令行的设计方式,让管理员和开发者可以使用动词-名词的方式来使用开发命令行工具。PowerShell本身对标Linux的Python,作为胶水语言来简化操作系统的管理。当然Python目前比PowerShell还是领先一些,Web应用开发的能力也是PowerShell所不具备的,这和PowerShell做为管理员工具存在的初始定位有关。
那么在Dockerfile中如何使用PowerShell呢?这里以一个Dockerfile为例进行说明。首先,通过escape注释语句设置本Dockerfile中的转义符号为倒角符(`)。接下来通过SHELL指令设置容器内默认命令行为PowerShell。然后通过RUN指令运行PowerShell命令。这里需要注意的是,示例中运行的已经不是单行命令,而是脚本块。因此命令之间是通过分号(;)进行分隔的。而为了避免一行命令过长,则使用倒角符截断命令参数。
PowerShell如果要展开来讨论,做为开发语言也有很多要讨论的地方,在Dockerfile中一般只是用来执行现成的命令。同时需要注意的在Windows Server, version 1709中PowerShell已从nanoserver镜像中移除。
#escape=`
FROM microsoft/windowsservercore
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" ]
总结
文章标题中使用了出行计划来形容Dockerfile之于容器制作的作用。技术上来说Dockerfile的存在使得开发人员可以在代码库中管理最终交付物的生成过程,比如如果应用要发布到Windows Server, version 1803中,只需更改FROM中使用的基础镜像即可。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。