Docker之Dockerfile 指令详解
閑話不多說(shuō),dokerfile常用指令解析奉上
FROM
作用:指定基礎(chǔ)鏡像,必須放在DOckerfile的第一行,表示從哪個(gè)baseimage開始構(gòu)建
格式:
- 鏡像必須是Dockerfile文件中第一條非注釋指令,表示從哪個(gè)baseimage開始構(gòu)建 FROM
- 指令能同一個(gè)Dockerfile文件中出現(xiàn)多次,為了創(chuàng)建多個(gè)鏡像 tag 和 digest
- 值是可選的,如果缺省,構(gòu)建器默認(rèn)為latest,當(dāng)tag不匹配時(shí),構(gòu)建器返回錯(cuò)誤
MAINTAINER
作用:指定作者信息,該指令已被廢棄但是目前還可以使用,可以用LABEL指令代替。
格式:
LABEL
作用:設(shè)定一些添加鏡像的元數(shù)據(jù),LABEL是一對(duì)key-value值
格式:
鏡像可以有多個(gè)LABEL,來(lái)指定多個(gè)標(biāo)簽,Docker建議在可能的情況下將 標(biāo)簽組合到單個(gè)LABEL指令中,
因?yàn)槊恳粋€(gè)LABEL指令都會(huì)產(chǎn)生一個(gè)新的層,而層數(shù)越多就會(huì)導(dǎo)致執(zhí)行花費(fèi)時(shí)間越長(zhǎng)。
LABEL中如果key已存在,后面添加相同的key那么新的value會(huì)覆蓋掉前面的。
COPY
作用:將工作目錄下的文件復(fù)制到所做的鏡像中的文件系統(tǒng)中
格式:
- <源路徑>用相對(duì)路徑,可以用通配符, 源文件必須在工作目錄或者工作目錄的子目錄中,<目標(biāo)路徑> 可以是容器內(nèi)的絕對(duì)路徑,也可以是相對(duì)于工作目錄的相對(duì)路徑(工作目錄可以用 WORKDIR 指令來(lái)指定)
- 目標(biāo)路徑不需要事先創(chuàng)建,如果目錄不存在會(huì)在復(fù)制文件前先行創(chuàng)建缺失目錄。
- 如果源文件是一個(gè)目錄,會(huì)自動(dòng)遞歸復(fù)制目錄下的文件到目標(biāo)位置,但是目錄自身不會(huì)復(fù)制
- 如果復(fù)制多個(gè)文件,或者源文件中用了通配符,那么目標(biāo)路徑必須以 / 為結(jié)尾
- 此外,還需要注意一點(diǎn),使用 COPY指令,源文件的各種元數(shù)據(jù)都會(huì)保留。比如讀、寫、執(zhí)行權(quán)限、文件變更時(shí)間等。這個(gè)特性對(duì)于鏡像定制很有用。特別是構(gòu)建相關(guān)文件都在使用 Git進(jìn)行管理的時(shí)候。
在使用該指令的時(shí)候還可以加上 --chown=: 選項(xiàng)來(lái)改變文件的所屬用戶及所屬組。
ADD
作用:和COPY類似,可以實(shí)現(xiàn)將文件和目錄復(fù)制到鏡像中,但是區(qū)別是可以實(shí)現(xiàn):
如果 <源路徑> 為一個(gè) tar 壓縮文件的話,壓縮格式為 gzip, bzip2 以及 xz 的情況下,ADD 指令將會(huì)自動(dòng)解壓縮這個(gè)壓縮文件到 <目標(biāo)路徑> 去。
如果<源路徑>是一個(gè)URL,Docker引擎會(huì)去下載這個(gè)鏈接的文件放到<目標(biāo)路徑>,下載后文件的權(quán)限自動(dòng)設(shè)置為600。注意:下載的tar包不會(huì)自動(dòng)解壓
格式:
使用ADD指令的時(shí)候也可以通過(guò)--chown=<user>:<group>選項(xiàng)廖改變文件的屬主和屬組
ADD --chown=cx55887:cx55887 files* /mydir/ADD --chown=cx55887 files* /mydir/ADD --chown=1 files* /mydir/ADD --chown=10:11 files* /mydir/WORKDIR
作用:設(shè)置鏡像中的工作目錄,相當(dāng)于cd命令
格式:
- WORKDIR 指令可以來(lái)指定工作目錄(或者稱為當(dāng)前目錄),以后各層的當(dāng)前目錄就被改為指定的目錄,如該目錄不存在,WORKDIR會(huì)幫你建立目錄。
VOLUME
作用:指定數(shù)據(jù)卷的掛載點(diǎn),若不存在會(huì)自動(dòng)創(chuàng)建
格式:
這樣/data目錄就會(huì)在運(yùn)行的自動(dòng)掛載,任何向/data寫入的信息都不會(huì)記錄進(jìn)容器儲(chǔ)存層,從而保證容器儲(chǔ)存層的無(wú)狀態(tài)化,當(dāng)然運(yùn)行時(shí)可以覆蓋掉這個(gè)掛載設(shè)置:
docker run -d -v mydata:/data xxxx在這條命令中,就使用了mydata 這個(gè)命名卷改在到了/data這個(gè)位置,替代了 Dockerfile中定義的匿名卷的掛在配置
EXPOSE
作用:告訴 Docker 服務(wù)端 容器對(duì)外映射的本地端口。
格式:
EXPOSE 指令是聲明運(yùn)行時(shí)容器提供服務(wù)端口,這只是一個(gè)聲明,在運(yùn)行時(shí)并不會(huì)因?yàn)檫@個(gè)聲明應(yīng)用就會(huì)開啟這個(gè)端口的服務(wù)。在dockerfile中聲名有兩個(gè)好處:
- 幫助鏡像使用者理解這個(gè)鏡像服務(wù)的守護(hù)端口,方便配置映射
- 運(yùn)行時(shí)使用隨機(jī)端口映射時(shí),也就是docker run -P時(shí),會(huì)隨機(jī)映射EXPOSE中聲明的端口。
- 另外需要注意的是將EXPOSE和在運(yùn)行時(shí)使用-p <宿主端口>:<容器端口>區(qū)分開,-p是映射宿主端口和容器端口,也就是說(shuō)將容器的對(duì)應(yīng)端口服務(wù)公開給外界訪問(wèn),而EXPOSE僅僅是聲名容器打算使用那些端口而已,并不會(huì)自動(dòng)在宿主機(jī)進(jìn)行端口映射
ENV
作用:設(shè)置環(huán)境變量
格式:
通過(guò)ENV所定義的變量是可以傳遞到容器之中,但是,在創(chuàng)建容器的時(shí)候,如果手動(dòng)指定了變量的值,那么這個(gè)值會(huì)覆蓋掉鏡像中原有的值
RUN
作用:RUN指令會(huì)在當(dāng)前鏡像的基礎(chǔ)上指定命令,并提交為新鏡像
格式:
前者將在shell終端中運(yùn)行命令,即/bin/sh -c;后者則使用exec執(zhí)行。指定使用其它終端可以通過(guò)第二種方式實(shí)現(xiàn),例如RUN ["/bin/bash", "-c", "echo hello"]。
CMD
作用:定義容器啟動(dòng)以后要默認(rèn)運(yùn)行的程序,即pid為1的程序
格式:
我們知道Docker不同于虛擬機(jī),容器就是進(jìn)程,既然是進(jìn)程,那么在啟動(dòng)容器的時(shí)候,需要指定所運(yùn)行的程序及參數(shù)。CMD指令就是指定容器主進(jìn)程啟動(dòng)命令的。
在運(yùn)行的時(shí)候可以指定新的命令來(lái)替代鏡像設(shè)置中的這個(gè)默認(rèn)命令,比如ubuntu鏡像的默認(rèn)的CMD是/bin/bsah,如果我們直接docker run -it ubuntu的話,會(huì)進(jìn)入bash 。我們也可以在運(yùn)行時(shí)指定運(yùn)行別的命令,如 docker run ubuntu cat /etc/os-release。這就是用 cat /etc/os-release 命令替換了默認(rèn)的/bin/bash 命令輸出了系統(tǒng)版本信息。
在指令格式上,推薦使用exec格式,這類格式在解析是會(huì)被解析成JOSN數(shù)組,因此一定要使用雙引號(hào),而不要使用單引號(hào)。
如果使用 shell 格式的話,實(shí)際的命令會(huì)被包裝為 sh -c 的參數(shù)的形式進(jìn)行執(zhí)行。比如:
CMD echo $NAME 在實(shí)際執(zhí)行中,會(huì)將其變更為:CMD [ "sh" ,"-c", "echo $NAME"]這就是為什么我們可以使用環(huán)境變量的原因,因?yàn)檫@些環(huán)境變量會(huì)被 shell 進(jìn)行解析處理。
提到 CMD 就不得不提容器中應(yīng)用在前臺(tái)執(zhí)行和后臺(tái)執(zhí)行的問(wèn)題。這是初學(xué)者常出現(xiàn)的一個(gè)混淆。
Docker 不是虛擬機(jī),容器中的應(yīng)用都應(yīng)該以前臺(tái)執(zhí)行,而不是像虛擬機(jī)、物理機(jī)里面那樣,用 upstart/systemd 去啟動(dòng)后臺(tái)服務(wù),容器內(nèi)沒(méi)有后臺(tái)服務(wù)的概念。
一些初學(xué)者將CMD寫為:
然后發(fā)現(xiàn)容器執(zhí)行后就立即退出了。甚至在容器內(nèi)去使用 systemctl 命令結(jié)果卻發(fā)現(xiàn)根本執(zhí)行不了。這就是因?yàn)闆](méi)有搞明白前臺(tái)、后臺(tái)的概念,沒(méi)有區(qū)分容器和虛擬機(jī)的差異,依舊在以傳統(tǒng)虛擬機(jī)的角度去理解容器。
對(duì)于容器而言,其啟動(dòng)程序就是容器應(yīng)用進(jìn)程,容器就是為了主進(jìn)程而存在的,主進(jìn)程退出,容器就失去了存在的意義,從而退出,其它輔助進(jìn)程不是它需要關(guān)心的東西。
而使用 service nginx start 命令,則是希望 upstart 來(lái)以后臺(tái)守護(hù)進(jìn)程形式啟動(dòng) nginx 服務(wù)。而剛才說(shuō)了 CMD service nginx start 會(huì)被理解為 CMD [ “sh”, “-c”, “service nginx start”],因此主進(jìn)程實(shí)際上是 sh。那么當(dāng) service nginx start 命令結(jié)束后,sh 也就結(jié)束了,sh 作為主進(jìn)程退出了,自然就會(huì)令容器退出。
正確的做法是直接執(zhí)行 nginx 可執(zhí)行文件,并且要求以前臺(tái)形式運(yùn)行。比如:
CMD [“nginx”, “-g”, “daemon off;”]
ENTRYPOINT
作用:ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器啟動(dòng)程序及參數(shù)
格式:
- 在運(yùn)行RUN的時(shí)候所執(zhí)行的命令無(wú)法覆蓋ENTRYPOINT中的命令 RUN
- 后面的命令會(huì)被以參數(shù)的方式追加到原本要執(zhí)行的命令的末尾,而不是替換
ARG
作用:定義在構(gòu)建鏡像時(shí)候所使用的變量,在將來(lái)容器運(yùn)行時(shí)是不會(huì)存在這些環(huán)境變量的。
格式:
Dockerfile 中的 ARG 指令是定義參數(shù)名稱,以及定義其默認(rèn)值。該默認(rèn)值可以在構(gòu)建命令 docker build 中用 --build-arg <參數(shù)名>=<值> 來(lái)覆蓋。
USER
作用:定義容器中的進(jìn)程以哪個(gè)用戶的身份運(yùn)行
格式:
該用戶必須存在于容器的用戶空間中(容器的文件系統(tǒng)的中的/etc/passwd中)
HEALTHCHECK
作用:HEALTHCHECK 指令是告訴 Docker 應(yīng)該如何進(jìn)行判斷容器的狀態(tài)是否正常
格式:
當(dāng)在一個(gè)鏡像指定了 HEALTHCHECK 指令后,用其啟動(dòng)容器,初始狀態(tài)會(huì)為 starting,在 HEALTHCHECK 指令檢查成功后變?yōu)?healthy,如果連續(xù)一定次數(shù)失敗,則會(huì)變?yōu)?unhealthy。命令的返回值決定了該次健康檢查的成功與否:0:成功;1:失敗;2:保留,不要使用這個(gè)值。
HEALTHCHECK 支持下列選項(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 次。ONBULID
作用:定義一個(gè)觸發(fā)器,用來(lái)實(shí)現(xiàn)當(dāng)基于這個(gè)這個(gè)鏡像做新鏡像的時(shí)候要執(zhí)行的命令
格式:
ONBUILD 是一個(gè)特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而這些指令,在當(dāng)前鏡像構(gòu)建時(shí)并不會(huì)被執(zhí)行。只有當(dāng)以當(dāng)前鏡像為基礎(chǔ)鏡像,去構(gòu)建下一級(jí)鏡像的時(shí)候才會(huì)被執(zhí)行。
------做運(yùn)維之前很矯情的小年輕-----
總結(jié)
以上是生活随笔為你收集整理的Docker之Dockerfile 指令详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Docker之镜像、容器、仓库概念
- 下一篇: 一次完整的HTTP事务过程--超详细!