【實踐】5.DOCKER之制作鏡像

1. 摘要

本文講解使用 Dockerfile 定制鏡像的方法缩滨,也介紹docker commit的使用方法兼搏。

2. 內(nèi)容

2.1 利用 commit 理解鏡像構(gòu)成

注意: docker commit 命令除了學(xué)習(xí)之外芹助,還有一些特殊的應(yīng)用場合励翼,比如被入侵后保存現(xiàn)場等缚去。但是,不要使用 docker commit 定制鏡像樟结,定制鏡像應(yīng)該使用 Dockerfile 來完成养交。如果你想要定制鏡像請查看下一小節(jié)。
鏡像是容器的基礎(chǔ)瓢宦,每次執(zhí)行 docker run 的時候都會指定哪個鏡像作為容器運行的基礎(chǔ)碎连。在之前的例子中,我們所使用的都是來自于 Docker Hub 的鏡像驮履。直接使用這些鏡像是可以滿足一定的需求鱼辙,而當(dāng)這些鏡像無法直接滿足需求時,我們就需要定制這些鏡像玫镐。接下來的幾節(jié)就將講解如何定制鏡像倒戏。
回顧一下之前我們學(xué)到的知識,鏡像是多層存儲恐似,每一層是在前一層的基礎(chǔ)上進(jìn)行的修改杜跷;而容器同樣也是多層存儲,是在以鏡像為基礎(chǔ)層矫夷,在其基礎(chǔ)上加一層作為容器運行時的存儲層葛闷。
現(xiàn)在讓我們以定制一個 Web 服務(wù)器為例子,來講解鏡像是如何構(gòu)建的双藕。

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

這條命令會用 nginx 鏡像啟動一個容器淑趾,命名為 webserver,并且映射了 80 端口忧陪,這樣我們可以用瀏覽器去訪問這個 nginx 服務(wù)器扣泊。

如果是在本機運行的 Docker,那么可以直接訪問:http://localhost 嘶摊,如果是在虛擬機旷赖、云服務(wù)器上安裝的 Docker,則需要將 localhost 換為虛擬機地址或者實際云服務(wù)器地址更卒。
直接用瀏覽器訪問的話等孵,我們會看到默認(rèn)的 Nginx 歡迎頁面。

現(xiàn)在蹂空,假設(shè)我們非常不喜歡這個歡迎頁面俯萌,我們希望改成歡迎 Docker 的文字,我們可以使用 docker exec 命令進(jìn)入容器上枕,修改其內(nèi)容咐熙。

$ docker exec -it webserver bash
root@3729b97e8226:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
root@3729b97e8226:/# exit
exit

我們以交互式終端方式進(jìn)入 webserver 容器,并執(zhí)行了 bash 命令辨萍,也就是獲得一個可操作的 Shell棋恼。
然后返弹,我們用 <h1>Hello, Docker!</h1> 覆蓋了 /usr/share/nginx/html/index.html 的內(nèi)容。
現(xiàn)在我們再刷新瀏覽器的話爪飘,會發(fā)現(xiàn)內(nèi)容被改變了义起。



我們修改了容器的文件,也就是改動了容器的存儲層师崎。我們可以通過 docker diff 命令看到具體的改動默终。

$ docker diff webserver
C /root
A /root/.bash_history
C /run
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp

現(xiàn)在我們定制好了變化,我們希望能將其保存下來形成鏡像犁罩。
要知道齐蔽,當(dāng)我們運行一個容器的時候(如果不使用卷的話),我們做的任何文件修改都會被記錄于容器存儲層里床估。而 Docker 提供了一個 docker commit 命令含滴,可以將容器的存儲層保存下來成為鏡像。換句話說丐巫,就是在原有鏡像的基礎(chǔ)上谈况,再疊加上容器的存儲層,并構(gòu)成新的鏡像鞋吉。以后我們運行這個新鏡像的時候鸦做,就會擁有原有容器最后的文件變化励烦。
docker commit 的語法格式為:

