Dockerfile参考(18) – SHELL设置执行命令的shell

格式:

  1. SHELL ["executable", "parameters"]

SHELL指令可以覆盖命令的shell模式所使用的默认shell。Linux的默认shell是[“/bin/sh”, “-c”],Windows的是[“cmd”, “/S”, “/C”]。SHELL指令必须以JSON格式编写。
SHELL指令在有两个常用的且不太相同的本地shell:cmd和powershell,以及可选的sh的windows上特别有用。
SHELL指令可以出现多次。每个SHELL指令覆盖之前的SHELL指令设置的shell,并影响随便的指令。例如:

  1. FROM windowsservercore
  2.  
  3. # Executed as cmd /S /C echo default
  4. RUN echo default
  5.  
  6. # Executed as cmd /S /C powershell -command Write-Host default
  7. RUN powershell -command Write-Host default
  8.  
  9. # Executed as powershell -command Write-Host hello
  10. SHELL ["powershell", "-command"]
  11. RUN Write-Host hello
  12.  
  13. # Executed as cmd /S /C echo hello
  14. SHELL ["cmd", "/S"", "/C"]
  15. RUN echo hello

当RUN, CMD和ENTRYPOINT使用shell形式时,将使用SHELL指令设置的shell执行。
以下的示例是windows常见的模式,可以使用SHELL指令精简:

  1. RUN powershell -command Execute-MyCmdlet -param1 "c:foo.txt"

由docker解析会是:

  1. cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:foo.txt"

这个命令之所以低效有两个原因。首先,没有必须调用cmd.exe。第二,每个使用shell模式的RUN指令需要一个额外的powershell。
为了优化这个命令更有效率,有两个方法,其中之一使用RUN指令的JSON形式,如:

  1. RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 "c:\foo.txt""]

虽然没有调用了cmd.exe,不过需要对双引号进行转义,看起来比较冗长。另一种机制是使用SHELL指令和shell形式,使得windows用户可以使用更自然的语法,特别是与escape指令一起用时:

  1. # escape=`
  2.  
  3. FROM windowsservercore
  4. SHELL ["powershell","-command"]
  5. RUN New-Item -ItemType Directory C:Example
  6. ADD Execute-MyCmdlet.ps1 c:example
  7. RUN c:exampleExecute-MyCmdlet -sample ‘hello world’

构建结果为:

  1. PS E:dockerbuildshell> docker build -t shell .
  2. Sending build context to Docker daemon 3.584 kB
  3. Step 1 : FROM windowsservercore
  4.  —> 5bc36a335344
  5. Step 2 : SHELL powershell -command
  6.  —> Running in 87d7a64c9751
  7.  —> 4327358436c1
  8. Removing intermediate container 87d7a64c9751
  9. Step 3 : RUN New-Item -ItemType Directory C:Example
  10.  —> Running in 3e6ba16b8df9
  11.  
  12.  
  13.     Directory: C:
  14.  
  15.  
  16. Mode                LastWriteTime         Length Name
  17. —-                ————-         —— —-
  18. d—–         6/2/2016   2:59 PM                Example
  19.  
  20.  
  21.  —> 1f1dfdcec085
  22. Removing intermediate container 3e6ba16b8df9
  23. Step 4 : ADD Execute-MyCmdlet.ps1 c:example
  24.  —> 6770b4c17f29
  25. Removing intermediate container b139e34291dc
  26. Step 5 : RUN c:exampleExecute-MyCmdlet -sample ‘hello world’
  27.  —> Running in abdcf50dfd1f
  28. Hello from Execute-MyCmdlet.ps1 – passed hello world
  29.  —> ba0e25255fda
  30. Removing intermediate container abdcf50dfd1f
  31. Successfully built ba0e25255fda
  32. PS E:dockerbuildshell>

Docker 1.12开始添加了此SHELL功能。