動機
這裡是研究(自己的觀察與猜測)dockerfile的語意啦
docker的container就是應用程式 只不過每個container都有自己的
- 網路空間
- 儲存空間
ENTRYPOINT & CMD
一般在網路上會看到ENTRYPOINT & CMD在不同form下會有不同的效果 在官方文件上有以下的表格
| | 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 |
來觀察一下在不同的form下會有什麼差別
exec form: 沒有/bin/sh -c
shell form: 有/bin/sh -c
所以shell form就是一種macro會自己加上/bin/sh -c
故想像成在terminal打指令
exec form: 直接打在terminal
shell form: 先加上/bin/sh -c
,在打到terminal
那再回來看ENTRYPOINT & CMD 其實ENTRYPOINT & CMD就是
分別展開ENTRYPOINT與CMD的指令再append起來再送到terminal執行
ARG & ENV
再來看ARG與ENV的scope
ARG是build的參數,所以只能在RUN的時候看到 ENTRYPOINT與CMD都看不到
ENV就都看的到
exec form & shell form
那執行期時ARG與ENV在exec form與shell form有什麼不同嗎? 直接跑跑看!!
Sending build context to Docker daemon 2.048kB
Step 1/9 : FROM alpine
latest: Pulling from library/alpine
df20fa9351a1: Pull complete
Digest: sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321
Status: Downloaded newer image for alpine:latest
---> a24bb4013296
Step 2/9 : ARG hi=1
---> Running in 81dac0cde5c5
Removing intermediate container 81dac0cde5c5
---> 0a224d4f46ce
Step 3/9 : ENV wow=2
---> Running in 6c54e59b4201
Removing intermediate container 6c54e59b4201
---> 6a008ef31f84
Step 4/9 : RUN echo $hi
---> Running in 69eec389ae0d
1
Removing intermediate container 69eec389ae0d
---> a025a3789730
Step 5/9 : RUN ["echo", "$hi"]
---> Running in ecf7cc563edf
$hi
Removing intermediate container ecf7cc563edf
---> c3f8c7e3d843
Step 6/9 : RUN echo $wow
---> Running in 0a47051aeaa0
2
Removing intermediate container 0a47051aeaa0
---> f0ec803da2d4
Step 7/9 : RUN ["echo", "$wow"]
---> Running in 7b443431db18
$wow
Removing intermediate container 7b443431db18
---> 91902d5a74b1
Step 8/9 : RUN ["/bin/sh", "-c", "echo", "$hi"]
---> Running in 865729798cb8
Removing intermediate container 865729798cb8
---> e709f7ba52dd
Step 9/9 : RUN ["/bin/sh", "-c", "echo", "$wow"]
---> Running in 9897c8732ca2
Removing intermediate container 9897c8732ca2
---> aaa72c558553
Successfully built aaa72c558553
如果用exec form,不會置換, shell form會置換
所以只有shell form才會看到Dockerfile的變數 但exec form根本看不到
所以可以對shell form與exec form下一個結論 shell form是統一跑在Dockerfile自己開的shell(像/bin/sh) exec form就是直接用像是execl之類的東西直接去跑,把所有東西當成字串
那麼應該可以猜shell的展開大概會像
envs = ""
for (k,v) in ENVS: # env的所有pair,與arg的pair(如果可以的話)
envs += "{}={} ".format(k,v)
return "/bin/sh -c {} {CMD}".format(envs,cmd)
exec的話就是
system(' '.join(input_array))
等等,那為什麼CMD可以執行指令,在沒有ENTRYPOINT的時候
如果沒有ENTRYPOINT就可以看成
"" + <expanded CMD>
自然就有CMD作為指令執行的效果
等等,那為什麼ENTRYPOINT的shell form會忽略CMD??
如果兩邊都是shell form,兩邊展開就是
/bin/sh -c ... /bin/sh -c ...
但是實際上CMD不會執行指令,他只是展開與ENTRYPOINT接在一起 這樣不符合shell form會執行指令的預期就擋掉了
2 phases
前面看了這麼多,可以看出Dockerfile有兩個階段
- build phase: 生成Image的時候,ARG+RUN+ENV
- run phase: 跑container的時候,ENTRYPOINT+CMD+ENV