溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Dockerfile最佳實(shí)踐(一)

發(fā)布時(shí)間:2020-07-07 02:59:21 來(lái)源:網(wǎng)絡(luò) 閱讀:384 作者:唐光輝 欄目:云計(jì)算

在“Docker部署您的第一個(gè)應(yīng)用程序”一篇中,我們已經(jīng)使用了Dockerfile來(lái)構(gòu)建鏡像,這一篇將補(bǔ)充Dockerfile經(jīng)常使用指令。

Dockerfile最佳實(shí)踐(一)


Docker可以通過(guò)讀取Dockerfile中的指令來(lái)生成鏡像。Dockerfile是一個(gè)文本文件,用戶對(duì)鏡像操作的所有指令都可以寫在Dockerfile文件中,最后使用docker build來(lái)構(gòu)建鏡像。

在“Docker部署您的第一個(gè)應(yīng)用程序”中,我們使用了命令“docker image build -t bulletinboard:1.0 . ”,docker image build命令通過(guò)讀取Dockerfile和指定的上下文來(lái)構(gòu)建鏡像,命令結(jié)尾有一個(gè)“." 點(diǎn),這個(gè)點(diǎn)就是構(gòu)建鏡像的上下文。

上下文是遞歸進(jìn)行處理的。因此,即包括該上下文下的所有子目錄。

鏡像的構(gòu)建是由Docker守護(hù)進(jìn)程(Docker daemon)完成的,而不是由CLI。構(gòu)建過(guò)程首先要做的是將整個(gè)上下文(遞歸地)發(fā)送給守護(hù)進(jìn)程。在大多數(shù)情況下,最好從一個(gè)空目錄作為上下文開始,并將Dockerfile保存在該目錄中。只添加生成Dockerfile所需的文件。

注意:千萬(wàn)不要使用"/"根作為上下文,例如如下命令,因?yàn)樗鼘?huì)將宿主機(jī)"/"根目錄下所有文件傳輸?shù)紻ocker的守護(hù)進(jìn)程,可以在開發(fā)環(huán)境嘗試執(zhí)行如下命令進(jìn)行驗(yàn)證。

# docker image build /

若要在構(gòu)建的上下文中將配置文件或包構(gòu)建到鏡像中,可在Dockerfile中使用COPY指令。若要提高構(gòu)建性能,可通過(guò)在上下文目錄中添加.dockerignore文件來(lái)排除文件和目錄。通常Dockerfile,位于上下文的根目錄中,在docker build中使用-f標(biāo)志可以指定文件系統(tǒng)中任何地方的docker file,使用-t標(biāo)志可以指定構(gòu)建鏡像的倉(cāng)庫(kù)以及tag標(biāo)簽,例如:

#?cat?>/tmp/centos?<<EOF
FROM?centos:latest
MAINTAINER?firefly@demo.com
EOF
#?docker?image?build?-f?/tmp/centos?-t?centos:v0.1?.
#?docker?images

REPOSITORY TAG IMAGE ID CREATED SIZE

centos v0.1 7eab7b4cc6ea 38 seconds ago 220MB

您也可以指定構(gòu)建鏡像的多個(gè)倉(cāng)庫(kù)以及tag,例如:

#?docker?image?build?-f?/tmp/centos?-t?t01/centos:v0.1?-t?t02/centos:v0.2?.
#?docker?images

REPOSITORY TAG IMAGE ID CREATED SIZE

centos v0.1 7eab7b4cc6ea 3 minutes ago 220MB

t01/centos v0.1 7eab7b4cc6ea 3 minutes ago 220MB

t02/centos v0.2 7eab7b4cc6ea 3 minutes ago 220MB

注意:當(dāng)前所指的倉(cāng)庫(kù)和tag均位于當(dāng)前宿主機(jī),在其他宿主機(jī)上,您是無(wú)法獲取這些鏡像的(除非您推送到您的docker hub賬戶下或其他方式),后續(xù)將會(huì)講到docker的私有倉(cāng)庫(kù)registry或Harobor來(lái)遠(yuǎn)程分享我們做好的鏡像。

使用Dockerfile構(gòu)建鏡像步驟總結(jié)如下:

1、為鏡像創(chuàng)建一個(gè)目錄,如bulletin-board-app

2、進(jìn)入bulletin-board-app目錄,在該目錄下創(chuàng)建并完成Dockerfile文件編寫

