使用Dockerfile創(chuàng)建鏡像

在上面的內(nèi)容中介紹了如何使用docker commit的方法來構(gòu)建鏡像,相反推薦使用被稱為Dockerfile的定義文件和docker build命令來構(gòu)建鏡像。Dockerfile使用基本的基于DSL語法的指令來構(gòu)建一個Docker鏡像,之后使用docker build命令基于該Dockerfile中的指令構(gòu)建一個新的鏡像。

(一)第一個Dockerfile

現(xiàn)在來創(chuàng)建一個最簡單的Dockerfile文件樣例,先創(chuàng)建一個空的Dockerfile文件,在任意目錄下都行,在Dockerfile文件中填入以下內(nèi)容。

FROM alpine:3.14

//設(shè)置容器內(nèi)的數(shù)據(jù)卷

VOLUME ["/var/html"]

EXPOSE 80

該Dockerfile由一系列指令和參數(shù)組成,每條指令,如FROM,都必須為大寫字母且后面跟隨一個參數(shù):FROM alpine:3.14,Dockerfile中的指令會按順序從上到下執(zhí)行,所以應(yīng)該根據(jù)需要合理安排指令的順序。

使用build命令構(gòu)建鏡像的步驟如下 :

第一步:Docker從基礎(chǔ)鏡像運行一個容器。

第二步:執(zhí)行數(shù)據(jù)卷指令來創(chuàng)建一個數(shù)據(jù)卷。

第三步:設(shè)置訪問端口

—— 最后所有指令執(zhí)行完畢。

每個Dockerfile的第一條指令都應(yīng)該是FROM,F(xiàn)ROM指令指定一個已經(jīng)存在的鏡像后續(xù)指令都將基于該鏡像進行,這個鏡像被稱為基礎(chǔ)鏡像(base iamge)。在上面的Dockerfile示例中,我們指定了alpine:3.14作為鏡像的基礎(chǔ)鏡像,基于這個Dockerfile構(gòu)建的新鏡像將以alpine:3.14操作系統(tǒng)為基礎(chǔ),在運行一個容器時,必須要指明是基于哪個基礎(chǔ)鏡像在進行構(gòu)建。

接著是VOLUME指令,用于指定數(shù)據(jù)卷的設(shè)置。

最后設(shè)置EXPOSE指令,這條指令告訴Docker該容器內(nèi)的應(yīng)用程序?qū)褂萌萜鞯闹付ǘ丝冢@并不意味著可以自動訪問任意容器運行中服務(wù)的端口,這里指定的是80端口。

(二)Dockerfile指令

本小節(jié)主要針對Dockerfile文件中使用到的指令進行介紹,介紹Dockerfiler文件中常用的指令,在Dockerfile文件中所有的指令都必須使用大寫。

1.FROM

FROM指令的格式如下:

FROM [--platform=<platform>] <image> [AS <name>]

OR

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

OR

FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

FROM指令表示初始化一個新構(gòu)建并作為后續(xù)指令的基本映像,所以一個有效的Dockerfile文件必須以FROM指令開始,為個鏡像也必須是一個有效鏡像,可以從一些公用庫中來獲取相應(yīng)的鏡像。

但ARG可以放在FROM指令前面,關(guān)于ARG和FROM如何交互將會在后面介紹。

FROM可以在單個Dockerfile中多出現(xiàn),這樣可以創(chuàng)建多個映像,或?qū)⒁粋€構(gòu)建階段用作另一個構(gòu)建階段的依賴庫。

FROM指令可以支持由其上一個指令ARG指令聲明的變量,并傳遞給FROM指令使用。

ARG CODE_VERSION=latest

FROM base:${CODE_VERSION}

CMD /code/run-app

FROM extras:${CODE_VERSION}

CMD /code/run-extras

2.RUN

RUN指令有兩種運行方式:

#shell格式:

RUN <command>

#exec格式:

RUN ["executable", "param1", "param2"]

# 例如:

# RUN ["./test.php", "dev", "offline"] 等價于 RUN ./test.php dev offline

注意:Dockerfile的指令每執(zhí)行一次都會在docker上新建一層,所以過多無意義的層,會造成鏡像膨脹過大。

