溫馨提示×

溫馨提示×

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

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

Dockerfile最佳實踐(二)鞏固篇

發(fā)布時間:2020-06-11 06:19:45 來源:網(wǎng)絡(luò) 閱讀:1438 作者:唐光輝 欄目:云計算

在“Dockerfile最佳實踐(一)”中,我們已經(jīng)了解到Dockerfile中常用指令的使用,并給出了演示示例,這一篇將再補充和鞏固Dockerfile中的常用知識點。

Dockerfile context(上下文)

在執(zhí)行docker image build時,CLI首先會告知此次構(gòu)建將向Docker守護進程發(fā)送生成上下文的大小,例如。

#?cat?>?Dockerfile?<<EOF
FROM?centos:7
EOF
#?docker?image?build?-t?demo?.

Sending build context to Docker daemon 2.048kB

前面我們已經(jīng)講到鏡像的構(gòu)建是由Docker守護進程(Docker daemon)完成的,那么上述執(zhí)行的"docker build -t demo . "其實是經(jīng)歷了兩步:

首先,Docker CLI將上下文下包含的所有文件(遞歸地)發(fā)送給Docker守護進程Docker daemon。

然后,Docker Demon會收到Dcoker CLI發(fā)送的內(nèi)容,通過讀取Dockerfile里面的指令進行鏡像的分層構(gòu)建。

注意:若是使用"/"根作為上下文,則可能會導(dǎo)致主機異常重啟(在AWS上驗證是會導(dǎo)致主機自動重啟),因為它將會將宿主機"/"根目錄下所有文件傳輸?shù)紻ocker的守護進程。

COPY指令

COPY指令有2種書寫格式

COPY [--chown=user:group] 本地源文件 容器目標(biāo)目錄

COPY [--chown=user:group] ["本地源文件", "容器目標(biāo)目錄"]

默認所有拷貝到容器的文件屬主(UID)和屬組(GID)都是 0(root用戶),除非可選參數(shù)--chown指定用戶名、組名或UID/GID。--chown允許是username和groupname字符串,或者使用UID和GID。

--chown 特性僅支持用于構(gòu)建Linux容器的Dockerfiles,在Windows容器上無效。這是因為Linux和Windows的用戶和組的概念是有差異并且不能相互轉(zhuǎn)換的,因此使用/etc/passwd和/etc/group將用戶和組名稱轉(zhuǎn)換為UID或GID此功也僅適用于基于Linux操作系統(tǒng)的容器。

COPY指令的本地源文件支持使用模糊匹配和正則匹配。

COPY指令中源文件的路徑是以上下文(context)作為起始點,而不是宿主機上某個絕對路徑下的文件。也因此推薦用戶在構(gòu)建鏡像時使用"."作為上下文,并且事先將Dockerfile中所需文件拷貝到指定的上下文路徑下。

注意:使用COPY指令拷貝的源文件是多個文件(不是一個文件)時,則目標(biāo)目錄必須以"/"結(jié)尾,如“/test/",不能寫成“/test”。

演示示例1

#?mkdir?demo2
#?cd?demo2
#?mkdir?dir{a..z}
#?touch?arr{a..z}.txt
#?cat?>Dockerfile?<<EOF
FROM?centos:latest
MAINTAINER?firefly@demo.com
#RUN?yum?-y?install?coreutils?procps-ng?bash
RUN?useradd?-d?/home/test?-m?test?-s?/bin/bash
RUN?mkdir?/test
WORKDIR?/test
COPY?dir*?/test/
COPY?arr*.txt?/home/test/
COPY?--chown=test:test?arr*.txt?/test/
EOF
#?docker?image?build?-t?demo:v0.1?.
#?docker?run?-idt?--name?demo01?demo:v0.1?/bin/bash
#?docker?exec?-it?demo01?ls?-l?/test/

RUN指令

RUN指令有2種書寫格式

RUN 命令???????? #RUN指令后面所接的命令是在shell中運行的,在Linux上就好比執(zhí)行了 /bin/sh -c command (例如在終端執(zhí)行:/bin/sh -c ls),在Windows上就好比是執(zhí)行 cmd /S /C command(例如按win+r鍵在“運行”窗口執(zhí)行: cmd /S /C mstsc)

RUN ["命令", "參數(shù)1", "參數(shù)2"]???????????? #以exec的方式運行

RUN指令執(zhí)行的任何命令都發(fā)生在當(dāng)前鏡像之上的一個新層中(即一個中間容器intermediate container),命令執(zhí)行結(jié)束后會將結(jié)果提交到新的鏡像(如同docker commit),并刪除中間容器,所以我們在執(zhí)行RUN指令時會經(jīng)??吹筋愃迫缦氯罩?。

