1杂靶、 Dockerfile基本結(jié)構(gòu)
Dockerfile由一行行命令語句組成持搜,并且支持以#開頭的注釋行。
一般而言辞居,Dockerfile分為四部分:基礎(chǔ)鏡像信息、維護者信息蛋勺、鏡像
操作指令和容器啟動時執(zhí)行指令瓦灶。例如:
# This Dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# Base image to use, this must be set as the first line
FROM ubuntu
# Maintainer: docker_user <docker_user at email.com> (@docker_user)
MAINTAINER docker_user docker_user@email.com
# Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/
sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Commands when creating a new container
CMD /usr/sbin/nginx
其中,一開始必須指明所基于的鏡像名稱抱完,接下來一般是說明維護者信息贼陶。后面則是鏡像操作指令,例如RUN指令巧娱,RUN指令將對鏡像執(zhí)行跟隨的命令碉怔。每運行一條RUN指令,鏡像就添加新的一層禁添,并提交撮胧。最后是CMD指令,用來指定運行容器時的操作命令老翘。
2芹啥、 指令說明
Dockerfile 指令 | 說明 |
---|---|
FROM | 指定基礎(chǔ)鏡像,用于后續(xù)的指令構(gòu)建铺峭。 |
MAINTAINER | 指定Dockerfile的作者/維護者墓怀。(已棄用,推薦使用LABEL指令) |
LABEL | 添加鏡像的元數(shù)據(jù)卫键,使用鍵值對的形式傀履。 |
RUN | 在構(gòu)建過程中在鏡像中執(zhí)行命令。 |
CMD | 指定容器創(chuàng)建時的默認命令莉炉。(可以被覆蓋) |
ENTRYPOINT | 設置容器創(chuàng)建時的主要命令钓账。(不可被覆蓋) |
EXPOSE | 聲明容器運行時監(jiān)聽的特定網(wǎng)絡端口碴犬。 |
ENV | 在容器內(nèi)部設置環(huán)境變量。 |
ADD | 將文件官扣、目錄或遠程URL復制到鏡像中翅敌,tar文件會自動解壓。 |
COPY | 將文件或目錄復制到鏡像中惕蹄。 |
VOLUME | 為容器創(chuàng)建掛載點或聲明卷蚯涮。 |
WORKDIR | 設置后續(xù)指令的工作目錄。 |
USER | 指定后續(xù)指令的用戶上下文卖陵。 |
ARG | 定義在構(gòu)建過程中傳遞給構(gòu)建器的變量遭顶,可使用 "docker build" 命令設置。 |
ONBUILD | 當該鏡像被用作另一個構(gòu)建過程的基礎(chǔ)時泪蔫,添加觸發(fā)器棒旗。 |
STOPSIGNAL | 設置發(fā)送給容器以退出的系統(tǒng)調(diào)用信號。 |
HEALTHCHECK | 定義周期性檢查容器健康狀態(tài)的命令撩荣。 |
SHELL | 覆蓋Docker中默認的shell铣揉,用于RUN、CMD和ENTRYPOINT指令餐曹。 |
FROM
指定所創(chuàng)建鏡像的基礎(chǔ)鏡像逛拱,如果本地不存在,則默認會去Docker Hub下載指定鏡像台猴。
任何Dockerfile中的第一條非注釋指令必須為FROM指令朽合。并且,如果在同一個Dockerfile中創(chuàng)建多個鏡像饱狂,可以使用多個FROM指令(每個鏡像一次)曹步。
空鏡像: scratchMAINTAINER
指定維護者信息,格式為MAINTAINER <name>休讳,已棄用讲婚,推薦使用LABEL指令
LABEL org.opencontainers.image.authors="SvenDowideit@home.org.au"
- RUN
運行指定的命令。
格式為RUN <command>或RUN ["executable"俊柔,"param1"磺樱,"param2"]。注意婆咸,后一個指令會被解析為Json數(shù)組竹捉,因此必須用雙引號。
前者默認將在shell終端中運行命令尚骄,即/ bin/sh -c块差;后者則使用exec執(zhí)行,不會啟動shell環(huán)境。
指定使用其他終端類型可以通過第二種方式實現(xiàn)憨闰,例如RUN ["/bin/ bash"状蜗,"-c","echo hello"]鹉动。
每條RUN指令將在當前鏡像的基礎(chǔ)上執(zhí)行指定命令轧坎,并提交為新的鏡像。當命令較長時可以使用\來換行泽示。例如:
RUN apt-get update \
&& apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev \
&& rm -rf /var/cache/apt
- CMD
CMD指令用來指定啟動容器時默認執(zhí)行的命令缸血。它支持三種格式:
· CMD ["executable","param1"械筛,"param2"]使用 exec執(zhí)行捎泻,是推薦使用的方式;
· CMD command param1 param2在/bin/sh中執(zhí)行埋哟,提供給需要交互的應用笆豁;
· CMD ["param1","param2"]提供給 ENTRYPOINT的默認參數(shù)赤赊。
每個Dockerfile只能有一條CMD命令闯狱。如果指定了多條命令,只有最后一條會被執(zhí)行抛计。
如果用戶啟動容器時手動指定了運行的命令(作為run的參數(shù))哄孤,則會覆蓋掉CMD指定的命令。 - LABEL
LABEL指令用來指定生成鏡像的元數(shù)據(jù)標簽信息爷辱。
LABEL version="1.0"
LABEL description="This text illustrates \ that label-values can span multiple lines."
- EXPOSE
聲明鏡像內(nèi)服務所監(jiān)聽的端口。
EXPOSE 22 80 8443
注意朦肘,該指令只是起到聲明作用饭弓,并不會自動完成端口映射。
在啟動容器時需要使用-P媒抠,Docker主機會自動分配一個宿主機的臨時端口轉(zhuǎn)發(fā)到指定的端口弟断;使用-p,則可以具體指定哪個宿主機的本地端口會映射過來趴生。
- ENV
指定環(huán)境變量阀趴,在鏡像生成過程中會被后續(xù)RUN指令使用,在鏡像啟動的容器中也會存在
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/
postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
指令指定的環(huán)境變量在運行時可以被覆蓋掉苍匆,如docker run --env <key>=<value> built_image刘急。
- ADD
該命令將復制指定的<src>路徑下的內(nèi)容到容器中的<dest>路徑下。
格式為ADD<src><dest>浸踩。
其中<src>可以是Dockerfile所在目錄的一個相對路徑(文件或目錄)叔汁,也可以是一個URL,還可以是一個tar文件(如果為tar文件,會自動解壓到<dest>路徑下)据块。<dest>可以是鏡像內(nèi)的絕對路徑码邻,或者相對于工作目錄(WORKDIR)的相對路徑。
ADD *.c /code/
COPY
格式為COPY<src><dest>另假。
復制本地主機的<src>(為Dockerfile所在目錄的相對路徑像屋、文件或目錄)下的內(nèi)容到鏡像中的<dest>下。目標路徑不存在時边篮,會自動創(chuàng)建己莺。
路徑同樣支持正則格式。
當使用本地目錄為源目錄時苟耻,推薦使用COPY篇恒。指定鏡像的默認入口命令,該入口命令會在啟動容器時作為根命令執(zhí)行凶杖,所有傳入值作為該命令的參數(shù)胁艰。
支持兩種格式:
ENTRYPOINT ["executable", "param1", "param2"](exec調(diào)用執(zhí)行);
ENTRYPOINT command param1 param2(shell中執(zhí)行)智蝠。
此時腾么,CMD指令指定值將作為根命令的參數(shù)。
每個Dockerfile中只能有一個ENTRYPOINT杈湾,當指定多個時解虱,只有最后一個有效。
在運行時漆撞,可以被--entrypoint參數(shù)覆蓋掉殴泰,如docker run --entrypoint。
VOLUME
創(chuàng)建一個數(shù)據(jù)卷掛載點浮驳,格式為VOLUME["/data"]悍汛。
可以從本地主機或其他容器掛載數(shù)據(jù)卷,一般用來存放數(shù)據(jù)庫和需要保存的數(shù)據(jù)等至会。USER
指定運行容器時的用戶名或UID离咐,后續(xù)的RUN等指令也會使用指定的用戶身份。
格式為USER daemon奉件。
當服務不需要管理員權(quán)限時宵蛀,可以通過該命令指定運行用戶,并且可以在之前創(chuàng)建所需要的用戶县貌。例如:
RUN groupadd -r postgres && useradd -r -g postgres postgres
- WORKDIR
為后續(xù)的RUN术陶、CMD和ENTRYPOINT指令配置工作目錄。
格式為WORKDIR/path/to/workdir煤痕。
可以使用多個WORKDIR指令瞳别,后續(xù)命令如果參數(shù)是相對路徑征候,則會基于之前命令指定的路徑。例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
則最終路徑為/ a/b/c祟敛。
- ARG
指定一些鏡像內(nèi)使用的參數(shù)(例如版本號信息等)疤坝,這些參數(shù)在執(zhí)行docker build命令時才以--build-arg <varname>=<value>格式傳入。
格式為ARG<name>[=<default value>]馆铁。
則可以用docker build --build-arg <name>=<value>.來指定參數(shù)值跑揉。
它與 ENV 作用一致。不過作用域不一樣埠巨。ARG 設置的環(huán)境變量僅對 Dockerfile 內(nèi)有效历谍,也就是說只有 docker build 的過程中有效,構(gòu)建好的鏡像內(nèi)不存在此環(huán)境變量辣垒。
構(gòu)建命令 docker build 中可以用 --build-arg <參數(shù)名>=<值> 來覆蓋望侈。
- ONBUILD
配置當所創(chuàng)建的鏡像作為其他鏡像的基礎(chǔ)鏡像時,所執(zhí)行的創(chuàng)建操作指令勋桶。
格式為ONBUILD[INSTRUCTION]脱衙。
例如,Dockerfile使用如下的內(nèi)容創(chuàng)建了鏡像 image-A:
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
如果基于image-A創(chuàng)建新的鏡像時例驹,新的Dockerfile中使用FROM image-A指定基礎(chǔ)鏡像捐韩,會自動執(zhí)行ONBUILD指令的內(nèi)容,等價于在后面添加了兩條指令:
FROM image-A
#Automatically run the following
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
使用ONBUILD指令的鏡像鹃锈,推薦在標簽中注明荤胁,例如ruby:1.9-onbuild。
- STOPSIGNAL
指定所創(chuàng)建鏡像啟動的容器接收退出的信號值屎债。例如:
STOPSIGNAL signal
- HEALTHCHECK
配置所啟動容器如何進行健康檢查(如何判斷健康與否)仅政,自Docker1.12開始支持。
格式有兩種:
HEALTHCHECK [OPTIONS] CMD command:根據(jù)所執(zhí)行命令返回值是否為0來判斷盆驹;
·HEALTHCHECK[OPTIONS]CMD command:根據(jù)所執(zhí)行命令返回值是否為0來判斷圆丹;
·HEALTHCHECK NONE:禁止基礎(chǔ)鏡像中的健康檢查。
OPTION支持:
·--interval=DURATION(默認為:30s):過多久檢查一次召娜;
·--timeout=DURATION(默認為:30s):每次檢查等待結(jié)果的超時运褪;
·--retries=N(默認為:3):如果失敗了惊楼,重試幾次才最終確定失敗玖瘸。
- SHELL
指定其他命令使用shell時的默認shell類型。
默認值為["/bin/sh"檀咙,"-c"]雅倒。
3、創(chuàng)建鏡像
編寫完成Dockerfile之后弧可,可以通過docker build命令來創(chuàng)建鏡像蔑匣。
$ docker build -t test-image:1.1 /tmp/docker_builder/
4、使用.dockerignore文件
可以通過.dockerignore文件(每一行添加一條匹配模式)來讓 Docker忽略匹配模式路徑下的目錄和文件。例如:
# comment
*/temp*
*/*/temp*
tmp?
~*
5裁良、最佳實踐
所謂最佳實踐凿将,實際上是從需求出發(fā),來定制適合自己价脾、高效方便的鏡像牧抵。
首先,要盡量吃透每個指令的含義和執(zhí)行效果侨把,自己多編寫一些簡單的例子進行測試犀变,弄清楚了再撰寫正式的Dockerfile。此外秋柄,Docker Hub官方倉庫中提供了大量的優(yōu)秀鏡像和對應的Dockefile获枝,可以通過閱讀它們來學習如何撰寫高效的Dockerfile。
筆者在應用過程中也總結(jié)了一些實踐經(jīng)驗骇笔。建議讀者在生成鏡像過程中省店,嘗試從如下角度進行思考,完善所生成的鏡像蜘拉。
- 精簡鏡像用途:盡量讓每個鏡像的用途都比較集中萨西、單一,避免構(gòu)造大而復雜旭旭、多功能的鏡像谎脯;
- 選用合適的基礎(chǔ)鏡像:過大的基礎(chǔ)鏡像會造成生成臃腫的鏡像,一般推薦較為小巧的debian鏡像持寄;
- 提供足夠清晰的命令注釋和維護者信息:Dockerfile也是一種代碼源梭,需要考慮方便后續(xù)擴展和他人使用;
- 正確使用版本號:使用明確的版本號信息稍味,如1.0废麻,2.0,而非latest模庐,將避免內(nèi)容不一致可能引發(fā)的慘案烛愧;
- 減少鏡像層數(shù):如果希望所生成鏡像的層數(shù)盡量少,則要盡量合并指令掂碱,例如多個RUN指令可以合并為一條怜姿;
- 及時刪除臨時文件和緩存文件:特別是在執(zhí)行apt-get指令后,/var/cache/apt下面會緩存一些安裝包疼燥;
- ·提高生成?度:如合理使用緩存沧卢,減少內(nèi)容目錄下的文件,或使用.dockerignore文件指定等醉者;
- 調(diào)整合理的指令順序:在開啟緩存的情況下但狭,內(nèi)容不變的指令盡量放在前面披诗,這樣可以盡量復用;
- 減少外部源的干擾:如果確實要從外部引入數(shù)據(jù)立磁,需要指定持久的地址呈队,并帶有版本信息,讓他人可以重復而不出錯唱歧。