如上,以 && 符號連接命令,這樣執(zhí)行后,只會創(chuàng)建 1 層鏡像。

3.CMD

CMD指令用于指定一個容器啟動時所運行的命令,這有點類似于RUN指令,但RUN指令是指定鏡像被構(gòu)建時要運行的命令,而CMD是指容器啟動時所要運行的命令,CMD指令有三種形式。

#exec格式 CMD ["executable","param1","param2"]

# 該寫法是為 ENTRYPOINT 指令指定的程序提供默認參數(shù) CMD ["param1","param2"]

#shell格式 CMD command param1 param2

一般推薦使用第一種格式,執(zhí)行過程清晰明確。第三種格式其實在運行過程中也會轉(zhuǎn)換成第一種格式運行,并且默認可執(zhí)行文件是sh。

CMD和使用docker run命令啟動容器時指定運行命令幾乎一致。

#如在Dockerfile文件中寫以下指令

CMD ["/bin/true"]

#上面這個CMD等同以下面的run指令

root@ubunhomhome/test# docker run -it nginx /bin/true

在Dockerfile中只能有一個CMD指令,即使如果有多個CMD指令,也只有最后一個CMD才會生效。

CMD指令主要是為執(zhí)行中的容器提供默認值,這些默認值可以包含可執(zhí)行文件,也可以省略可執(zhí)行文件,在這種情況下,就必須指定一條ENTRYPOINT指令。

如果用戶在使用docker run指定參數(shù)時,則它們將會覆蓋Dockerfile文件中的CMD參數(shù)默認值。

4.LABEL

LABEL指令用來給鏡像添加一些元數(shù)據(jù)(metadata),以鍵值對的形式,語法格式如下:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

如果LABEL值中需要跨多行,則需要加入反斜杠和引號。

一個鏡像可以有多個標簽,可以在一行上指定多個標簽,有以下兩種方式可以實現(xiàn)。

5.EXPOSE

該指令用于聲明監(jiān)聽的端口號,在監(jiān)聽是可以指定是TCP還是UDP協(xié)議,默認值為TCP,其主要有以下作用:

幫助鏡像使用理解這個鏡像服務(wù)的守護端口,以方便配置映射。

在運行時使用隨時端口映射,也就是docker run -P時,會自動隨機映射EXPOSE的端口。

EXPOSE指令實際上并未發(fā)布指定端口,它是將我們訪問時輸入的端口和運行容器之間做一種關(guān)聯(lián)或通信,具體發(fā)布哪些端口,要在運行容器時發(fā)布實際端口,可以使用docker run中-p或-P來設(shè)置映射的端口號。

默認情況下一般如果我們未指定協(xié)議的話,那么都是使用TCP協(xié)議,當然也可以指定具體的協(xié)議,也可以同時指定TCP和UDP協(xié)議。

EXPOSE 80/tcp

EXPOSE 80/udp

6.ENV

設(shè)置環(huán)境變量,定義了環(huán)境變量,這樣在后續(xù)的指令中,就可以使用這個環(huán)境變量。如果在環(huán)境變量引用過程中包含空格,那么需要使用到反斜杠。

其語法格式如下:

ENV <key> <value>

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

ENV MY_NAME="John Doe"

ENV MY_DOG=Rex\ The\ Dog

ENV MY_CAT=fluffy

使用ENV設(shè)置的環(huán)境變量會保留下來,當容器運行時可以使用docker inspect查看值,并且可以使用docker run --env = 更改環(huán)境變量的值。

如果僅僅是在構(gòu)建過程中需要環(huán)境變量,而在最終映像中不需要,可以考慮為單個命令設(shè)置一個值或使用ARG,ARG指令不會人保留在最終鏡像中。

ARG DEBIAN_FRONTEND=noninteractive

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

7.ARG

ARG構(gòu)建參數(shù)與ENV作用一致,不過作用域不一樣,ARG設(shè)置的環(huán)境變量僅對Dockerfile內(nèi)有效,也就是說只有docker build的過程中有效,構(gòu)建好的鏡像內(nèi)不存在此環(huán)境變量。

構(gòu)建命令docker build中可以用--build-arg <參數(shù)名>=<值>來覆蓋,ARG指令格式如下:

ARG <參數(shù)名>[=默認值]

如果ARG指令具有默認值,并且在構(gòu)建時未傳遞任何值,則構(gòu)建時會使用默認值,相反如果未設(shè)置默認值,并且在構(gòu)建中未傳遞任何值,那么構(gòu)建時會輸出警告信息。

8.ADD

ADD指令是指將宿主機的文件或目錄復制到鏡像文件系統(tǒng)中指定的路徑,其語法格式有兩種:

ADD [--chown=<user>:<group>] <src>... <dest>

ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

每個可以使用通配符,并且匹配將使用Go的filepath.Match規(guī)則進行,例如:

要添加所有以“hom”開頭的文件:

ADD hom* /mydir/

“?”可以替換任意一個字符,例如:

ADD hom?.txt /mydir/

是指構(gòu)建容器的路徑,可以是絕對路徑,也可以是相對路徑,但這個相對路徑是相對于WORKDIR的路徑。如以下示例是將“test.txt”文件添加到/relativeDir/。

ADD test.txt relativeDir/

下面的示例則是將“test.txt”添加到相對路徑/absoluteDie/中。

ADD test.txt /absoluteDir/

如果路徑中包含一些特字符,那么需要按照Golang規(guī)則轉(zhuǎn)義那些路徑,以防止在解析過程中將它們視為匹配的模式,如要添加名為sarr[1].txt的文件。

ADD sarr[[]1].txt /mydir/

路徑必須是構(gòu)建內(nèi)容的一個內(nèi)部路徑,不能添加類似于ADD ../path /path,因為docker build的第一步是將上下文目錄和子目錄發(fā)送到docker守護進程。

如果是URL,而不以斜杠結(jié)尾,則從URL下載文件并將其復制到。

如果是URL,而以斜杠結(jié)尾,則從URL推斷文件名,并將文件下載到/,例如ADD http://chuanshi.com/foobar /,將創(chuàng)建文件/foobar,該URL必須具有正確的路徑,以便在這種情況下可以找到適當?shù)奈募?/p>

如果是目錄,則復制目錄的整個內(nèi)容,包括文件系統(tǒng)元數(shù)據(jù)。

如果是任何其他類型的文件,則會將其及其元數(shù)據(jù)一起單獨復制,在這種情況下,如果以斜杠結(jié)尾,則它將被視為目錄,并且的內(nèi)容將被寫在/base()中。

如果直接或由于使用通配符而指定多個資源,則必須是目錄,并且必須以斜杠結(jié)尾。

如果不以斜杠結(jié)尾,則將其視為常規(guī)文件,并且的內(nèi)容將被寫入。

如果不存在,則會與路徑中所有缺少的目錄一起創(chuàng)建它。

1.ADD的優(yōu)點:在執(zhí)行為tar壓縮文件的話,壓縮格式為gzip、gzip2以及xz的情況下,會自動復制并解壓到。

2.ADD的缺點:在不解壓的前提下,無法復制tar壓縮文件,會令鏡像構(gòu)建緩存失效,從而可能會令鏡像構(gòu)建變得比較緩慢,具體是否使用,可以根據(jù)是否需要自動解壓來決定。

9.COPY

復制指令,從上下文目錄中復制文件或者目錄到容器里指定路徑,通常有以下兩種格式:

COPY [--chown=<user>:<group>] <src>... <dest>

COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

COPY指令表示從復制新文件或目錄,并將它們添加到容器的文件系統(tǒng)中,路徑為。

可以指定多個資源,但是文件和目錄的路徑將被解釋為相對于構(gòu)建上下文。

每個可能包含通配 符,并且匹配將合作Go人filepath.Match規(guī)則進行。

例如要添加所有"hom"開頭的文件:

COPY home* /mydir/

"?"表示可以匹配任意一個字符:

COPY hom?.txt /mydir/

是指構(gòu)建容器的路徑,可以是絕對路徑,也可以是相對路徑,但這個相對路徑是相對于WORKDIR的路徑。如以下示例是將“test.txt”文件添加到/relativeDir/。

COPY test.txt relativeDir/

下面的示例則是將“test.txt”添加到相對路徑/absoluteDie/中。

COPY test.txt /absoluteDir/

