對(duì)Docker 構(gòu)建上下文的理解誤區(qū)
我們都知道,構(gòu)建一個(gè) Docker 鏡像非常簡(jiǎn)單,大家一般都會(huì)這么做(當(dāng)然這么做是完全正確的):
- 1.跳到 Dockerfile 所在目錄;
- 2.執(zhí)行 docker build 構(gòu)建命令:
docker build -t <imageName:imageTag> .
通過(guò)上面的工作流,很容易形成這樣的理解誤區(qū):
- docker build 后面的 . 為 Dockerfile 所在的目錄;
- Dockerfile 文件名 必須為 Dockerfile;
其實(shí)上面這種理解是錯(cuò)誤的,要想準(zhǔn)確理解其含義,首先我們需要先了解下 Docker 的架構(gòu)和 docker build 的工作原理。
理解 Docker 的架構(gòu)
Docker 是一個(gè)典型的 C/S 架構(gòu)的應(yīng)用,分為 Docker 客戶端(即平時(shí)敲的 docker 命令) Docker 服務(wù)端(dockerd 守護(hù)進(jìn)程)。
Docker 客戶端通過(guò) REST API 和服務(wù)端進(jìn)行交互,docker 客戶端每發(fā)送一條指令,底層都會(huì)轉(zhuǎn)化成 REST API 調(diào)用的形式發(fā)送給服務(wù)端,服務(wù)端處理客戶端發(fā)送的請(qǐng)求并給出響應(yīng)。
Docker 鏡像的構(gòu)建、容器創(chuàng)建、容器運(yùn)行等工作都是 Docker 服務(wù)端來(lái)完成的,Docker 客戶端只是承擔(dān)發(fā)送指令的角色。
Docker 客戶端和服務(wù)端可以在同一個(gè)宿主機(jī),也可以在不同的宿主機(jī),如果在同一個(gè)宿主機(jī)的話,Docker 客戶端默認(rèn)通過(guò) UNIX 套接字(/var/run/docker.sock)和服務(wù)端通信。
文章來(lái)自 https://blog.csdn.net/qianghaohao/article/details/87554255
理解 docker build 的工作原理
理解了 Docker 的架構(gòu)就很容易理解 docker build 構(gòu)建鏡像的工作原理了。docker build 構(gòu)建鏡像的流程大概如下:
執(zhí)行 docker build -t <imageName:imageTag> . ;
Docker 客戶端會(huì)將構(gòu)建命令后面指定的路徑(.)下的所有文件打包成一個(gè) tar 包,發(fā)送給 Docker 服務(wù)端;
Docker 服務(wù)端收到客戶端發(fā)送的 tar 包,然后解壓,根據(jù) Dockerfile 里面的指令進(jìn)行鏡像的分層構(gòu)建;
正確理解 Docker 構(gòu)建上下文
了解了 Docker 的架構(gòu)和鏡像構(gòu)建的工作原理后,Docker 構(gòu)建上下文也就容易理解了。Docker 構(gòu)建上下文就是 Docker 客戶端上傳給服務(wù)端的 tar 文件解壓后的內(nèi)容,也即 docker build 命令行后面指定路徑下的文件。
Docker 鏡像的構(gòu)建是在遠(yuǎn)程服務(wù)端進(jìn)行的,所以客戶端需要把構(gòu)建所需要的文件傳輸給服務(wù)端。服務(wù)端以客戶端發(fā)送的文件為上下文,也就是說(shuō) Dockerfile 中指令的工作目錄就是服務(wù)端解壓客戶端傳輸?shù)?tar 包的路徑。
關(guān)于 docker build 指令的幾點(diǎn)重要的說(shuō)明:
如果構(gòu)建鏡像時(shí)沒(méi)有明確指定 Dockerfile,那么 Docker 客戶端默認(rèn)在構(gòu)建鏡像時(shí)指定的上下文路徑下找名字為 Dockerfile 的構(gòu)建文件;
Dockerfile 可以不在構(gòu)建上下文路徑下,此時(shí)需要構(gòu)建時(shí)通過(guò) -f 參數(shù)明確指定使用哪個(gè)構(gòu)建文件,并且名稱可以自己任意命名。
下面通過(guò)具體的實(shí)例來(lái)理解下:
首先創(chuàng)建一個(gè)簡(jiǎn)單的 demo 工程,工程結(jié)構(gòu)如下:
helloworld-app
├── Dockerfile
└── docker
├── app-1.0-SNAPSHOT.jar
├── hello.txt
└── html
└── index.html
Dockerfile 內(nèi)容:
FROM busybox
COPY hello.txt .
COPY html/index.html .
實(shí)踐1:直接進(jìn)入 helloworld-app 目錄進(jìn)行鏡像構(gòu)建,以 docker 目錄為構(gòu)建上下文:
$ docker build -t hello-app:1.0 docker
unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /Users/haohao/opensource/helloworld-app/docker/Dockerfile: no such file or directory
可以看出默認(rèn) docker 客戶端從 docker 構(gòu)建上下文路徑下找名字為 Dockerfile 的構(gòu)建文件。
實(shí)踐2:明確指定 Dockerfile 文件進(jìn)行鏡像構(gòu)建,還是以 docker 目錄為構(gòu)建上下文:
$ docker build -f Dockerfile -t hello-app:1.0 docker
Sending build context to Docker daemon 96.61MB
Step 1/3 : FROM busybox
---> d8233ab899d4
Step 2/3 : COPY hello.txt .
---> 3305fc373120
Step 3/3 : COPY html/index.html .
---> efdefc4e6eb2
Successfully built efdefc4e6eb2
Successfully tagged hello-app:1.0
從輸出結(jié)果可以得知:
- 構(gòu)建鏡像時(shí)客戶端會(huì)先給服務(wù)端發(fā)送構(gòu)建上下路徑下的內(nèi)容(即 docker 目錄下的文件);
- Dockerfile 可以不在構(gòu)建上下文路徑下;
- Dockerfile 中指令的工作目錄是服務(wù)端解壓客戶端傳輸?shù)?tar 包的路徑;
實(shí)踐3:以當(dāng)前目錄為構(gòu)建上下文路徑:
$ls
Dockerfile docker
$ docker build -t hello-app:2.0 .
Sending build context to Docker daemon 96.62MB
Step 1/3 : FROM busybox
---> d8233ab899d4
Step 2/3 : COPY hello.txt .
COPY failed: stat /var/lib/docker/tmp/docker-builder375982663/hello.txt: no such file or directory
可以看出:
- 鏡像構(gòu)建上下文路徑并不是 Dockerfile 文件所在的路徑;
- Dockerfile 中指令的工作目錄是服務(wù)端解壓客戶端傳輸?shù)?tar 包的路徑,因?yàn)?COPY 指令失敗了,意味著當(dāng)前目錄并沒(méi)有 hello.txt 文件;
————————————————
版權(quán)聲明:本文為CSDN博主「qhh0205」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qianghaohao/article/details/87554255
