FROM 指定基礎(chǔ)鏡像
基礎(chǔ)鏡像是構(gòu)建鏡像的起點(diǎn),定制鏡像都需要以一個(gè)鏡像為基礎(chǔ),然后對(duì)其進(jìn)行修改,F(xiàn)rom就是用來(lái)指定基礎(chǔ)鏡像的,因此Dockerfile中From是必備的指令,而且必須是第一條。
Docker中存在一個(gè)特殊鏡像名為 scratch 這個(gè)鏡像并不存在,僅表示一個(gè)空白的鏡像,下一條指令會(huì)作為鏡像的第一層存在。
FROM 指令還可以用于實(shí)現(xiàn)多段構(gòu)建,這在需要進(jìn)行多個(gè)步驟來(lái)構(gòu)建鏡像時(shí)非常有用。例如,在第一個(gè)階段構(gòu)建代碼,第二個(gè)階段將構(gòu)建的代碼復(fù)制到最終鏡像中。多階段構(gòu)建可以減小最終鏡像的大小,因?yàn)橹挥袠?gòu)建時(shí)需要的文件和依賴(lài)項(xiàng)才會(huì)被包含在鏡像中,而構(gòu)建過(guò)程中生成的臨時(shí)文件則會(huì)被丟棄。
示例:
創(chuàng)建docker文件夾,并在目錄下創(chuàng)建Dockerfile文件
mkdir docker
cd docker
vim Dockerfile
在Dockerfile中寫(xiě)入:
# 第一個(gè)階段:構(gòu)建二進(jìn)制文件
FROM golang:latest AS builder
# 指定工作目錄
WORKDIR /app
# 將上下文路徑內(nèi)容復(fù)制到工作目錄
COPY . .
# 編譯二進(jìn)制文件
RUN go env -w GO111MODULE=off \
&& go build hello.go
# 第二個(gè)階段:構(gòu)建最終鏡像
FROM ubuntu:18.04
WORKDIR /root/
# 從第一個(gè)階段復(fù)制二進(jìn)制文件到最終鏡像中
COPY --from=builder /app/hello .
# 設(shè)置容器啟動(dòng)命令
CMD ["./hello"]
再創(chuàng)建一個(gè)go文件
vim hello.go
寫(xiě)入:
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
執(zhí)行:
docker build -t hello-world:v1 .
docker run --rm hello-world:v1
可以看到輸出Hello World 。
用docker history 指令查看創(chuàng)建的鏡像,只看到最后一個(gè)FROM后的指令:
docker history hello-world:v1
RUN 執(zhí)行命令
RUN指令用于在鏡像構(gòu)建過(guò)程中執(zhí)行命令,有兩種語(yǔ)法格式:
shell 格式:
RUN <command>
示例:
RUN apt-get update && apt-get install -y \
package1 \
package2 \
package3
exec 格式:
RUN ["executable", "param1", "param2"...]
示例:
RUN ["apt-get", "update"]
RUN ["apt-get", "install", "-y", "package1", "package2", "package3"]
緩存機(jī)制:當(dāng)使用Dockerfile構(gòu)建鏡像時(shí),Docker會(huì)檢查每一步的緩存。如果之前已經(jīng)構(gòu)建過(guò)相同的鏡像且鏡像層沒(méi)有發(fā)生變化,Docker會(huì)直接復(fù)用之前的鏡像層,避免重復(fù)的構(gòu)建工作,加快鏡像的構(gòu)建速度。
COPY 復(fù)制文件
格式如下:
COPY <源路徑>... <目標(biāo)路徑> // 格式1
COPY ["源路徑",..."目標(biāo)路徑"] //格式2
源路徑以上下文路徑為基礎(chǔ)。
…指可以有多個(gè)源路徑,但是目標(biāo)路徑只能有一個(gè)。
如果源路徑為文件夾,復(fù)制的時(shí)候不是直接復(fù)制該文件夾,而是將文件夾中的內(nèi)容復(fù)制到目標(biāo)路徑。
源路徑可以是通配符,但是需要滿(mǎn)足GO的filepath.Match規(guī)則
示例:
COPY hom* /mydir/
COPY hom?.txt /mydir/
默認(rèn)情況下,COPY 指令會(huì)保留文件或目錄的原始權(quán)限和所有者。如果需要更改文件的權(quán)限或所有者,可以使用 --chown選項(xiàng)。
COPY [--chown=<user>:<group>] <源路徑>... <目標(biāo)路徑>
COPY [--chown=<user>:<group>] ["<源路徑>",... "<目標(biāo)路徑>"]
在多段構(gòu)建時(shí)可以使用–from選項(xiàng)來(lái)指定從某個(gè)階段復(fù)制文件。
COPY [--from=builderName] <源路徑>... <目標(biāo)路徑>
COPY [--from=builderName] ["<源路徑>",... "<目標(biāo)路徑>"]
ADD 高級(jí)文件復(fù)制
ADD指令與 COPY指令類(lèi)似,都是用于將文件或目錄從主機(jī)(構(gòu)建上下文)復(fù)制到 Docker 鏡像中的指定位置。但 ADD
指令在功能上更加強(qiáng)大,它除了復(fù)制文件外,還支持自動(dòng)解壓縮壓縮包、支持 URL 地址。
ADD [--chown=<user>:<group>] <源路徑>... <目標(biāo)路徑>
如果源路徑是一個(gè)壓縮文件(.tar
, .tar.gz
, .tgz
, .tar.bz2
, .tbz2
, .tar.xz
, .txz
, .zip
)會(huì)被自動(dòng)解壓縮到目標(biāo)路徑
如果源路徑是一個(gè)URL,會(huì)被下載到目標(biāo)路徑。
注:ADD 會(huì)使鏡像緩存失效,可能會(huì)導(dǎo)致鏡像構(gòu)建緩慢。在復(fù)制文件時(shí),應(yīng)當(dāng)盡可能使用COPY,僅在需要自動(dòng)解壓縮的場(chǎng)景使用ADD。
CMD 容器啟動(dòng)命令
格式與RUN相近:
CMD <command> // shell格式
CMD ["executable", "param1", "param2"...] // exec格式
CMD 命令用于指定容器啟動(dòng)時(shí)執(zhí)行的默認(rèn)命令。
如果在 Dockerfile 中有多個(gè) CMD 指令,則只有最后一個(gè)會(huì)生效。
通常情況下,推薦使用 Exec 格式,因?yàn)樗用鞔_和可靠。Shell 形式可能會(huì)受到 shell 環(huán)境的影響,而且可能會(huì)導(dǎo)致一些不可預(yù)測(cè)的問(wèn)題。
容器中的應(yīng)用都應(yīng)該以前臺(tái)執(zhí)行,容器沒(méi)有后臺(tái)的概念,如果后臺(tái)執(zhí)行可能會(huì)導(dǎo)致容器退出。
docker run 提供的參數(shù)列表會(huì)覆蓋掉CMD的參數(shù)列表,如:
在Dockerfile中寫(xiě)入:
FROM ubuntu:18.04
CMD ["echo","Hello"]
執(zhí)行:
docker build -t hello:v1 .
docker run --rm hello:v1 "echo" "hello world"
可以看到容器輸出 hello world 而不是 Hello
ENTRYPOINT 入口點(diǎn)
格式與CMD相近:
ENTRYPOINT <command> // shell格式
ENTRYPOINT ["executable", "param1", "param2"...] // exec格式
ENTRYPOINT指令和CMD指令都是指定容器啟動(dòng)時(shí)的指令和參數(shù),但docker run 提供的參數(shù)列表不會(huì)覆蓋掉ENTRYPOINT的參數(shù)列表,而是會(huì)添加到參數(shù)列表后,如:
在Dockerfile中寫(xiě)入:
FROM ubuntu:18.04
ENTRYPOINT ["echo","Hello"]
執(zhí)行:
docker build -t hello:v2 .
docker run --rm hello:v2 "World"
可以看到容器輸出 Hello World
當(dāng)CMD與ENTRYPOIN一起使用時(shí),CMD的參數(shù)會(huì)傳給ENTRYPOINT,如:
在Dockerfile中寫(xiě)入:
FROM ubuntu:18.04
ENTRYPOINT ["echo","Hello"]
CMD ["World"]
執(zhí)行:
docker build -t hello:v3 .
docker run --rm hello:v3
可以看到容器輸出Hello World。
–rm選項(xiàng)刪除了容器,鏡像還在,可以使用下面指令刪除掉剛剛創(chuàng)建的幾個(gè)鏡像:
docker image rm $(docker image ls hello -q)
ENV 設(shè)置環(huán)境變量
ENV 指令用于在 Dockerfile 中設(shè)置環(huán)境變量,類(lèi)似給一個(gè)值設(shè)置別名。ENV設(shè)置的環(huán)境變量可以在容器運(yùn)行時(shí)被應(yīng)用程序使用。ENV 指令的基本語(yǔ)法如下:
ENV <key> <value> // 格式1
ENV <key1>=<value1> <key2>=<value2>... // 格式2
示例:
在Dockerfile寫(xiě)入:
FROM ubuntu:18.04
ENV HW Hello_World
RUN ["echo","$HW"]
執(zhí)行:
docker build -t hw:v1 .
可以在構(gòu)建信息中看到,RUN指令的參數(shù)列表實(shí)際為[“echo”,“Hello World”]
=> [2/2] RUN ["echo","Hello_World"]
下列指令可以支持環(huán)境變量展開(kāi): ADD
、COPY
、ENV
、EXPOSE
、FROM
、LABEL
、USER
、WORKDIR
、VOLUME
、STOPSIGNAL
、ONBUILD
、RUN
。
不支持的有:CMD
、ENTRYPOINT
注:FROM雖然支持展開(kāi),但ENV不能在第一行,否則會(huì)輸出錯(cuò)誤:
ERROR: failed to solve: no build stage in current context
ARG 構(gòu)建參數(shù)
格式:
ARG <參數(shù)名>[=<默認(rèn)值>]
ARG 與 ENV 的效果一樣,都是設(shè)置環(huán)境變量,區(qū)別是ARG在容器運(yùn)行時(shí)無(wú)效,僅在構(gòu)建過(guò)程中生效。
ARG用于構(gòu)建過(guò)程中的參數(shù)傳遞,使用這個(gè)指令并不創(chuàng)建新的層,因此可以在第一個(gè)FROM之前使用,而 ENV 是用于設(shè)置鏡像和容器的運(yùn)行環(huán)境,會(huì)創(chuàng)建新的層,因此必須在 FROM之后使用。
生效范圍:若在第一個(gè)FROM之前指定,則僅在每個(gè)FROM指令中生效。在多段構(gòu)建中,F(xiàn)ROM后指定的ARG只在當(dāng)前階段生效。
注:ARG的參數(shù)可以在構(gòu)建命令 docker build
中用 --build-arg <參數(shù)名>=<值>
來(lái)覆蓋。
靈活的使用 ARG
指令,能夠在不修改 Dockerfile 的情況下,構(gòu)建出不同的鏡像。
VOLUME 定義匿名卷
格式:
VOLUME <路徑>
VOLUME ["<路徑1>", "<路徑2>"...]
容器運(yùn)行時(shí)應(yīng)該盡量保持容器存儲(chǔ)層不發(fā)生寫(xiě)操作,對(duì)于動(dòng)態(tài)的數(shù)據(jù)應(yīng)當(dāng)保存在VOLUME中。在 Docker 中,Volume(卷)是用于持久化存儲(chǔ)數(shù)據(jù)的機(jī)制,允許容器與宿主機(jī)之間共享數(shù)據(jù)。Volumes 可以在容器的生命周期內(nèi)持續(xù)存在,即使容器被刪除,數(shù)據(jù)也可以保留在宿主機(jī)上。
如:
VOLUME /data
在容器中任何對(duì)/data文件夾的寫(xiě)入都不會(huì)記錄在容器存儲(chǔ)層,而是保存在宿主機(jī)的/data文件夾中,而容器從宿主機(jī)中讀取數(shù)據(jù)。
EXPOSE 聲明端口
格式:
EXPOSE <端口1> [<端口2>...]
EXPOSE 僅用于說(shuō)明該容器運(yùn)行時(shí)的有哪些提供服務(wù)的端口,并無(wú)實(shí)際用處,類(lèi)似于注釋提高可讀性。該指令與ARG指令一樣并不會(huì)新建層。
若需要暴露容器端口并映射到宿主機(jī)端口需要在docker run時(shí)使用-p <宿主端口>:<容器端口>
選項(xiàng):
如:
docker run --name web -d -p 8000:80 nginx
WORKDIR 指定工作目錄
WORKDIR 指令用于指定工作目錄,以后各層的當(dāng)前目錄就被改為指定的目錄
如該目錄不存在,WORKDIR
會(huì)新建目錄。
可以使用絕對(duì)路徑或相對(duì)路徑來(lái)指定工作目錄。如果使用相對(duì)路徑,則會(huì)相對(duì)于上一個(gè) WORKDIR
指令設(shè)置的目錄。
如:
WORKDIR /hello
WORKDIR world
RUN pwd
RUN pwd
的工作目錄為 /hello/world
。
USER 指定當(dāng)前用戶(hù)
格式:
USER <用戶(hù)名>[:<用戶(hù)組>]
USER 指令和 WORKDIR 相似,都是改變環(huán)境狀態(tài)并影響以后的層。WORKDIR 是改變工作目錄,USER 則是改變之后層的執(zhí)行 RUN, CMD以及 ENTRYPOINT這類(lèi)命令的身份。
注:USER 只是切換到指定用戶(hù)而已,這個(gè)用戶(hù)必須是事先建立好的,否則無(wú)法切換。
HEALTHCHECK 健康檢查
格式:
HEALTHCHECK [選項(xiàng)] CMD <命令> // 設(shè)置檢查容器健康狀況的命令
HEALTHCHECK NONE // 屏蔽基礎(chǔ)鏡像的健康檢查指令
Docker 的 HEALTHCHECK 是用于在容器運(yùn)行時(shí)檢查容器內(nèi)服務(wù)或應(yīng)用程序的狀態(tài)的機(jī)制。通過(guò) HEALTHCHECK,可以告訴 Docker 應(yīng)該如何進(jìn)行判斷容器的狀態(tài)是否正常。沒(méi)有HEALTHCHECK指令時(shí),Docker只會(huì)在主進(jìn)程退出時(shí)認(rèn)為容器狀態(tài)不正常,而進(jìn)程陷入死鎖或者死循環(huán)等不正常狀態(tài)時(shí)Docker不會(huì)理會(huì)。
選項(xiàng):
--interval=<間隔>
:兩次健康檢查的間隔,默認(rèn)為 30 秒;--timeout=<時(shí)長(zhǎng)>
:健康檢查命令運(yùn)行超時(shí)時(shí)間,如果超過(guò)這個(gè)時(shí)間,本次健康檢查就被視為失敗,默認(rèn) 30 秒;--retries=<次數(shù)>
:當(dāng)連續(xù)失敗指定次數(shù)后,則將容器狀態(tài)視為unhealthy
,默認(rèn) 3 次。
HEALTHCHECK指令只有最后一條生效,后面的會(huì)覆蓋掉前面的。
CMD格式與CMD指令一致,需要有返回值,命令的返回值決定這次HEALTHCHECK的結(jié)果:0
:成功;1
:失??;2
:保留,不要使用這個(gè)值。
如:
HEALTHCHECK CMD <command> || exit <code>
||
: Shell 中的邏輯 OR 運(yùn)算符,表示如果前面的命令失?。ǚ祷胤橇阃顺龃a),則執(zhí)行接下來(lái)的命令。
exit <code>
:用于退出當(dāng)前腳本,并且返回一個(gè)退出碼。
健康檢查命令的輸出(包括 stdout
以及 stderr
)都會(huì)被存儲(chǔ)于健康狀態(tài)里,可以用 docker inspect
來(lái)查看:
docker inspect --format '{{json .State.Health}}' <container_name>
可以在命令末尾添加json工具命令進(jìn)行格式化輸出,如:
docker inspect --format '{{json .State.Health}}' <container_name> | python -m json.tool
ONBUILD 構(gòu)建觸發(fā)器
ONBUILD
用于定義鏡像構(gòu)建觸發(fā)器,當(dāng)一個(gè)鏡像包含 ONBUILD
指令時(shí),這個(gè)指令將不會(huì)立即執(zhí)行,而是在該鏡像作為另一個(gè)鏡像的基礎(chǔ)鏡像(父鏡像)進(jìn)行構(gòu)建時(shí)觸發(fā)。當(dāng)需要構(gòu)建多個(gè)鏡像,但各個(gè)鏡像中有重復(fù)部分的場(chǎng)景,就可以使用ONBUILD構(gòu)建一個(gè)基礎(chǔ)鏡像,然后其他鏡像以這個(gè)基礎(chǔ)鏡像進(jìn)行構(gòu)建。這樣的好處在于減少重復(fù)代碼的編寫(xiě),并且如果基礎(chǔ)鏡像出現(xiàn)錯(cuò)誤或者紕漏時(shí),只需修改基礎(chǔ)鏡像并根據(jù)Dockerfile重新構(gòu)建其他鏡像即可,這無(wú)疑大大提高了鏡像的可維護(hù)性與Dockerfile的編寫(xiě)效率。
示例:
在docker文件夾外,新建文件夾baseDocker并創(chuàng)建一個(gè)Dockerfile:
mkdir baseDocker
cd baseDocker
vim Dockerfile
輸入:
FROM golang:latest
WORKDIR /app
ONBUILD COPY . .
ONBUILD RUN go env -w GO111MODULE=off \
&& go build hello.go
執(zhí)行:
docker build -t base:v1 .
回到docker文件夾在Dockerfile中輸入:
# ONBUILD構(gòu)建的基礎(chǔ)鏡像
FROM base:v1 AS builder
FROM ubuntu:18.04
WORKDIR /root/
COPY --from=builder /app/hello .
CMD ["./hello"]
執(zhí)行:
docker build -t hello-world:v1 .
docker run --rm hello-world:v1
可以看到容器輸出Hello World。
ONBUILD的指令會(huì)延遲到作為父鏡像構(gòu)建新鏡像時(shí)執(zhí)行,這樣可以獲取到足夠的信息。比如上下文路徑,如果不使用ONBUILD ,構(gòu)建基礎(chǔ)鏡像時(shí)的上下文路徑已經(jīng)定死了,后續(xù)鏡像只能在基礎(chǔ)鏡像的上下文路徑中構(gòu)建,這顯然是不可行的。
LABEL 添加元數(shù)據(jù)
格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
LABEL
指令用于向 Docker 鏡像添加元數(shù)據(jù),通常用來(lái)提供關(guān)于鏡像的描述信息、版本信息、維護(hù)者信息等。這些標(biāo)簽信息可以幫助用戶(hù)更好地理解和使用鏡像,也可以在構(gòu)建鏡像時(shí)提供一些有用的信息。
注:LABEL也會(huì)新建一層,所以盡可能使用一個(gè)LABEL避免鏡像臃腫。
如果在第一個(gè)FROM前使用LABEL會(huì)輸出錯(cuò)誤:
ERROR: failed to solve: no build stage in current context
在Dockerfile中輸入:
FROM ubuntu:18.04
LABEL authors="bulo"
ENTRYPOINT ["echo","Hello"]
執(zhí)行:
docker build -t hello:v1 .
docker history hello:v1
可以看到LABEL指令創(chuàng)建的層
鏡像被添加的元數(shù)據(jù)也可以用 docker inspect
來(lái)查看:
docker inspect --format='{{json .Config.Labels}}' <image_name>
執(zhí)行:
docker inspect --format='{{json .Config.Labels}}' hello:v1
SHELL 指定解釋器
格式:
SHELL ["executable", "parameters"]
SHELL
指令用于設(shè)置 Dockerfile 中后續(xù)指令的默認(rèn)解釋器,比如在執(zhí)行 RUN
、CMD
、ENTRYPOINT
等命令時(shí)使用的 Shell 解釋器。默認(rèn)情況下,Docker 使用 /bin/sh -c
作為默認(rèn)的 Shell 解釋器。
如使用bash作為默認(rèn)解釋器:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-853282.html
SHELL ["/bin/bash", "-c"]
PS:阿巴阿巴阿巴…文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-853282.html
到了這里,關(guān)于Docker學(xué)習(xí)筆記(三)Dockerfile指令詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!