3、鏡像所需要的文件或代碼都拷貝到bulletin-board-app目錄

4、如果bulletin-board-app目錄下有文件是構(gòu)建時(shí)不需要的,則可以創(chuàng)建并編寫.dockerignore文件來(lái)忽略不需要的文件

5、在bulletin-board-app目錄下執(zhí)行docker image build命令,并指定上下文位置為".",如命令”docker image build -t test/bulletinboard .“

Docker守護(hù)進(jìn)程在執(zhí)行Dockerfile中的指令之前,會(huì)先對(duì)Dockerfile執(zhí)行初步驗(yàn)證,如果語(yǔ)法不正確,則返回相關(guān)錯(cuò)誤,如果是參數(shù)錯(cuò)誤,例如目標(biāo)目錄不存在則不會(huì)檢查,直到執(zhí)行到該指令時(shí)拋出錯(cuò)誤。

Docker守護(hù)進(jìn)程逐個(gè)執(zhí)行Dockerfile中的指令,必要時(shí)將每條指令的結(jié)果提交給新鏡像,最后輸出新鏡像的ID。Docker守護(hù)進(jìn)程將自動(dòng)清理您發(fā)送的上下文。

注意,每個(gè)指令都是獨(dú)立運(yùn)行的,因此上一指命的執(zhí)行不會(huì)對(duì)下一個(gè)指令產(chǎn)生任何影響。

只要有可能,Docker將會(huì)重用中間鏡像(緩存),以顯著加快Docker的構(gòu)建過(guò)程。并且在控制臺(tái)會(huì)輸出Using cache消息。

演示示例:

#?cat?>Dockerfile?<<EOF
FROM?alpine:3.2
MAINTAINER?firefly@demo.com
RUN?apk?update?&&?apk?add?socat?&&?rm?-r?/var/cache/
CMD?env?|?grep?_TCP=?|?(sed?'s/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat?-t?100000000?TCP4-LISTEN:\1,fork,reuseaddr?TCP4:\2:\3?\&/'?&&?echo?wait)?|?sh
EOF

第一次構(gòu)建

#?docker?build?-t?demo/demo:v0.1?.

Sending build context to Docker daemon 2.048kB

Step 1/4 : FROM alpine:3.2

3.2: Pulling from library/alpine

95f5ecd24e43: Pull complete

Digest: sha256:ddac200f3ebc9902fb8cfcd599f41feb2151f1118929da21bcef57dc276975f9

Status: Downloaded newer image for alpine:3.2

---> 98f5f2d17bd1

Step 2/4 : MAINTAINER firefly@demo.com

---> Running in fa3786732ad5

Removing intermediate container fa3786732ad5

---> 6f5007fa547d

Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/

---> Running in b157222691fb

fetch http://dl-cdn.alpinelinux.org/alpine/v3.2/main/x86_64/APKINDEX.tar.gz

v3.2.3-474-g10ee65f [http://dl-cdn.alpinelinux.org/alpine/v3.2/main]

OK: 5294 distinct packages available

(1/4) Installing ncurses-terminfo-base (5.9)

(2/4) Installing ncurses-libs (5.9)

(3/4) Installing readline (6.3.008)

(4/4) Installing socat (1.7.3.0)

Executing busybox-1.23.2.trigger

OK: 7 MiB in 19 packages

Removing intermediate container b157222691fb

---> 58c5258280f7

Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh

---> Running in ca843dd16f02

Removing intermediate container ca843dd16f02

---> 7bf06f4ab80b

Successfully built 7bf06f4ab80b

Successfully tagged demo/demo:v0.1

第二次構(gòu)建

#?docker?build?-t?demo/demo:v0.2?.

Sending build context to Docker daemon 2.048kB

Step 1/4 : FROM alpine:3.2

---> 98f5f2d17bd1

Step 2/4 : MAINTAINER firefly@demo.com

---> Using cache

---> 6f5007fa547d

Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/

---> Using cache

---> 58c5258280f7

Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh

---> Using cache

---> 7bf06f4ab80b

Successfully built 7bf06f4ab80b

Successfully tagged demo/demo:v0.2

生成緩存僅用于具有本地父鏈的鏡像。這也意味著這些緩存鏡像均是由之前的構(gòu)建生成的,或者整個(gè)鏡像鏈?zhǔn)怯胐ocker load方式加載的。如果需要指定鏡像緩存,可以使用--cache from選項(xiàng)。使用--cache from指定的鏡像不需要有父鏈,可以從其他倉(cāng)庫(kù)中拉取。

