本文僅為個(gè)人學(xué)習(xí)記錄. 教程來源Docker--從入門到實(shí)踐
FROM 指定基礎(chǔ)鏡像
FROM nginx
FROM 有一個(gè)比較特殊的鏡像(空鏡像)
FROM scratch
一般 golang 程序會(huì)直接使用FROM scratch.
RUN 執(zhí)行命令
run指令有兩種格式
- shell格式
RUN echo 'hello docker'
- exec格式
RUN apt-get update
RUN apt-get install -y gcc
注意:Dockerfile每一個(gè)指令都會(huì)構(gòu)建一層,不得超過127層
所以很多時(shí)候我們會(huì)使用 &&
來減少構(gòu)建的層數(shù)
例如上例可改寫為
RUN apt-get update && apt-get install -y gcc
Dockerfile nginx 實(shí)例
FROM nginx
RUN echo '<h1>Hello,Docker!!</h1>' > /usr/share/nginx/html/index.html
構(gòu)建命令
docker build -t nginx:v3 .
運(yùn)行命令
docker run --name webserver -d -p 80:80 nginx:v3
COPY 復(fù)制文件
COPY 指令將從構(gòu)建上下文目錄中 <源路徑> 的文件/目錄復(fù)制到新的一層的鏡像內(nèi)的 <目標(biāo)路徑> 位置。
COPY [--chown=<user>:<group>]<源路徑> ... <目標(biāo)路徑>
COPY [--chown=<user>:<group>] ["<源路徑1>",... "<目標(biāo)路徑>"]
<目標(biāo)路徑> 可以是容器內(nèi)的絕對路徑论悴,也可以是相對于工作目錄的相對路徑(工作目錄可以用 WORKDIR 指令來指定)。目標(biāo)路徑不需要事先創(chuàng)建耻讽,如果目錄不存在會(huì)在復(fù)制文件前先行創(chuàng)建缺失目錄针肥。
例子:
COPY package.json /usr/src/app/
這里源路徑可以使用通配符,其通配符規(guī)則要滿足 go 的 filepath.Match規(guī)則
例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
ADD 更高級的復(fù)制文件 (雖然很高級但不建議使用)
ADD [--chown=<user>:<group>]<源路徑> ... <目標(biāo)路徑>
ADD [--chown=<user>:<group>] ["<源路徑1>",... "<目標(biāo)路徑>"]
ADD
指令和 COPY
的格式和性質(zhì)基本一致。但是在 COPY
基礎(chǔ)上增加了一些功能
比如 <源路徑> 可以是一個(gè) URL具帮,這種情況下蜂厅,Docker 引擎會(huì)試圖去下載這個(gè)鏈接的文件放到 <目標(biāo)路徑> 去。下載后的文件權(quán)限自動(dòng)設(shè)置為 600唇跨,如果這并不是想要的權(quán)限改橘,那么還需要增加額外的一層 RUN 進(jìn)行權(quán)限調(diào)整唧龄,另外既棺,如果下載的是個(gè)壓縮包耽梅,需要解壓縮眼姐,也一樣還需要額外的一層 RUN 指令進(jìn)行解壓縮众旗。所以不如直接使用 RUN 指令贡歧,然后使用 wget 或者 curl 工具下載利朵,處理權(quán)限、解壓縮著洼、然后清理無用文件更合理年碘。因此屿衅,這個(gè)功能其實(shí)并不實(shí)用涤久,而且不推薦使用
注意 ADD 指令會(huì)令鏡像構(gòu)建緩存失效响迂,從而可能會(huì)令鏡像構(gòu)建變得比較緩慢。因此在 COPY 和 ADD 指令中選擇的時(shí)候然遏,可以遵循這樣的原則待侵,所有的文件復(fù)制均使用 COPY 指令怨酝,僅在需要自動(dòng)解壓縮的場合使用 ADD农猬。
CMD 容器啟動(dòng)命令
Docker 不是虛擬機(jī)售淡,容器就是進(jìn)程。既然是進(jìn)程楔壤,那么在啟動(dòng)容器的時(shí)候蹲嚣,需要指定所運(yùn)行的程序及參數(shù)隙畜。CMD 指令就是用于指定默認(rèn)的容器主進(jìn)程的啟動(dòng)命令的
CMD指令的格式和RUN相似,也是兩種格式:
#shell格式
CMD <命令>
#exec格式
CMD ["可執(zhí)行文件","參數(shù)1","參數(shù)2"...]
在指令格式上,一般推薦使用 exec 格式言询,這類格式在解析時(shí)會(huì)被解析為 JSON 數(shù)組运杭,因此一定要使用雙引號 "辆憔,而不要使用單引號熊榛。
如果使用 shell 格式的話, 實(shí)際的命令會(huì)被包裝為 sh -c 的參數(shù)的形式進(jìn)行執(zhí)行.
CMD echo $HOME
在實(shí)際執(zhí)行中, 會(huì)將其變更為:
CMD [ "sh", "-c", "echo $HOME" ]
這就是為什么我們可以使用環(huán)境變量的原因, 因?yàn)檫@些環(huán)境變量會(huì)被shell 進(jìn)行解析處理, 提到CMD
就不得不提容器中應(yīng)用在前臺執(zhí)行和后臺執(zhí)行的問題. 這是初學(xué)者常出現(xiàn)的一個(gè)混淆.
Docker不是虛擬機(jī), 容器中的應(yīng)用都應(yīng)該以前臺執(zhí)行,而不是像虛擬機(jī)/物理機(jī)那樣,用upstart/systemd去啟動(dòng)后臺服務(wù), 容器內(nèi)沒有后臺服務(wù)的概念
一些初學(xué)者將CMD寫為
CMD service nginx start
然后發(fā)現(xiàn)容器執(zhí)行后就立即退出了,甚至在容器內(nèi)去使用systemctl 命令,結(jié)果發(fā)現(xiàn)根本執(zhí)行不了.這就是因?yàn)闆]搞明白前臺,后臺的概念, 沒有區(qū)分容器和虛擬機(jī)的差異,依舊用傳統(tǒng)虛擬機(jī)的角度去理解容器
對于容器而言, 其啟動(dòng)程序就是容器應(yīng)用進(jìn)程, 容器就是為了主進(jìn)程而存在的, 主進(jìn)程退出 , 容器就失去了存在的意義,從而退出, 其他輔助進(jìn)程不是他需要關(guān)心的東西
而使用 service nginx start命令 則是希望upstart來以"后臺守護(hù)進(jìn)程"的形式啟動(dòng)nginx服務(wù), 但剛才說了 CMD service nginx start
會(huì)被理解為 CMD [ "sh", "-c", "echo $HOME" ]
,因此主進(jìn)程實(shí)際上是sh
.那么當(dāng)service nginx start命令結(jié)束后 , sh
也就結(jié)束了,sh
作為主進(jìn)程退出了, 自然就會(huì)讓容器也跟著退出
正確的做法是 直接執(zhí)行nginx可執(zhí)行文件, 并且要求以前臺的形式運(yùn)行.
比如:
CMD ["nginx", "-g", "deamon off"]
個(gè)人理解:
推薦使用 exec
格式的用意是為了避免類似sh -c
的命令干擾
ENTRYPOINT (入口點(diǎn))
ENTRYPOINT
的格式和RUN
指令格式一樣, 分為 exec
和shell
ENTRYPOINT
的目的和CMD
一樣都是在指定容器啟動(dòng)程序及參數(shù). ENTRYPOINT
在運(yùn)行是也可以替代,不過比CMD
略顯繁瑣, 需要通過docker run
的參數(shù)--entrypoint
來指定
當(dāng)指定了ENTRYPOINT
后, CMD
的含義就發(fā)生了改變, 不再是直接的運(yùn)行其命令, 而是將CMD
的內(nèi)容當(dāng)作參數(shù)傳給ENTRYPOINT
指令.可以理解為:
<ENTRYPOINT> "<CMD>"
場景一: 讓鏡像變成像命令一樣使用
假設(shè)我們需要一個(gè)得知自己當(dāng)前公網(wǎng) IP 的鏡像营搅,那么可以先用 CMD
來實(shí)現(xiàn):
FROM ubuntu:18.04
RUN apt-get update \
&&apt-get install -y curl \
&&rm -rf /var/lib/apt/lists/*
CMD ["curl", "-s" ,"https://ip.cn"]
假如我們使用 docker build -t myip .
來構(gòu)建鏡像的話, 如果我們需要查詢當(dāng)前公網(wǎng)IP, 只需要執(zhí)行
docker run myip
這里遇到一個(gè)問題, 如果我們想用curl -i
的話就會(huì)出現(xiàn)問題
所以這里就引申出了ENTRYPOINT
的用法
FROM ubuntu:18.04
RUN apt-get update \
&&apt-get install -y curl \
&&rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["curl","-s","https://ip.cn"]
ENV 設(shè)置環(huán)境變量
格式有兩種
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2> ...
這個(gè)指令很簡單,就是設(shè)置環(huán)境變量而已休蟹,無論是后面的其它指令,如 RUN
哪轿,還是運(yùn)行時(shí)的應(yīng)用杨耙,都可以直接使用這里定義的環(huán)境變量珊膜。
.