docker commit [選項] <容器ID或容器名> [<倉庫名>[:<標(biāo)簽>]]

我們可以用下面的命令將容器保存為鏡像:

$ docker commit \
    --author "Tao Wang <twang2218@gmail.com>" \
    --message "修改了默認(rèn)網(wǎng)頁" \
    webserver \
    nginx:v2
sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214

其中 --author 是指定修改的作者谓着,而 --message 則是記錄本次修改的內(nèi)容。這點和 git 版本控制相似坛掠,不過這里這些信息可以省略留空赊锚。

其中 --author 是指定修改的作者,而 --message 則是記錄本次修改的內(nèi)容屉栓。這點和 git 版本控制相似舷蒲,不過這里這些信息可以省略留空导坟。
我們可以在 docker image ls 中看到這個新定制的鏡像:

$ docker image ls nginx
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v2                  07e334659748        9 seconds ago       181.5 MB
nginx               1.11                05a60462f8ba        12 days ago         181.5 MB
nginx               latest              e43d811ce2f4        4 weeks ago         181.5 MB

我們還可以用 docker history 具體查看鏡像內(nèi)的歷史記錄帖池,如果比較 nginx:latest 的歷史記錄污朽,我們會發(fā)現(xiàn)新增了我們剛剛提交的這一層秉剑。

$ docker history nginx:v2
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
07e334659748        54 seconds ago      nginx -g daemon off;                            95 B                修改了默認(rèn)網(wǎng)頁
e43d811ce2f4        4 weeks ago         /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon    0 B
<missing>           4 weeks ago         /bin/sh -c #(nop)  EXPOSE 443/tcp 80/tcp        0 B
<missing>           4 weeks ago         /bin/sh -c ln -sf /dev/stdout /var/log/nginx/   22 B
<missing>           4 weeks ago         /bin/sh -c apt-key adv --keyserver hkp://pgp.   58.46 MB
<missing>           4 weeks ago         /bin/sh -c #(nop)  ENV NGINX_VERSION=1.11.5-1   0 B
<missing>           4 weeks ago         /bin/sh -c #(nop)  MAINTAINER NGINX Docker Ma   0 B
<missing>           4 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0 B
<missing>           4 weeks ago         /bin/sh -c #(nop) ADD file:23aa4f893e3288698c   123 MB

新的鏡像定制好后贰逾,我們可以來運行這個鏡像罚渐。

docker run --name web2 -d -p 81:80 nginx:v2

這里我們命名為新的服務(wù)為 web2明刷,并且映射到 81 端口鸯绿。訪問 http://localhost:81 看到結(jié)果启绰,其內(nèi)容應(yīng)該和之前修改后的 webserver 一樣昂儒。
至此,我們第一次完成了定制鏡像委可,使用的是 docker commit 命令渊跋,手動操作給舊的鏡像添加了新的一層,形成新的鏡像,對鏡像多層存儲應(yīng)該有了更直觀的感覺拾酝。

慎用 docker commit

使用 docker commit 命令雖然可以比較直觀的幫助理解鏡像分層存儲的概念燕少,但是實際環(huán)境中并不會這樣使用。
首先微宝,如果仔細(xì)觀察之前的 docker diff webserver 的結(jié)果棺亭,你會發(fā)現(xiàn)除了真正想要修改的 /usr/share/nginx/html/index.html 文件外,由于命令的執(zhí)行蟋软,還有很多文件被改動或添加了镶摘。這還僅僅是最簡單的操作,如果是安裝軟件包岳守、編譯構(gòu)建凄敢,那會有大量的無關(guān)內(nèi)容被添加進(jìn)來,將會導(dǎo)致鏡像極為臃腫湿痢。
此外涝缝,使用 docker commit 意味著所有對鏡像的操作都是黑箱操作,生成的鏡像也被稱為 黑箱鏡像譬重,換句話說拒逮,就是除了制作鏡像的人知道執(zhí)行過什么命令、怎么生成的鏡像臀规,別人根本無從得知滩援。而且,即使是這個制作鏡像的人塔嬉,過一段時間后也無法記清具體的操作玩徊。這種黑箱鏡像的維護(hù)工作是非常痛苦的。
而且谨究,回顧之前提及的鏡像所使用的分層存儲的概念恩袱,除當(dāng)前層外,之前的每一層都是不會發(fā)生改變的胶哲,換句話說畔塔,任何修改的結(jié)果僅僅是在當(dāng)前層進(jìn)行標(biāo)記、添加鸯屿、修改澈吨,而不會改動上一層。如果使用 docker commit 制作鏡像碾盟,以及后期修改的話棚辽,每一次修改都會讓鏡像更加臃腫一次,所刪除的上一層的東西并不會丟失冰肴,會一直如影隨形的跟著這個鏡像屈藐,即使根本無法訪問到榔组。這會讓鏡像更加臃腫。