完成構(gòu)建后,就可以考慮將存儲(chǔ)在本地倉(cāng)庫(kù)的鏡像推送到遠(yuǎn)端倉(cāng)庫(kù)(例如:Harobor)

BuildKit

從18.09版開始,Docker支持一個(gè)新的構(gòu)建工具buildkit,moby/buildkit項(xiàng)目(https://github.com/moby/buildkit)。與現(xiàn)有的實(shí)現(xiàn)工具相比,BuildKit提供了許多特性:

1、檢測(cè)并跳過(guò)執(zhí)行未使用的構(gòu)建階段

2、并行化獨(dú)立構(gòu)建階段

3、構(gòu)建過(guò)程中只增量地傳輸上下文中更改的文件

4、檢測(cè)并跳過(guò)在上下文中傳輸未使用的文件

5、許多新特性在外部Dockerfile實(shí)現(xiàn)

6、避免與API的其余部分(中間鏡像和容器)產(chǎn)生副作用

7、自動(dòng)修剪并設(shè)置生成緩存的優(yōu)先級(jí)

要使用BuildKit,需要在調(diào)用docker build命令之前在CLI上設(shè)置環(huán)境變量DOCKER_BUILDKIT=1。

要了解可用于基于BuildKit的構(gòu)建的實(shí)驗(yàn)Dockerfile語(yǔ)法,請(qǐng)參閱BuildKit文檔(https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md)。

Dockerfile指令與語(yǔ)法

Dockerfile中的指令不區(qū)分大小寫。但是,按慣例是要大寫,以便更容易地將它們與參數(shù)區(qū)分開來(lái)。

Docker按順序運(yùn)行Dockerfile中的指令。Dockerfile必須以“FROM”指令開頭。當(dāng)然,F(xiàn)ROM指令之前可以有注釋和全局參數(shù)。FROM指令指定了父鏡像。FROM前面只能有一個(gè)或多個(gè)ARG指令,這些指令聲明Dockerfile的FROM行中使用的參數(shù)。

Docker將以#開頭的行視為注釋。

1、FROM 鏡像:標(biāo)簽

指定新鏡像是基于哪個(gè)(基礎(chǔ))鏡像創(chuàng)建,每一個(gè)鏡像的創(chuàng)建都需要一條FROM指令,例如:

FROM centos:latest

2、MAINTAINER 名字/郵箱

維護(hù)人信息,例如:

MAINTAINER firefly@demo.com

3、ADD 源文件 新鏡像目錄

將源文件復(fù)制到新創(chuàng)建鏡像中,源文件要與Dockerfile同屬一個(gè)目錄,ADD指令會(huì)自動(dòng)解壓tar、tgz包,例如:

ADD example.tgz /data

4、COPY 源文件 目標(biāo)目錄

將源文復(fù)制到新建像中,源文件要與Dockerfile所屬同一個(gè)目錄,同ADD類似,例如:

COPY sources.list /etc/apt

5、ENV 關(guān)鍵字 值

設(shè)置變量或環(huán)境變量,例如:

ENV foo /var/www/html

上述表示變量foo的值是/var/www/html

6、RUN 命令

基于現(xiàn)有鏡像執(zhí)行命令,并提交到新鏡像上,通常在安裝軟件包時(shí)使用RUN,例如:

RUN yum -y install sysstat

7、WORKDIR 目錄

指定工作目錄,通過(guò)WORKDIR設(shè)置工作目錄后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都會(huì)在該目錄下執(zhí)行,后續(xù)登錄基于該鏡像的容器缺省路徑就是WORKDIR。

8、EXPOSE 端口號(hào)

指定Docker容器從該鏡像運(yùn)行時(shí)所開啟的端口,例如:

EXPOSE 80

9、VOLUME 掛載點(diǎn)

Docker容器從該鏡像運(yùn)行時(shí)會(huì)設(shè)置一個(gè)掛載點(diǎn),例如:

VOLUME /data

10、CMD["要運(yùn)行的程序","參數(shù)1","參數(shù)2"]

容器啟動(dòng)時(shí)要運(yùn)行的命令或腳本,Dockerfile只能有一條CMD命令,如果有多條,則執(zhí)行最后一條,另外執(zhí)行docker run 命令時(shí)若使用了/bin/bash,則會(huì)覆蓋CMD。例如:

CMD ["/bin/bash","/root/start.sh"]

示例演示

1、創(chuàng)建Dockerfile

#?mdkir?demo
#?cd?demo
#?cat?>?Dockerfile?<<EOF
#My?first?image
FROM?ubuntu:latest
MAINTAINER?firefly@demo.com
ENV?foo?/var/www/html
WORKDIR?${foo}
ADD?code.tgz?$foo
COPY?sources.list?/etc/apt
COPY?start.sh?/root/
RUN?chmod?755?/root/start.sh
RUN?mkdir?/data
VOLUME?/data
RUN?apt-get?-y?update?&&?apt-get?-y?install?sysstat?lsof?net-tools?procps?vim?bash
RUN?apt-get?-y?install?apache2
RUN?ln?-fs?/usr/share/zoneinfo/Asia/Shanghai?/etc/localtime
RUN?date
COPY?ports.conf?/etc/apache2/ports.conf
ADD?example.tgz?/data
EXPOSE?80
CMD?["/bin/bash","/root/start.sh"]
EOF

上述Dockerfile中用到的相關(guān)腳本配置如下:

#?cat?>sources.list?<<EOF
deb?http://mirrors.aliyun.com/ubuntu/?bionic?main?restricted?universe?multiverse
deb?http://mirrors.aliyun.com/ubuntu/?bionic-security?main?restricted?universe?multiverse
deb?http://mirrors.aliyun.com/ubuntu/?bionic-updates?main?restricted?universe?multiverse
deb?http://mirrors.aliyun.com/ubuntu/?bionic-proposed?main?restricted?universe?multiverse
deb?http://mirrors.aliyun.com/ubuntu/?bionic-backports?main?restricted?universe?multiverse
deb-src?http://mirrors.aliyun.com/ubuntu/?bionic?main?restricted?universe?multiverse
deb-src?http://mirrors.aliyun.com/ubuntu/?bionic-security?main?restricted?universe?multiverse
deb-src?http://mirrors.aliyun.com/ubuntu/?bionic-updates?main?restricted?universe?multiverse
deb-src?http://mirrors.aliyun.com/ubuntu/?bionic-proposed?main?restricted?universe?multiverse
deb-src?http://mirrors.aliyun.com/ubuntu/?bionic-backports?main?restricted?universe?multiverse
EOF
#?cat?>ports.conf?<<EOF
ServerName?localhost
Listen?80
<IfModule?ssl_module>
Listen?443
</IfModule>
<IfModule?mod_gnutls.c>
Listen?443
</IfModule>
EOF
#?cat?>start.sh?<<EOF
#!/bin/bash
apache2ctl?start
bash
EOF

2、通過(guò)Dockerfile構(gòu)建鏡像

#?docker?image?build?-t?test/httpd:v0.1?.
#?docker?images

REPOSITORY TAG IMAGE ID CREATED SIZE

test/httpd v0.1 9a9a2b7dd312 2 minutes ago 165MB

httpd latest 2ae34abc2ed0 3 weeks ago 165MB

3、基于鏡像運(yùn)行容器

#?docker?container?run?-idt?-p?80?--name?test_httpd01?test/httpd:v0.1

6e7a40ec63b618bf043b45d334c289df782f02e19617dc0686c3be41a582e047

注意:在創(chuàng)建容器時(shí)不要加/bin/bash,不然會(huì)覆蓋CMD導(dǎo)致apache服務(wù)不啟動(dòng)。

4、查看容器狀態(tài)并確認(rèn)端口處于監(jiān)聽狀態(tài)

#?docker?ps?-a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

a919ee33ae0e test/httpd:v0.1 "/bin/bash /root/sta…" 3 minutes ago Up 3 minutes 0.0.0.0:32787->80/tcp test_httpd01

#?docker?exec?-it?test_httpd01?netstat?-antp

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name

tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 18/apache2

5、測(cè)試

#?curl?http://127.0.0.1:32787

hello

6、刪除容器和鏡像,容器的生命周期結(jié)束

#?docker?stop?test_httpd01
#?docker?rm?test_httpd01
#?docker?rmi?$(docker?images?|grep?"test/httpd"?|awk?'{print?$3}')


總結(jié)
對(duì)于有一定Linux基礎(chǔ)的童鞋,編寫Dockerfile是比較簡(jiǎn)單的,但仍然需要注意一些細(xì)節(jié),比如ADD、COPY指令差異,RUN與CMD指令差異等。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI