Docker
container
Dockerfile
「初學Docker」Dockerfile易混亂的指令
2019/04/08 11:19:10
8
18360
Dockerfile Instructions
前言:
各位好,本人是樣樣學樣樣鬆樣樣不精通的不負責任講座。最近臉頰肉也開始覺得有點鬆···怎麼辦?!啊~~~~~
因為近期的案子,使用到docker、kubernetes來部署安裝;同仁們都是首次實戰build docker image。
我們來聊聊幾個在寫Dockerfile時,容易混亂搞不懂意思的指令。
簡介:
Dockerfile簡單介紹一下,是用來描述這個image要怎麼組成的文檔。
詳細的Dockerfile指令與介紹,可參考Dockerfile官方文檔、Best practices for writing Dockerfiles
或者是去參考docker hub許多官方image的寫法,東參考西參考很快就能上手!
比如說要觀摩postgres Dockerfile是怎麼寫的:
就可以暸解許多高深的Dockerfile寫法!
主題:
底下介紹幾種在寫Dockerfile時,容易讓人混亂的指令:
1.
COPY vs ADD
COPY和ADD二個的功用都一樣,就是將檔案複製進去image裡!
差別在於:
• COPY只能複製本機端的檔案或目錄
• ADD能增加遠端url的檔案到docker image
• ADD能順手將本機端複製進去的tar檔解開(遠端的tar不行!)
罷特!很重要!客倌們!
在實例上並不建議使用ADD來抓取網路上的檔案,會使用RUN curl or wget的方式。
原因是使用一次ADD指令會增加docker image layers一次,原則上layers越多,docker image size就會越大!
咱們來看看docker自己提供的範例:
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
1.增加遠端的tar檔
2.解開tar檔
3.編譯程式
因為ADD、RUN都是會增加image layers的指令,所以上面就增加了三層layers。
再來看看建議的寫法:
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
只用一個RUN指令就做完同樣的事情,功能不變,但只用了一層layers。
誒~各位人客不要小看容量減少帶來的好處,除了減少下載的時間;
在雲端環境上,網路可都是斤斤計較要計費的!一分流量一分錢,當然是能省則省呀。
本段重點:
• 使用COPY複製檔案,因為意義比較明確
• 只有需要解開本機tar檔進image時,才使用ADD
2.
EXPOSE vs publish
這又是另一個讓人摸不著重點的指令···
很多人以為加上EXPOSE 8080,docker run起來後,就可以從本機端連得到container的8080 port。
但是,孩子,這是不可能的。
EXPOSE概念上比較像是在告訴使用這個image的人,服
務是在那個port。
我們來下些指令
docker pull nginx
docker inspect nginx
可以看到下圖在Config裡有個ExposedPorts;
這邊就在告訴你,這個nginx的container跑起來後,服務是在port 80/tcp
因此我們若要在本機端能夠連的到container中的ngin
x服務,
必須要publish一下,在參數加上-p <要讓外部連的到的port>:<app服務的port>
docker run -p 8888:80 -d nginx
就能夠連的到nginx啦!
本段重點:
• EXPOSE是在告訴Docker,本服務是啟動在某個port
•
要讓宿主機能連進該服務,要使用publish
3.
CMD or ENTRYPOINT
CMD與ENTRYPOINT指令,都可以用來配置container啟動時要運行的命令。
那麼二種有什麼不同呢?來看個小小的例子。
我在Dockerfile裡寫CMD echo "Hello Weber!",執行docker run -it <image>會輸出
Hello Weber! |
但是若啟動時另外指定docker run -it <image> echo "What's up~",會變成只輸出
What's up~ |
咦咦~~蝦咪碗糕,我設定的CMD命令怎麼不見了!
這是因為CMD的目的是讓你配置一個預設的命令內容;
啟動容器時若是有另外指定命令,就會忽略原本的CMD命令內容。
相反的,ENTRYPOINT設定的命令則一定會被執行,並且會將docker run帶的參數加在後面一併運行。
因此ENTRYPOINT跟CMD是可以互相配合的,讓CMD的參數當作ENTRYPOINT的額外參數。
讓ENTRYPOINT帶必要的參數,而CMD帶可以被替換掉的參數。
並且有多種形式可以互相搭配,但屬於比較進階的用法,這邊暫不詳加敘述以免大家又亂掉了。
本段重點:
•
CMD的內容,當容器啟動若有指定其他命令,會被忽略
•
ENTRYPOINT設定的指令,一定會被執行
• 可以有多個CMD,不過只有最後一個會生效
後記:
以上內容,是小的在工作上親身經歷的心得,希望能幫助到各位。
或許也有誤解的部分,也請大家不吝提供正確的觀念,互相討論。
下次有機會來聊聊Kubernetes + Helm實戰吧!
石偉琪
2019/04/15 15:41:35
跪求 Kubernetes + Helm實戰
侯清慈(AlexHou)
2019/04/17 14:59:21
真是篇講人話的好文章...