2019-05-07 Dockerfile 詳解

本文僅為個人學(xué)習(xí)記錄. 教程來源Docker--從入門到實踐

FROM 指定基礎(chǔ)鏡像

FROM nginx

FROM 有一個比較特殊的鏡像(空鏡像)

FROM scratch

一般 golang 程序會直接使用FROM scratch.


RUN 執(zhí)行命令

run指令有兩種格式

  • shell格式
RUN echo 'hello docker'
  • exec格式
RUN apt-get update
RUN apt-get install -y gcc

注意:Dockerfile每一個指令都會構(gòu)建一層,不得超過127層

所以很多時候我們會使用 && 來減少構(gòu)建的層數(shù)
例如上例可改寫為

RUN apt-get update && apt-get install -y gcc

Dockerfile nginx 實例

FROM nginx
RUN echo '<h1>Hello,Docker!!</h1>' > /usr/share/nginx/html/index.html

構(gòu)建命令

docker build -t nginx:v3 .

運行命令

docker run --name webserver -d -p 80:80 nginx:v3

COPY 復(fù)制文件

COPY 指令將從構(gòu)建上下文目錄中 <源路徑> 的文件/目錄復(fù)制到新的一層的鏡像內(nèi)的 <目標路徑> 位置。

COPY [--chown=<user>:<group>]<源路徑> ... <目標路徑>
COPY [--chown=<user>:<group>] ["<源路徑1>",... "<目標路徑>"]

<目標路徑> 可以是容器內(nèi)的絕對路徑,也可以是相對于工作目錄的相對路徑(工作目錄可以用 WORKDIR 指令來指定)。目標路徑不需要事先創(chuàng)建,如果目錄不存在會在復(fù)制文件前先行創(chuàng)建缺失目錄。
例子:

COPY package.json /usr/src/app/

這里源路徑可以使用通配符,其通配符規(guī)則要滿足 go 的 filepath.Match規(guī)則

例如:

COPY hom* /mydir/
COPY hom?.txt /mydir/

ADD 更高級的復(fù)制文件 (雖然很高級但不建議使用)

ADD [--chown=<user>:<group>]<源路徑> ... <目標路徑>
ADD [--chown=<user>:<group>] ["<源路徑1>",... "<目標路徑>"]

ADD 指令和 COPY 的格式和性質(zhì)基本一致。但是在 COPY 基礎(chǔ)上增加了一些功能

比如 <源路徑> 可以是一個 URL,這種情況下,Docker 引擎會試圖去下載這個鏈接的文件放到 <目標路徑> 去。下載后的文件權(quán)限自動設(shè)置為 600,如果這并不是想要的權(quán)限,那么還需要增加額外的一層 RUN 進行權(quán)限調(diào)整,另外,如果下載的是個壓縮包,需要解壓縮,也一樣還需要額外的一層 RUN 指令進行解壓縮。所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下載,處理權(quán)限、解壓縮、然后清理無用文件更合理。因此,這個功能其實并不實用,而且不推薦使用

注意 ADD 指令會令鏡像構(gòu)建緩存失效,從而可能會令鏡像構(gòu)建變得比較緩慢。因此在 COPY 和 ADD 指令中選擇的時候,可以遵循這樣的原則,所有的文件復(fù)制均使用 COPY 指令,僅在需要自動解壓縮的場合使用 ADD。


CMD 容器啟動命令

Docker 不是虛擬機,容器就是進程。既然是進程,那么在啟動容器的時候,需要指定所運行的程序及參數(shù)。CMD 指令就是用于指定默認的容器主進程的啟動命令的

CMD指令的格式和RUN相似,也是兩種格式:

#shell格式
CMD <命令>
#exec格式
CMD ["可執(zhí)行文件","參數(shù)1","參數(shù)2"...]

在指令格式上,一般推薦使用 exec 格式,這類格式在解析時會被解析為 JSON 數(shù)組,因此一定要使用雙引號 ",而不要使用單引號。

如果使用 shell 格式的話, 實際的命令會被包裝為 sh -c 的參數(shù)的形式進行執(zhí)行.