Step 9/19 : RUN chmod 755 /root/start.sh

---> Running in a2e6b9ce0940

Removing intermediate container a2e6b9ce0940

---> 6b03e9b0ce70

新提交鏡像將用于Dockerfile中的下一個指令。分層運行指令和提交符合Docker的核心概念,在Docker中,提交開銷很小,我們可以從鏡像歷史記錄的任何一點來創(chuàng)建容器,就像源代碼管理一樣。

CMD指令

CMD指令有3種書寫格式

CMD 命令????????????? #以shell方式運行

CMD ["可執(zhí)行程序","參數(shù)1","參數(shù)2"]???????????????? #exec方式,推薦運行方式

CMD ["參數(shù)1", "參數(shù)2"]??????????? #用于給ENTRYPOINT指令提供默認參數(shù)

Dockerfile中只能有一條CMD指令。如果出現(xiàn)多條,則只有最后一條指令生效。

注意: CMD指令會被 docker run 后的參數(shù)所覆蓋。例如:

docker run -idt --name demo01 demo:v0.1 /bin/bash??????? # "/bin/bash"將會覆蓋CMD指令

ENTRYPOINT指令

ENTRYPOINT指令有2種書寫格式

ENTRYPOINT [“命令”,“參數(shù)1”,“參數(shù)2”]???????????????????? #執(zhí)行效果同docker exec

ENTRYPOINT 命令 參數(shù)1 參數(shù)2???????????????????? #執(zhí)行效果同shell命令

ENTRYPOINT指令不會被 docker run 后的參數(shù)所覆蓋,而是附加在ENTRYPOINT指令之后。而且CMD指令中的參數(shù)會傳遞給ENTRYPOINT。

同CMD指令一樣,Dockerfile中也只能有一條ENTRYPOINT指令,并且若是多條則最后一條生效。

CMD與ENTRYPOINT指令存在的目的就是在容器啟動時就運行必要的應(yīng)用程序。

演示示例2

驗證CMD指令

#?mkdir?demo2
#?cd?demo2
#?cat?>Dockerfile?<<EOF
FROM?ubuntu
RUN?apt-get?-y?update?&&?apt-get?install?-y?iputils-ping
CMD?["ping",?"114.114.114.114"]
EOF

構(gòu)建鏡像

#?docker?image?build?-t?demo02:v0.1?.

根據(jù)上述鏡像創(chuàng)建容器demo02,并且不指定類似"/bin/bash" 命令

#?docker?run?-idt?--name?demo02?demo02:v0.1

查看容器demo02日志輸出

#?docker?logs?demo02

PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.

64 bytes from 114.114.114.114: icmp_seq=1 ttl=61 time=36.7 ms

64 bytes from 114.114.114.114: icmp_seq=2 ttl=61 time=36.5 ms

登錄到容器,并執(zhí)行top命令查看,如圖1.1所示。

# docker exec -it demo02 /bin/bash

Dockerfile最佳實踐(二)鞏固篇

圖1.1


如果,我們在創(chuàng)建容器demo02_2時指定運行參數(shù) "/bin/bash",如

#?docker?run?-idt?--name?demo02_2?demo02:v0.1?/bin/bash


查看容器demo02_2運行狀態(tài)

#?docker?ps?-a?|grep?demo02_2

9b76b8af295d??? demo02:v0.1????? "/bin/bash"????????????? 7 seconds ago?????????????????? Up 7 seconds??????????????????? demo02_2

登錄到容器,使用top命令查看容器進程,可以看到CMD指令被docker run 后的"/bin/bash"參數(shù)覆蓋了,如圖1.2所示。

#?docker?exec?-it?demo02_2?/bin/bash


Dockerfile最佳實踐(二)鞏固篇

圖1.2

演示示例3

驗證ENTRYPOINT指令

#?mkdir?demo3
#?cd?demo3
#?cat?>Dockerfile?<<EOF
FROM?ubuntu
RUN?apt-get?-y?update?&&?apt-get?install?-y?iputils-ping
ENTRYPOINT?["ping",?"114.114.114.114"]
EOF
#?docker?image?build?-t?demo03:v0.1?.

注意,創(chuàng)建容器時不指定類似"/bin/bash"

#?docker?run?-idt?--name?demo03?demo03:v0.1

查看容器日志

#?docker?logs?demo03

PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.

64 bytes from 114.114.114.114: icmp_seq=1 ttl=61 time=36.6 ms

64 bytes from 114.114.114.114: icmp_seq=2 ttl=78 time=36.5 ms

登錄到容器,并執(zhí)行top命令查看,如圖1.3所示。

#?docker?exec?-it?demo03?/bin/bash


Dockerfile最佳實踐(二)鞏固篇

