Dockerfile 參考

原文地址:https://docs.docker.com/engine/reference/builder/

[TOC]

Docker可以從Dockerfile中讀取指令來自動構建鏡像绞佩。Dockerfile是一個文本文件,它包含了用戶可以在命令調用以制作鏡像的命令铁追。用戶可以使用docker build連續(xù)執(zhí)行一些命令行指令來開啟一個自動構建拙毫。

此文檔描述了在Dockerfile中可以使用的命令脑又。當你讀完這個文檔時融虽,請參閱Dockfile最佳實踐獲取進階指南柒竞。

使用

docker build命令從Dockerfile和上下文構建鏡像匣掸。構建上下文是一個

構建的上下文是指定位置PATH或URL處的文件集

The docker build command builds an image from a Dockerfile and a context. The build’s context is the set of files at a specified location PATH or URL. The PATH is a directory on your local filesystem. The URL is a Git repository location.

A context is processed recursively. So, a PATH includes any subdirectories and the URL includes the repository and its submodules. This example shows a build command that uses the current directory as context:

$ docker build .
Sending build context to Docker daemon 6.51 MB
...
The build is run by the Docker daemon, not by the CLI. The first thing a build process does is send the entire context (recursively) to the daemon. In most cases, it’s best to start with an empty directory as context and keep your Dockerfile in that directory. Add only the files needed for building the Dockerfile.

CMD

CMD指令有三種用法:

  • CMD ["executable","param1","param2"] (exec形式, 這是首選形式)
  • CMD ["param1","param2"] (作為ENTRYPOINT默認參數)
  • CMD command param1 param2 (shell 形式)

一個Dockerfile里只能有一個CMD指令涝登。如果你有多個CMD指令雄家,只有 最后一個 生效。

CMD的主要目的是為運行容器提供默認值胀滚。 默認值可以包含一個可執(zhí)行文件趟济,也忽略可執(zhí)行文件,在此情況下必須同時指定ENTRYPOINT指令咽笼。

注: 如果CMD用于為ENTRYPOINT指令提供默認參數顷编,CMDENTRYPOINT都應該使用json數組格式。

