
官方倉(cāng)庫(kù)示例
這些官方倉(cāng)庫(kù)的 Dockerfile 都是參考典范:https://github.com/docker-library/docs
COPY 復(fù)制文件
- COPY <源路徑>... <目標(biāo)路徑>
- COPY ["<源路徑1>",... "<目標(biāo)路徑>"]
和 RUN 指令一樣,也有兩種格式,一種類似于命令行,一種類似于函數(shù)調(diào)用。
COPY 指令將從構(gòu)建上下文目錄中 <源路徑> 的文件/目錄復(fù)制到新的一層的鏡像內(nèi)的 <目標(biāo)路徑> 位置。比如:
COPY package.json /usr/src/app/
<源路徑> 可以是多個(gè),甚至可以是通配符,其通配符規(guī)則要滿足 Go 的 filepath.Match 規(guī)則,如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目標(biāo)路徑> 可以是容器內(nèi)的絕對(duì)路徑,也可以是相對(duì)于工作目錄的相對(duì)路徑(工作目錄可以用 WORKDIR 指令來指定)。目標(biāo)路徑不需要事先創(chuàng)建,如果目錄不存在會(huì)在復(fù)制文件前先行創(chuàng)建缺失目錄。
此外,還需要注意一點(diǎn),使用 COPY 指令,源文件的各種元數(shù)據(jù)都會(huì)保留。比如讀、寫、執(zhí)行權(quán)限、文件變更時(shí)間等。這個(gè)特性對(duì)于鏡像定制很有用。特別是構(gòu)建相關(guān)文件都在使用 Git 進(jìn)行管理的時(shí)候。
ADD 更高級(jí)的復(fù)制文件
如果 <源路徑> 為一個(gè) tar 壓縮文件的話,壓縮格式為 gzip, bzip2 以及 xz 的情況下,ADD 指令將會(huì)自動(dòng)解壓縮這個(gè)壓縮文件到 <目標(biāo)路徑> 去。
在某些情況下,這個(gè)自動(dòng)解壓縮的功能非常有用,比如官方鏡像 ubuntu 中:
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
在 Docker 官方的 Dockerfile 最佳實(shí)踐文檔 中要求,盡可能的使用 COPY,因?yàn)?COPY 的語義很明確,就是復(fù)制文件而已,而 ADD 則包含了更復(fù)雜的功能,其行為也不一定很清晰。最適合使用 ADD 的場(chǎng)合,就是所提及的需要自動(dòng)解壓縮的場(chǎng)合。
因此在 COPY 和 ADD 指令中選擇的時(shí)候,可以遵循這樣的原則,所有的文件復(fù)制均使用 COPY 指令,僅在需要自動(dòng)解壓縮的場(chǎng)合使用 ADD。
CMD 容器啟動(dòng)命令
CMD 指令的格式和 RUN 相似,也是兩種格式:
- shell 格式:CMD <命令>
- exec 格式:CMD ["可執(zhí)行文件", "參數(shù)1", "參數(shù)2"...]
- 參數(shù)列表格式:CMD ["參數(shù)1", "參數(shù)2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具體的參數(shù)。
在指令格式上,一般推薦使用 exec 格式,這類格式在解析時(shí)會(huì)被解析為 JSON 數(shù)組,因此一定要使用雙引號(hào) ",而不要使用單引號(hào)。
果使用 shell 格式的話,實(shí)際的命令會(huì)被包裝為 sh -c 的參數(shù)的形式進(jìn)行執(zhí)行。比如:
CMD echo $HOME
在實(shí)際執(zhí)行中,會(huì)將其變更為:
CMD [ "sh", "-c", "echo $HOME" ]
ENV 設(shè)置環(huán)境變量
格式有兩種:
- ENV <key> <value>
- ENV <key1>=<value1> <key2>=<value2>...
這個(gè)指令很簡(jiǎn)單,就是設(shè)置環(huán)境變量而已,無論是后面的其它指令,如 RUN,還是運(yùn)行時(shí)的應(yīng)用,都可以直接使用這里定義的環(huán)境變量。
ENV VERSION=1.0 DEBUG=on \
NAME="Happy Feet"
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
&& grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
&& tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
&& rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
這里先定義了環(huán)境變量 NODE_VERSION,其后的 RUN 這層里,多次使用 $NODE_VERSION 來進(jìn)行操作定制??梢钥吹?,將來升級(jí)鏡像構(gòu)建版本的時(shí)候,只需要更新 7.2.0 即可,Dockerfile 構(gòu)建維護(hù)變得更輕松了。
VOLUME 定義匿名卷
格式為:
- VOLUME ["<路徑1>", "<路徑2>"...]
- VOLUME <路徑>
VOLUME /data
這里的 /data 目錄就會(huì)在運(yùn)行時(shí)自動(dòng)掛載為匿名卷,任何向 /data 中寫入的信息都不會(huì)記錄進(jìn)容器存儲(chǔ)層,從而保證了容器存儲(chǔ)層的無狀態(tài)化。當(dāng)然,運(yùn)行時(shí)可以覆蓋這個(gè)掛載設(shè)置。比如:
docker run -d -v mydata:/data xxxx
在這行命令中,就使用了 mydata 這個(gè)命名卷掛載到了 /data 這個(gè)位置,替代了 Dockerfile 中定義的匿名卷的掛載配置。
EXPOSE 暴露端口
格式為 EXPOSE <端口1> [<端口2>...]。
WORKDIR 指定工作目錄
- 格式為 WORKDIR <工作目錄路徑>。
Dockerfile 等同于 Shell 腳本來書寫,這種錯(cuò)誤的理解還可能會(huì)導(dǎo)致出現(xiàn)下面這樣的錯(cuò)誤:
RUN cd /app
RUN echo "hello" > world.txt
Dockerfile 參考文檔
Dockerfie 官方文檔:https://docs.docker.com/engine/reference/builder/
Dockerfile 最佳實(shí)踐文檔:https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/
Docker 官方鏡像 Dockerfile:https://github.com/docker-library/docs