圖1.3


創(chuàng)建容器demo05時指定運行參數(shù) ”127.0.0.1”

#?docker?run?-idt?--name?demo05?demo03:v0.1?127.0.0.1

進入容器demo05并執(zhí)行top查看,確認docker run 后的參數(shù)127.0.0.1是傳遞給了ENTRYPOINT指令,如圖1.4所示。

Dockerfile最佳實踐(二)鞏固篇

圖1.4


演示示例4

ENTRYPOINT指令和CMD指令結(jié)合使用

我們將可能會調(diào)整的參數(shù)寫到CMD指令。然后在docker run 里指定參數(shù),這樣CMD指令后的參數(shù)就會被覆蓋掉而ENTRYPOINT里的不被覆蓋。

#?cat?>Dockerfile?<<EOF
FROM?ubuntu
RUN?apt-get?-y?update?&&?apt-get?install?-y?iputils-ping
ENTRYPOINT?["ping",?"114.114.114.114"]
CMD?["-a"]
EOF
#?docker?image?build?-t?demo03:v0.2?.

創(chuàng)建容器demo03_2時指定運行參數(shù)為"-c 3"

# docker run -idt --name demo03_2 demo03:v0.2 -c 3

查看容器運行日志,確認是ping -c 3次后結(jié)束,即CMD指令后的參數(shù)被覆蓋為CMD ["-c 3"]

#?docker?logs?demo03_2

PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.

64 bytes from 114.114.114.114: icmp_seq=1 ttl=64 time=36.7 ms

64 bytes from 114.114.114.114: icmp_seq=2 ttl=59 time=36.5 ms

64 bytes from 114.114.114.114: icmp_seq=3 ttl=62 time=36.4 ms

--- 114.114.114.114 ping statistics ---

3 packets transmitted, 3 received, 0% packet loss, time 2003ms

rtt min/avg/max/mdev = 36.495/36.613/36.789/0.254 ms


Dockerfile使用管道符或標(biāo)準(zhǔn)輸入方式來構(gòu)建鏡像

示例:

echo?-e?'FROM?busybox\nRUN?echo?"hello?world"'?|?docker?build?-

或者

docker?build?-<<EOF
FROM?busybox
RUN?echo?"hello?world"
EOF

上述2個示例是等價的

docker build [OPTIONS] - 中的"-"是連接符,用于獲取路徑的位置,并指示Docker從stdin讀取構(gòu)建上下文。

以下示例我們嘗試使用COPY或ADD指令

#?mkdir?example1
#?cd?example1
#?touch?somefile.txt
docker?build?-t?myimage:v0.1?-<<EOF
FROM?busybox
COPY?somefile.txt?.
RUN?cat?/somefile.txt
EOF

會提示如下錯誤,因為上述并沒有指定從本地來構(gòu)建上下文

Sending build context to Docker daemon 2.048kB

Step 1/3 : FROM busybox

---> b534869c81f0

Step 2/3 : COPY somefile.txt .

COPY failed: stat /var/lib/docker/tmp/docker-builder461920604/somefile.txt: no such file or directory

但使用以下語法就可以使用本地文件系統(tǒng)上的文件,并且使用stdin中的Dockerfile來構(gòu)建鏡像。語法使用-f(或--file)選項指定要使用的Dockerfile,使用連字符(-)作為文件名指示Docker從stdin讀取Dockerfile

docker?build?[OPTIONS]?-f-?PATH

以下示例我們嘗試使用COPY或ADD指令

#?mkdir?example2
#?cd?example2
#?touch?somefile.txt
#?docker?build?-t?myimage:v0.2?-f-?.?<<EOF
FROM?busybox
COPY?somefile.txt?.
RUN?cat?/somefile.txt
EOF


從遠端倉庫接取代碼,然后再從標(biāo)準(zhǔn)輸入讀取Dockerfile構(gòu)建鏡像

docker?build?[OPTIONS]?-f-?PATH

如果要從不包含Dockerfile的git倉庫中來構(gòu)建鏡像,或者是使用自定義Dockerfile構(gòu)建鏡像,則此語法非常有用。

#?docker?build?-t?myimage:latest?-f-?https://github.com/docker-library/hello-world.git?<<EOF
FROM?busybox
COPY?hello.c?.
EOF

注意:上述示例執(zhí)行成功前提是已安裝好git客戶端

總結(jié)

本節(jié)示例較多,但均是非常簡單的示例,說話孰能生巧,需勤加練習(xí)。另Docker官方建議,為降低復(fù)雜性、依賴性、以及鏡像大小和構(gòu)建時間,要盡量避免安裝額外的或不必要的包。

向AI問一下細節(jié)

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

AI