2.2 使用 Dockerfile 定制鏡像

從剛才的 docker commit 的學(xué)習(xí)中联逻,我們可以了解到搓扯,鏡像的定制實際上就是定制每一層所添加的配置、文件包归。如果我們可以把每一層修改锨推、安裝、構(gòu)建公壤、操作的命令都寫入一個腳本换可,用這個腳本來構(gòu)建、定制鏡像厦幅,那么之前提及的無法重復(fù)的問題沾鳄、鏡像構(gòu)建透明性的問題、體積的問題就都會解決确憨。這個腳本就是 Dockerfile译荞。
Dockerfile 是一個文本文件,其內(nèi)包含了一條條的 指令(Instruction)休弃,每一條指令構(gòu)建一層吞歼,因此每一條指令的內(nèi)容,就是描述該層應(yīng)當(dāng)如何構(gòu)建塔猾。
還以之前定制 nginx 鏡像為例篙骡,這次我們使用 Dockerfile 來定制。
在一個空白目錄中桥帆,建立一個文本文件医增,并命名為 Dockerfile:

$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile

其內(nèi)容為:

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

這個 Dockerfile 很簡單慎皱,一共就兩行老虫。涉及到了兩條指令,F(xiàn)ROM 和 RUN茫多。

FROM 指定基礎(chǔ)鏡像

所謂定制鏡像祈匙,那一定是以一個鏡像為基礎(chǔ),在其上進(jìn)行定制天揖。就像我們之前運行了一個 nginx 鏡像的容器夺欲,再進(jìn)行修改一樣,基礎(chǔ)鏡像是必須指定的今膊。而 FROM 就是指定 基礎(chǔ)鏡像些阅,因此一個 DockerfileFROM 是必備的指令,并且必須是第一條指令斑唬。

Docker Hub 上有非常多的高質(zhì)量的官方鏡像市埋,有可以直接拿來使用的服務(wù)類的鏡像黎泣,如 nginxredis缤谎、mongo抒倚、mysqlhttpd坷澡、php托呕、tomcat 等;也有一些方便開發(fā)频敛、構(gòu)建项郊、運行各種語言應(yīng)用的鏡像,如 node斟赚、openjdk呆抑、pythonruby汁展、golang 等鹊碍。可以在其中尋找一個最符合我們最終目標(biāo)的鏡像為基礎(chǔ)鏡像進(jìn)行定制食绿。

如果沒有找到對應(yīng)服務(wù)的鏡像侈咕,官方鏡像中還提供了一些更為基礎(chǔ)的操作系統(tǒng)鏡像,如 ubuntu器紧、debian耀销、centosfedora铲汪、alpine 等熊尉,這些操作系統(tǒng)的軟件庫為我們提供了更廣闊的擴展空間。

除了選擇現(xiàn)有鏡像為基礎(chǔ)鏡像外掌腰,Docker 還存在一個特殊的鏡像狰住,名為 scratch。這個鏡像是虛擬的概念齿梁,并不實際存在催植,它表示一個空白的鏡像。

FROM scratch
...

如果你以 scratch 為基礎(chǔ)鏡像的話勺择,意味著你不以任何鏡像為基礎(chǔ)创南,接下來所寫的指令將作為鏡像第一層開始存在。

不以任何系統(tǒng)為基礎(chǔ)省核,直接將可執(zhí)行文件復(fù)制進(jìn)鏡像的做法并不罕見稿辙,對于 Linux 下靜態(tài)編譯的程序來說,并不需要有操作系統(tǒng)提供運行時支持气忠,所需的一切庫都已經(jīng)在可執(zhí)行文件里了邻储,因此直接 FROM scratch 會讓鏡像體積更加小巧未桥。使用 Go 語言 開發(fā)的應(yīng)用很多會使用這種方式來制作鏡像,這也是為什么有人認(rèn)為 Go 是特別適合容器微服務(wù)架構(gòu)的語言的原因之一芥备。

RUN 執(zhí)行命令

RUN 指令是用來執(zhí)行命令行命令的冬耿。由于命令行的強大能力,RUN 指令在定制鏡像時是最常用的指令之一萌壳。其格式有兩種:
shell 格式:RUN <命令>亦镶,就像直接在命令行中輸入的命令一樣。剛才寫的 Dockerfile 中的 RUN 指令就是這種格式袱瓮。

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

exec 格式:RUN ["可執(zhí)行文件", "參數(shù)1", "參數(shù)2"]缤骨,這更像是函數(shù)調(diào)用中的格式。
既然 RUN 就像 Shell 腳本一樣可以執(zhí)行命令尺借,那么我們是否就可以像 Shell 腳本一樣把每個命令對應(yīng)一個 RUN 呢绊起?比如這樣:

FROM debian:stretch

RUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

之前說過,Dockerfile 中每一個指令都會建立一層燎斩,RUN 也不例外虱歪。每一個 RUN 的行為,就和剛才我們手工建立鏡像的過程一樣:新建立一層栅表,在其上執(zhí)行這些命令笋鄙,執(zhí)行結(jié)束后,commit 這一層的修改怪瓶,構(gòu)成新的鏡像萧落。
而上面的這種寫法,創(chuàng)建了 7 層鏡像洗贰。這是完全沒有意義的找岖,而且很多運行時不需要的東西,都被裝進(jìn)了鏡像里敛滋,比如編譯環(huán)境许布、更新的軟件包等等。結(jié)果就是產(chǎn)生非常臃腫矛缨、非常多層的鏡像爹脾,不僅僅增加了構(gòu)建部署的時間帖旨,也很容易出錯箕昭。 這是很多初學(xué) Docker 的人常犯的一個錯誤。
Union FS 是有最大層數(shù)限制的解阅,比如 AUFS落竹,曾經(jīng)是最大不得超過 42 層,現(xiàn)在是不得超過 127 層货抄。
上面的 Dockerfile 正確的寫法應(yīng)該是這樣:

FROM debian:stretch

RUN set -x; buildDeps='gcc libc6-dev make wget' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

首先述召,之前所有的命令只有一個目的朱转,就是編譯、安裝 redis 可執(zhí)行文件积暖。因此沒有必要建立很多層藤为,這只是一層的事情。因此夺刑,這里沒有使用很多個 RUN 一一對應(yīng)不同的命令缅疟,而是僅僅使用一個 RUN 指令,并使用 && 將各個所需命令串聯(lián)起來遍愿。將之前的 7 層存淫,簡化為了 1 層。在撰寫 Dockerfile 的時候沼填,要經(jīng)常提醒自己桅咆,這并不是在寫 Shell 腳本,而是在定義每一層該如何構(gòu)建坞笙。
并且岩饼,這里為了格式化還進(jìn)行了換行。Dockerfile 支持 Shell 類的行尾添加 \ 的命令換行方式薛夜,以及行首 # 進(jìn)行注釋的格式忌愚。良好的格式,比如換行却邓、縮進(jìn)硕糊、注釋等,會讓維護(hù)腊徙、排障更為容易简十,這是一個比較好的習(xí)慣。
此外撬腾,還可以看到這一組命令的最后添加了清理工作的命令螟蝙,刪除了為了編譯構(gòu)建所需要的軟件,清理了所有下載民傻、展開的文件胰默,并且還清理了 apt 緩存文件。這是很重要的一步漓踢,我們之前說過牵署,鏡像是多層存儲,每一層的東西并不會在下一層被刪除喧半,會一直跟隨著鏡像奴迅。因此鏡像構(gòu)建時,一定要確保每一層只添加真正需要添加的東西挺据,任何無關(guān)的東西都應(yīng)該清理掉取具。
很多人初學(xué) Docker 制作出了很臃腫的鏡像的原因之一脖隶,就是忘記了每一層構(gòu)建的最后一定要清理掉無關(guān)文件。

構(gòu)建鏡像

好了暇检,讓我們再回到之前定制的 nginx 鏡像的 Dockerfile 來〔澹現(xiàn)在我們明白了這個 Dockerfile 的內(nèi)容,那么讓我們來構(gòu)建這個鏡像吧块仆。
在 Dockerfile 文件所在目錄執(zhí)行:

$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM nginx
 ---> e43d811ce2f4
Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 9cdc27646c7b
 ---> 44aa4490ce2c
Removing intermediate container 9cdc27646c7b
Successfully built 44aa4490ce2c

從命令的輸出結(jié)果中心墅,我們可以清晰的看到鏡像的構(gòu)建過程。在 Step 2 中榨乎,如同我們之前所說的那樣怎燥,RUN 指令啟動了一個容器 9cdc27646c7b,執(zhí)行了所要求的命令蜜暑,并最后提交了這一層 44aa4490ce2c铐姚,隨后刪除了所用到的這個容器 9cdc27646c7b。
這里我們使用了 docker build 命令進(jìn)行鏡像構(gòu)建肛捍。其格式為:

docker build [選項] <上下文路徑/URL/->

在這里我們指定了最終鏡像的名稱 -t nginx:v3隐绵,構(gòu)建成功后,我們可以像之前運行 nginx:v2 那樣來運行這個鏡像拙毫,其結(jié)果會和 nginx:v2 一樣依许。

鏡像構(gòu)建上下文(Context)

如果注意,會看到 docker build 命令最后有一個 .缀蹄。. 表示當(dāng)前目錄峭跳,而 Dockerfile 就在當(dāng)前目錄,因此不少初學(xué)者以為這個路徑是在指定 Dockerfile 所在路徑缺前,這么理解其實是不準(zhǔn)確的蛀醉。如果對應(yīng)上面的命令格式,你可能會發(fā)現(xiàn)衅码,這是在指定 上下文路徑拯刁。那么什么是上下文呢?

首先我們要理解 docker build 的工作原理逝段。Docker 在運行時分為 Docker 引擎(也就是服務(wù)端守護(hù)進(jìn)程)和客戶端工具垛玻。Docker 的引擎提供了一組 REST API,被稱為 Docker Remote API奶躯,而如 docker 命令這樣的客戶端工具帚桩,則是通過這組 API 與 Docker 引擎交互,從而完成各種功能巫糙。因此朗儒,雖然表面上我們好像是在本機執(zhí)行各種 docker 功能,但實際上参淹,一切都是使用的遠(yuǎn)程調(diào)用形式在服務(wù)端(Docker 引擎)完成醉锄。也因為這種 C/S 設(shè)計,讓我們操作遠(yuǎn)程服務(wù)器的 Docker 引擎變得輕而易舉浙值。

當(dāng)我們進(jìn)行鏡像構(gòu)建的時候恳不,并非所有定制都會通過 RUN 指令完成,經(jīng)常會需要將一些本地文件復(fù)制進(jìn)鏡像开呐,比如通過 COPY 指令烟勋、ADD 指令等。而 docker build 命令構(gòu)建鏡像筐付,其實并非在本地構(gòu)建卵惦,而是在服務(wù)端,也就是 Docker 引擎中構(gòu)建的瓦戚。那么在這種客戶端/服務(wù)端的架構(gòu)中沮尿,如何才能讓服務(wù)端獲得本地文件呢?

這就引入了上下文的概念较解。當(dāng)構(gòu)建的時候畜疾,用戶會指定構(gòu)建鏡像上下文的路徑,docker build 命令得知這個路徑后印衔,會將路徑下的所有內(nèi)容打包啡捶,然后上傳給 Docker 引擎。這樣 Docker 引擎收到這個上下文包后奸焙,展開就會獲得構(gòu)建鏡像所需的一切文件瞎暑。

如果在 Dockerfile 中這么寫:

COPY ./package.json /app/

這并不是要復(fù)制執(zhí)行 docker build 命令所在的目錄下的 package.json,也不是復(fù)制 Dockerfile 所在目錄下的 package.json与帆,而是復(fù)制 上下文(context) 目錄下的 package.json金顿。
因此,COPY 這類指令中的源文件的路徑都是相對路徑鲤桥。這也是初學(xué)者經(jīng)常會問的為什么 COPY ../package.json /app 或者 COPY /opt/xxxx /app 無法工作的原因揍拆,因為這些路徑已經(jīng)超出了上下文的范圍,Docker 引擎無法獲得這些位置的文件茶凳。如果真的需要那些文件嫂拴,應(yīng)該將它們復(fù)制到上下文目錄中去。
現(xiàn)在就可以理解剛才的命令 docker build -t nginx:v3 . 中的這個 .贮喧,實際上是在指定上下文的目錄筒狠,docker build 命令會將該目錄下的內(nèi)容打包交給 Docker 引擎以幫助構(gòu)建鏡像。
如果觀察 docker build 輸出箱沦,我們其實已經(jīng)看到了這個發(fā)送上下文的過程:

$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
...

理解構(gòu)建上下文對于鏡像構(gòu)建是很重要的辩恼,避免犯一些不應(yīng)該的錯誤。比如有些初學(xué)者在發(fā)現(xiàn) COPY /opt/xxxx /app 不工作后,于是干脆將 Dockerfile 放到了硬盤根目錄去構(gòu)建灶伊,結(jié)果發(fā)現(xiàn) docker build 執(zhí)行后疆前,在發(fā)送一個幾十 GB 的東西,極為緩慢而且很容易構(gòu)建失敗聘萨。那是因為這種做法是在讓 docker build 打包整個硬盤竹椒,這顯然是使用錯誤。
一般來說米辐,應(yīng)該會將 Dockerfile 置于一個空目錄下胸完,或者項目根目錄下。如果該目錄下沒有所需文件翘贮,那么應(yīng)該把所需文件復(fù)制一份過來赊窥。如果目錄下有些東西確實不希望構(gòu)建時傳給 Docker 引擎,那么可以用 .gitignore 一樣的語法寫一個 .dockerignore狸页,該文件是用于剔除不需要作為上下文傳遞給 Docker 引擎的锨能。
那么為什么會有人誤以為 . 是指定 Dockerfile 所在目錄呢?這是因為在默認(rèn)情況下肴捉,如果不額外指定 Dockerfile 的話腹侣,會將上下文目錄下的名為 Dockerfile 的文件作為 Dockerfile。
這只是默認(rèn)行為齿穗,實際上 Dockerfile 的文件名并不要求必須為 Dockerfile傲隶,而且并不要求必須位于上下文目錄中,比如可以用 -f ../Dockerfile.php 參數(shù)指定某個文件作為 Dockerfile窃页。
當(dāng)然跺株,一般大家習(xí)慣性的會使用默認(rèn)的文件名 Dockerfile,以及會將其置于鏡像構(gòu)建上下文目錄中脖卖。

其它 docker build 的用法

直接用 Git repo 進(jìn)行構(gòu)建