注: exec形式傳遞json數組剑刑,意味著你必須使用雙引號(")而不是單引號(')引用字符

注:shell形式不同媳纬,exec形式不會像,那樣調用命令行shell施掏。這意味著沒有通常的shell處理钮惠。例如,CMD [ "echo", "$HOME" ]將不會對$HOME做變量替換七芭。如果你想使用shell處理可使用shell形式或直接執(zhí)行一個shell素挽,例如:["sh", "-c", "echo $HOME"]。當使用exec形式并且直接執(zhí)行一個shell狸驳,在這種情況下shell形式预明,執(zhí)行環(huán)境變量擴展的是shell,而不是docker耙箍。

當使用shellexec格式時撰糠,CMD指令設置鏡像運行時執(zhí)行的命令。

如果你使用CMDshell形式辩昆,<command>將以/bin/sh -c的形式運行:

FROM ubuntu
CMD echo "This is a test." | wc -

如果你想不使用shell運行你的<command>就必須以JSON數組的形式表示并且使用可執(zhí)行文件的完整路徑阅酪。數組形式是CMD的首選格式。任何獨立的參數都必須表達為數組的一個獨立的字符串卤材。

FROM ubuntu
CMD ["/usr/bin/wc","--help"]

如果你系統(tǒng)容器每次運行相同的可執(zhí)行文件遮斥,你應該考慮ENTRYPOINTCMD結合使用。

如果用戶為docker run指定了參數扇丛,那么他們將覆蓋CMD中指定的默認參數术吗。

注:不要混淆RUNCMDRUN實際上運行命令并提交結果帆精;CMD在構建時什么都不執(zhí)行较屿,只是指定鏡像將要執(zhí)行的命令隧魄。

EXPOSE

EXPOSE <port> [<port>...]

EXPOSE指令通知Docker容器運行時監(jiān)聽指定的網絡端口。EXPOSE不會使容器端口對宿主機可訪問隘蝎。要那么做购啄,你必須使用-p標記來發(fā)布一系列端口或者-P標記發(fā)布所有暴露端口。你可以暴露一個端口號并可以使用另一個端口對外發(fā)布嘱么。

要在宿主機系統(tǒng)上設置端口重定向狮含,使用-P標記Docker網絡功能支持網絡內創(chuàng)建網絡而不需要暴露端口曼振,詳細信息請查看功能概述几迄。

ADD

ADD有兩種形式:

  • ADD <src>... <dest>
  • ADD ["<src>",... "<dest>"] (路徑中包含空格需要這種形式)

ADD指令

ENTRYPOINT

ENTRYPOINT有2中形式:

  • ENTRYPOINT ["executable", "param1", "param2"] (exec 形式, 首選)
  • ENTRYPOINT command param1 param2 (shell 形式)

ENTRYPOINT允許你配置一個將作為可執(zhí)行程序運行的容器。

例如冰评,以下命令將啟動一個nginx默認監(jiān)控80端口:

docker run -i -t --rm -p 80:80 nginx

docker run <image>的命令行參數將被追加到以exec形式的ENTRYPOINT所有元素后面映胁,并且覆蓋使用CMD指定的所有元素。這使得參數可以被傳遞給入口, 例如甲雅,docker run <image> -d將傳遞 -d參數給入口解孙。你可以使用docker run --entrypoint標記覆蓋ENTRYPOINT執(zhí)行。

shell形式阻止任何CMD或者run的命令行參數被使用抛人,但是有個弊端弛姜,你的ENTRYPOINT將被作為/bin/sh -c的一個子命令啟動,不能傳遞信號函匕。這意味著可執(zhí)行程序不是容器ID為1的進程 - 并且不會接受Unix信號 - 所以你的可執(zhí)行程序不會接受來自docker stop <container>SIGTERM娱据。

只有Dockerfile最后一個ENTRYPOINT指令會生效蚪黑。

VOLUME

VOLUME ["/data"]

VOLUME指令創(chuàng)建一個具有指定名稱的掛載點并且將其標記作為從宿主機或者其他容器外部掛載卷盅惜。值可以是一個JSON數組,VOLUME ["/var/log"]忌穿,或者有多參數的純字符串抒寂,比如:VOLUME /var/log或者VOLUME /var/log /var/db。更多Docker客戶端的掛載指令信息/例子掠剑,移步文檔通過卷共享目錄屈芜。

docker run命令使用基礎鏡像內指定位置存在的任意數據初始化新創(chuàng)建的卷。比如朴译,認為以下Dockerfile片段:

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

這個Dockerfile的結果是致使docker run會創(chuàng)建一個新的掛載點/myvol并且拷貝gretting文件到新創(chuàng)建的卷井佑。

指定volumes的注意事項

關于Dockerfile中的volumes,請注意以下事項眠寿。

  • 基于Windows容器的Volumes 當使用基于Windows的容器躬翁,容器內volume的目標位置必須是以下之一:
    • 一個不存在的或者空目錄
    • C盤以外的驅動器:
  • Dockerfile內更改卷: 如果任何構建步驟在volume聲明之后修改了數據,這些修改將會被丟棄盯拱。
  • JSON 格式: 列表將會被作為一個JSON數組解析盒发。你必須使用雙引號(")而不是單引號(')將單詞包起來例嘱。
  • 主機目錄在容器運行時聲明: 主機目錄(掛載點)本質上是與主機相關的。這是為了保證鏡像的可移植性宁舰。因為一個指定的主機目錄不能保證在所有的主機上可用拼卵。因此,你不能在Dockerfile內掛載一個主機目錄蛮艰。VOLUME指令不支持指定一個主機目錄參數腋腮。你必須在容器創(chuàng)建或運行時指定掛載點。

Exec形式ENTRYPOINT實例

你可以使用ENTRYPOINTexec形式設置相當穩(wěn)定的默認命令和參數壤蚜,然后使用CMD任意一種形式設置額外的更可能被修改的其他附加默認值低葫。

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

但你運行該容器時,你僅僅可以看到top進程:

$ docker run -it --rm --name test  top -H
top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top

要進一步檢查結果仍律,可以使用docker exec

$ docker exec -it test ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  2.6  0.1  19752  2352 ?        Ss+  08:24   0:00 top -b -H
root         7  0.0  0.1  15572  2164 ?        R+   08:25   0:00 ps aux

并且你可以使用docker stop test請求top優(yōu)雅的退出嘿悬。

以下Dockerfile展示了使用ENTRYPOINT在前端運行Apache(例如,PID為1)水泉。

FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

如果你需要為單個可執(zhí)行程序寫一個啟動腳本善涨,你可以使用execgosu命令來確保最終執(zhí)行程序可以收到Unix信號。

#!/usr/bin/env bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"

最后草则,如果你需要在退出時做一些額外的清理(或者與其他容器通信)钢拧,或者配合執(zhí)行多個可執(zhí)行文件,你可能需要確保ENTRYPOINT腳本接受Unix信號炕横,傳遞他們并做更多工作:

#!/bin/sh
# Note: I've written this using sh so it works in the busybox container too

# USE the trap if you need to also do manual cleanup after the service is stopped,
#     or need to start multiple services in the one container
trap "echo TRAPed signal" HUP INT QUIT TERM

# start service in background here
/usr/sbin/apachectl start

echo "[hit enter key to exit] or run 'docker stop <container>'"
read

# stop service and clean up here
echo "stopping apache"
/usr/sbin/apachectl stop

echo "exited $0"

如果你使用docker run -it -p 80:80 --name test apache運行該鏡像源内,然后你可以使用docker exec檢查容器進程,或者docker top份殿,并且可以通過腳本停止Apache膜钓。

$ docker exec -it test ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  0.0   4448   692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
root        19  0.0  0.2  71304  4440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
www-data    20  0.2  0.2 360468  6004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
www-data    21  0.2  0.2 360468  6000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
root        81  0.0  0.1  15572  2140 ?        R+   00:44   0:00 ps aux
$ docker top test
PID                 USER                COMMAND
10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054               root                /usr/sbin/apache2 -k start
10055               33                  /usr/sbin/apache2 -k start
10056               33                  /usr/sbin/apache2 -k start
$ /usr/bin/time docker stop test
test
real    0m 0.27s
user    0m 0.03s
sys 0m 0.03s

注:你可以使用--entrypoint覆蓋ENTRYPOINT配置,但是這只會將二進制設置為execsh -c不會被使用)卿嘲。

注:exec形式被解析為JSON數組颂斜,意味著你必須使用雙引號(")包裹單詞而不是單引號(')。

注:不像shell形式拾枣,exec形式并不會調用shell命令沃疮。這意味著不會做普通的shell處理。例如梅肤,ENTRIPOIN ["echo", "$HOME"]將不能對$HOME做變量置換司蔬。如果你既想shell處理又想使用shell形式或直接執(zhí)行一shell,例如:ENTRYPOINT ["sh", "-c", "echo $HOME"]姨蝴。當使用exec形式和直接執(zhí)行shell時俊啼,在shell形式這種情況下,是shell做的環(huán)境變量擴展似扔,而不是docker吨些。

Shell形式ENTRYPOINT實例

你可以為ENTRYPOINT指定一個純文本的字符串搓谆,它會以/bin/sh -c的形式運行。這種形式將使用shell處理shell代替shell環(huán)境變量豪墅,并且將忽略任何CMD或者docker run命令的命令行參數泉手。為了確保docker stop能夠正常發(fā)出信號給任何長時間運行的ENTRYPOINT可執(zhí)行文件,您需要記住使用exec啟動它:

FROM ubuntu
ENTRYPOINT exec top -b

當你啟動鏡像偶器,你會看到PID為1的進程:

$ docker run -it --rm --name test top
Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
Load average: 0.08 0.03 0.05 2/98 6
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     R     3164   0%   0% top -b

它將會在執(zhí)行docker stop時徹底退出:

$ /usr/bin/time docker stop test
test
real    0m 0.20s
user    0m 0.02s
sys 0m 0.04s

如果你忘記了在ENTRYPOINT開頭增加exec:

FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1

你可以啟動它(為了下一步給它指定名稱):

$ docker run -it --name test top --ignored-param2
Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
CPU:   9% usr   2% sys   0% nic  88% idle   0% io   0% irq   0% sirq
Load average: 0.01 0.02 0.05 2/101 7
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     S     3168   0%   0% /bin/sh -c top -b cmd cmd2
    7     1 root     R     3164   0%   0% top -b

你可以看到top的輸出斩萌,ENTRYPOINT指定的不是PID 1。

如果你接下來執(zhí)行docker stop test屏轰,容器不會被徹底退出 - 超時以后top命令會被發(fā)送一個SIGKILL颊郎。

$ docker exec -it test ps aux
PID   USER     COMMAND
    1 root     /bin/sh -c top -b cmd cmd2
    7 root     top -b
    8 root     ps aux
$ /usr/bin/time docker stop test
test
real    0m 10.19s
user    0m 0.04s
sys 0m 0.03s

理解CMD和ENTRYPOINT如何交互

CMDENTRYPOINT指令都定義了當啟動一個容器時執(zhí)行什么命令。描述他們如何一起工作的規(guī)則很少霎苗。

  1. Dockerfile至少應該指定一個CMDENTRYPOINT命令姆吭。
  2. 當容器做一個可執(zhí)行程序時,ENTRYPOINT應該被定義唁盏。
  3. CMD應該被用作一種給ENTRYPOINT定義默認參數的方式内狸,或在容器中執(zhí)行ad-hoc命令的方式。
  4. 當運行容器時是用了交互參數時厘擂,CMD將被會被覆蓋昆淡。

下表顯示了對不同ENTRYPOINT / CMD組合執(zhí)行的命令:

No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市刽严,隨后出現(xiàn)的幾起案子昂灵,更是在濱河造成了極大的恐慌,老刑警劉巖舞萄,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件眨补,死亡現(xiàn)場離奇詭異,居然都是意外死亡鹏氧,警方通過查閱死者的電腦和手機渤涌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門佩谣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來把还,“玉大人,你說我怎么就攤上這事茸俭。” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵想虎,是天一觀的道長补憾。 經常有香客問我,道長腾窝,這世上最難降的妖魔是什么缀踪? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任居砖,我火速辦了婚禮,結果婚禮上驴娃,老公的妹妹穿的比我還像新娘奏候。我一直安慰自己,他們只是感情好唇敞,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布蔗草。 她就那樣靜靜地躺著,像睡著了一般疆柔。 火紅的嫁衣襯著肌膚如雪咒精。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天旷档,我揣著相機與錄音模叙,去河邊找鬼。 笑死鞋屈,一個胖子當著我的面吹牛向楼,可吹牛的內容都是我干的。 我是一名探鬼主播谐区,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼湖蜕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宋列?” 一聲冷哼從身側響起昭抒,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炼杖,沒想到半個月后灭返,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡坤邪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年熙含,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艇纺。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡怎静,死狀恐怖,靈堂內的尸體忽然破棺而出黔衡,到底是詐尸還是另有隱情蚓聘,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布盟劫,位于F島的核電站夜牡,受9級特大地震影響,放射性物質發(fā)生泄漏侣签。R本人自食惡果不足惜塘装,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一急迂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蹦肴,春花似錦袋毙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至裂七,卻和暖如春皆看,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背背零。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工腰吟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人徙瓶。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓毛雇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親侦镇。 傳聞我的和親對象是個殘疾皇子灵疮,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內容

  • 博客原文 本文接著上一篇文章《Dockerfile 參考手冊(一)》接續(xù)Dockerfile相關的學習。本文主要介...
    rabbitGYK閱讀 1,616評論 0 9
  • 一壳繁、Docker創(chuàng)建鏡像的方式有兩種: 一種通過commit的方式:把做了一系列操作的容器關閉震捣,然后利用docke...
    jie0112閱讀 3,829評論 0 3
  • 摘錄不同出處的與趨勢相關的言論,與君分享闹炉,感知及體會趨勢之美蒿赢! 關于股市打壓論 問:股市現(xiàn)在被人為操控打壓得厲害,...
    布衣之子閱讀 292評論 0 1
  • 今日打卡1:共計51分鐘 為何要為變質的雞肉花36.09美元渣触? 為什么動畫片要用名人配音羡棵? 推銷一罐嬰兒配方奶粉需...
    吟_f3da閱讀 182評論 0 0
  • 在人與人溝通的時候皂冰,你講的東西是他想聽的,或者關于他的話題啊犬,或者是能夠幫助到他的灼擂,這個話題就可以得到延續(xù),...
    李安娜126閱讀 295評論 0 1