CMD echo $HOME

在實際執(zhí)行中, 會將其變更為:

CMD [ "sh", "-c", "echo $HOME" ]

這就是為什么我們可以使用環(huán)境變量的原因, 因為這些環(huán)境變量會被shell 進行解析處理, 提到CMD 就不得不提容器中應(yīng)用在前臺執(zhí)行和后臺執(zhí)行的問題. 這是初學(xué)者常出現(xiàn)的一個混淆.

Docker不是虛擬機, 容器中的應(yīng)用都應(yīng)該以前臺執(zhí)行,而不是像虛擬機/物理機那樣,用upstart/systemd去啟動后臺服務(wù), 容器內(nèi)沒有后臺服務(wù)的概念

一些初學(xué)者將CMD寫為

CMD service nginx start

然后發(fā)現(xiàn)容器執(zhí)行后就立即退出了,甚至在容器內(nèi)去使用systemctl 命令,結(jié)果發(fā)現(xiàn)根本執(zhí)行不了.這就是因為沒搞明白前臺,后臺的概念, 沒有區(qū)分容器和虛擬機的差異,依舊用傳統(tǒng)虛擬機的角度去理解容器

對于容器而言, 其啟動程序就是容器應(yīng)用進程, 容器就是為了主進程而存在的, 主進程退出 , 容器就失去了存在的意義,從而退出, 其他輔助進程不是他需要關(guān)心的東西

而使用 service nginx start命令 則是希望upstart來以"后臺守護進程"的形式啟動nginx服務(wù), 但剛才說了 CMD service nginx start 會被理解為 CMD [ "sh", "-c", "echo $HOME" ],因此主進程實際上是sh.那么當(dāng)service nginx start命令結(jié)束后 , sh 也就結(jié)束了,sh作為主進程退出了, 自然就會讓容器也跟著退出

正確的做法是 直接執(zhí)行nginx可執(zhí)行文件, 并且要求以前臺的形式運行.
比如:

CMD ["nginx", "-g", "deamon off"]

個人理解:
推薦使用 exec格式的用意是為了避免類似sh -c的命令干擾


ENTRYPOINT (入口點)

ENTRYPOINT 的格式和RUN指令格式一樣, 分為 execshell
ENTRYPOINT 的目的和CMD一樣都是在指定容器啟動程序及參數(shù). ENTRYPOINT 在運行是也可以替代,不過比CMD略顯繁瑣, 需要通過docker run的參數(shù)--entrypoint來指定

當(dāng)指定了ENTRYPOINT 后, CMD的含義就發(fā)生了改變, 不再是直接的運行其命令, 而是將CMD的內(nèi)容當(dāng)作參數(shù)傳給ENTRYPOINT指令.可以理解為:

<ENTRYPOINT> "<CMD>"

場景一: 讓鏡像變成像命令一樣使用

假設(shè)我們需要一個得知自己當(dāng)前公網(wǎng) IP 的鏡像,那么可以先用 CMD 來實現(xiàn):

FROM ubuntu:18.04
RUN apt-get update \
    &&apt-get install -y curl \
    &&rm -rf /var/lib/apt/lists/*
CMD ["curl", "-s" ,"https://ip.cn"]

假如我們使用 docker build -t myip . 來構(gòu)建鏡像的話, 如果我們需要查詢當(dāng)前公網(wǎng)IP, 只需要執(zhí)行

docker run myip

這里遇到一個問題, 如果我們想用curl -i的話就會出現(xiàn)問題
所以這里就引申出了ENTRYPOINT的用法

FROM ubuntu:18.04
RUN apt-get update \
    &&apt-get install -y curl \
    &&rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["curl","-s","https://ip.cn"]

ENV 設(shè)置環(huán)境變量

格式有兩種

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2> ...

這個指令很簡單,就是設(shè)置環(huán)境變量而已,無論是后面的其它指令,如 RUN,還是運行時的應(yīng)用,都可以直接使用這里定義的環(huán)境變量。

.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容