或許你已經(jīng)注意到了乒省,docker build 還支持從 URL 構(gòu)建,比如可以直接從 Git repo 中構(gòu)建:

# $env:DOCKER_BUILDKIT=0
# export DOCKER_BUILDKIT=0

$ docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world

Step 1/3 : FROM scratch
 --->
Step 2/3 : COPY hello /
 ---> ac779757d46e
Step 3/3 : CMD ["/hello"]
 ---> Running in d2a513a760ed
Removing intermediate container d2a513a760ed
 ---> 038ad4142d2b
Successfully built 038ad4142d2b

這行命令指定了構(gòu)建所需的 Git repo畦木,并且指定分支為 master袖扛,構(gòu)建目錄為 /amd64/hello-world/,然后 Docker 就會自己去 git clone 這個項目十籍、切換到指定分支蛆封、并進(jìn)入到指定目錄后開始構(gòu)建。

用給定的 tar 壓縮包構(gòu)建

$ docker build http://server/context.tar.gz

如果所給出的 URL 不是個 Git repo勾栗,而是個 tar 壓縮包惨篱,那么 Docker 引#擎會下載這個包,并自動解壓縮围俘,以其作為上下文砸讳,開始構(gòu)建琢融。

從標(biāo)準(zhǔn)輸入中讀取 Dockerfile 進(jìn)行構(gòu)建

docker build - < Dockerfile

cat Dockerfile | docker build -

如果標(biāo)準(zhǔn)輸入傳入的是文本文件,則將其視為 Dockerfile簿寂,并開始構(gòu)建漾抬。這種形式由于直接從標(biāo)準(zhǔn)輸入中讀取 Dockerfile 的內(nèi)容,它沒有上下文陶耍,因此不可以像其他方法那樣可以將本地文件 COPY 進(jìn)鏡像之類的事情奋蔚。

從標(biāo)準(zhǔn)輸入中讀取上下文壓縮包進(jìn)行構(gòu)建

$ docker build - < context.tar.gz

如果發(fā)現(xiàn)標(biāo)準(zhǔn)輸入的文件格式是 gzip她混、bzip2 以及 xz 的話烈钞,將會使其為上下文壓縮包,直接將其展開坤按,將里面視為上下文毯欣,并開始構(gòu)建。

3. 參考

(1) 利用 commit 理解鏡像構(gòu)成 https://yeasy.gitbook.io/docker_practice/image/commit
(2)使用 Dockerfile 定制鏡像
https://yeasy.gitbook.io/docker_practice/image/build

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末臭脓,一起剝皮案震驚了整個濱河市酗钞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌来累,老刑警劉巖砚作,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘹锁,居然都是意外死亡葫录,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門领猾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來米同,“玉大人,你說我怎么就攤上這事摔竿∶媪福” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵继低,是天一觀的道長熬苍。 經(jīng)常有香客問我,道長袁翁,這世上最難降的妖魔是什么柴底? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮梦裂,結(jié)果婚禮上似枕,老公的妹妹穿的比我還像新娘。我一直安慰自己年柠,他們只是感情好凿歼,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布褪迟。 她就那樣靜靜地躺著,像睡著了一般答憔。 火紅的嫁衣襯著肌膚如雪味赃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天虐拓,我揣著相機與錄音心俗,去河邊找鬼。 笑死蓉驹,一個胖子當(dāng)著我的面吹牛城榛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播态兴,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼狠持,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瞻润?” 一聲冷哼從身側(cè)響起喘垂,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绍撞,沒想到半個月后正勒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡傻铣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年章贞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矾柜。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡阱驾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出怪蔑,到底是詐尸還是另有隱情里覆,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布缆瓣,位于F島的核電站喧枷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏弓坞。R本人自食惡果不足惜隧甚,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渡冻。 院中可真熱鬧戚扳,春花似錦、人聲如沸族吻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至砍艾,卻和暖如春蒂教,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脆荷。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工凝垛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蜓谋。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓梦皮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親孤澎。 傳聞我的和親對象是個殘疾皇子届氢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容