如果路徑中包含一些特字符,那么需要按照Golang規(guī)則轉(zhuǎn)義那些路徑,以防止在解析過程中將它們視為匹配的模式,如要添加名為sarr[1].txt的文件。

COPY sarr[[]1].txt /mydir/

路徑必須是構(gòu)建內(nèi)容的一個內(nèi)部路徑,不能添加類似于COPY ../path /path,因為docker build的第一步是將上下文目錄和子目錄發(fā)送到docker守護進程。

如果是目錄,則復制目錄的整個內(nèi)容,包括文件系統(tǒng)無數(shù)據(jù),目錄本身不會被復制,只是其內(nèi)容被復制。

如果是任何其他類型的文件,則會將其及其元數(shù)據(jù)一起單獨復制,在這種情況下,如果以斜杠結(jié)尾,則它將被視為目錄,并且的內(nèi)容將被寫在/base()中。

如果直接或由于使用通配符而指定多個資源,則必須是目錄,并且必須以斜杠結(jié)尾。

如果不以斜杠結(jié)尾,則將其視為常規(guī)文件,并且的內(nèi)容將被寫入。

如果不存在,則會與路徑中所有缺少的目錄一起創(chuàng)建它。

10.ENTRYPOINT

類似于CMD指令,但其不會被docker run指令運行參數(shù)所覆蓋,并且這些命令行參數(shù)會被當作參數(shù)送給ENTRYPOINT指令指定的程序。

但是如果運行docker run時使用了--entrypoint選項,將覆蓋CMD指令指定的程序。

其語法格式有以下兩種:

#exec格式

ENTRYPOINT ["executable", "param1", "param2"]

#shell格式

ENTRYPOINT command param1 param2

ENTRYPOINT的優(yōu)點在執(zhí)行docker run的時候可以指定ENTRYPOINT運行所需要的參數(shù)。

但如果Dockerfile中如果存在多個ENTRYPOINT指令時,只有最后一個會生效。

可以將ENTRYPOINT與CMD命令搭配使用,一般是變參才會使用CMD,這里的CMD等于是在給ENTRYPOINT傳參。

例如,通過Dockerfile構(gòu)建了一個nginx:V1.0的鏡像。

FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定參

CMD ["/etc/nginx/nginx.conf"] # 變參

如果在運行容器時,不傳參運行,

root@ubunhomhome/test# docker run -it nginx:v1.0

容器內(nèi)則會默認運行以下命令,啟動主進程。

nginx -c /etc/nginx/nginx.conf

如果在運行容器時傳參運行,

root@ubunhomhome/test# docker run -it nginx:v1.0 -c /etc/nginx/new_nginx.conf

容器內(nèi)會默認運行以下命令,啟動主進程。

nginx -c /etc/nginxnew_nginx.conf

11.VOLUME

VOLUME指令在后面的章節(jié)會進行詳細的介紹,在本小節(jié)中不做介紹

12.USER

USER指令用于指定執(zhí)行后續(xù)命令的用戶和用戶組,這邊只是切換后續(xù)指令執(zhí)行的用戶(用戶和用戶組必須提前已經(jīng)存在)。其語法格式如下:

USER <user>[:<group>]

#or

USER <UID>[:<GID>]

13.WORKDIR

WORKDIR指令表示指定工作目錄,該指定的目錄必須提前創(chuàng)建好,docker build構(gòu)建鏡像過程中的,每個RUN命令都是新建的一層,只有通過WORKDIR創(chuàng)建才會一直存在。其語法格式如下:

WORKDIR /path/to/workdir

WORKDIR指令可在Dockerfile中多次使用,如果提供了相對路徑,則它將相對于上一個WORKDIR指令的路徑來創(chuàng)建目錄,如:

WORKDIR /a

WORKDIR b

WORKDIR c

RUN pwd

該Dockerfile中最后一個pwd命令的輸出為/a/b/c。

WORKDIR指令也可以解析ENV設(shè)置的環(huán)境變量,如:

ENV DIRPATH=/path

WORKDIR $DIRPATH/$DIRNAME

RUN pwd

該Dockerfile中最后一個pwd命令的輸出為/path/$DIRNAME。

?著作權(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)容