Docker
能夠從Dockerfile
中讀取指令來自動構建鏡像。Dockerfile
是一個文本文件,它包含了用戶能夠在命令調用以製做鏡像的命令。用戶可使用docker build
連續執行一些命令行指令來開啓一個自動構建。前端
此文檔描述了在Dockerfile
中可使用的命令。當你讀完這個文檔時,請參閱Dockfile
最佳實踐獲取進階指南。nginx
docker build
命令從Dockerfile
和上下文構建鏡像。構建上下文是特定路徑或URL的文件集合。該路徑是你本地文件系統的一個目錄。URL是一個Git倉庫地址。docker
上下文會被遞歸處理。因此,路徑包含的任意字母路合URL包含的倉庫及其子模塊也會被處理。一下實例展現了一個使用當前目錄做爲上下文的build
命令:shell
$ docker build . Sending build context to Docker daemon 6.51 MB ...
構建由Docker daemon
執行, 而非cli。構建進程的第一件事是(遞歸的)發送上下文給守護進程(daemon)。在大多數狀況下,最好以一個空目錄下做爲上下文發送給守護進程而且保持Dockerfile
在該目錄下。只爲構建Dockerfile
增長必須的文件。apache
CMD
指令有三種用法:json
CMD ["executable","param1","param2"]
(exec
形式, 這是首選形式)CMD ["param1","param2"]
(做爲ENTRYPOINT
默認參數)CMD command param1 param2
(shell 形式)一個Dockerfile
裏只能有一個CMD
指令。若是你有多個CMD
指令,只有 最後一個 生效。ubuntu
CMD
的主要目的是爲運行容器提供默認值。 默認值能夠包含一個可執行文件,也忽略可執行文件,在此狀況下必須同時指定ENTRYPOINT
指令。數組
注: 若是CMD
用於爲ENTRYPOINT
指令提供默認參數,CMD
和ENTRYPOINT
都應該使用json
數組格式。注:
exec
形式傳遞json
數組,意味着你必須使用雙引號(")而不是單引號(')引用字符bash注: 與
shell
形式不一樣,exec
形式不會像,那樣調用命令行shell
。這意味着沒有一般的shell
處理。例如,CMD [ "echo", "$HOME" ]
將不會對$HOME
作變量替換。若是你想使用shell
處理可以使用shell
形式或直接執行一個shell
,例如:["sh", "-c", "echo $HOME"]
。當使用exec
形式而且直接執行一個shell
,在這種狀況下shell
形式,執行環境變量擴展的是shell
,而不是docker
。網絡
當使用shell
或exec
格式時,CMD
指令設置鏡像運行時執行的命令。
若是你使用CMD
的shell
形式,<command>
將以/bin/sh -c
的形式運行:
FROM ubuntu CMD echo "This is a test." | wc -
若是你想不使用shell
運行你的<command>
就必須以JSON
數組的形式表示而且使用可執行文件的完整路徑。數組形式是CMD
的首選格式。任何獨立的參數都必須表達爲數組的一個獨立的字符串。
FROM ubuntu CMD ["/usr/bin/wc","--help"]
若是你係統容器每次運行相同的可執行文件,你應該考慮ENTRYPOINT
和CMD
結合使用。
若是用戶爲docker run
指定了參數,那麼他們將覆蓋CMD
中指定的默認參數。
注:不要混淆RUN
和CMD
。RUN
實際上運行命令並提交結果;CMD
在構建時什麼都不執行,只是指定鏡像將要執行的命令。
EXPOSE <port> [<port>...]
EXPOSE
指令通知Docker
容器運行時監聽指定的網絡端口。EXPOSE
不會使容器端口對宿主機可訪問。要那麼作,你必須使用-p
標記來發布一系列端口或者-P
標記發佈全部暴露端口。你能夠暴露一個端口號並可使用另外一個端口對外發布。
要在宿主機系統上設置端口重定向,使用-P
標記。Docker
網絡功能支持網絡內建立網絡而不須要暴露端口,詳細信息請查看功能概述。
ADD
有兩種形式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
(路徑中包含空格須要這種形式)ADD
指令
ENTRYPOINT
有2中形式:
ENTRYPOINT ["executable", "param1", "param2"]
(exec
形式, 首選)ENTRYPOINT command param1 param2
(shell
形式)ENTRYPOINT
容許你配置一個將做爲可執行程序運行的容器。
例如,如下命令將啓動一個nginx
默認監控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
執行。
shell
形式阻止任何CMD
或者run
的命令行參數被使用,可是有個弊端,你的ENTRYPOINT
將被做爲/bin/sh -c
的一個子命令啓動,不能傳遞信號。這意味着可執行程序不是容器ID爲1的進程 - 而且不會接受Unix信號 - 因此你的可執行程序不會接受來自docker stop <container>
的SIGTERM
。
只有Dockerfile
最後一個ENTRYPOINT
指令會生效。
VOLUME ["/data"]
VOLUME
指令建立一個具備指定名稱的掛載點而且將其標記做爲從宿主機或者其餘容器外部掛載卷。值能夠是一個JSON
數組,VOLUME ["/var/log"]
,或者有多參數的純字符串,好比:VOLUME /var/log
或者VOLUME /var/log /var/db
。更多Docker
客戶端的掛載指令信息/例子,移步文檔經過卷共享目錄。
docker run
命令使用基礎鏡像內指定位置存在的任意數據初始化新建立的卷。好比,認爲如下Dockerfile
片斷:
FROM ubuntu RUN mkdir /myvol RUN echo "hello world" > /myvol/greeting VOLUME /myvol
這個Dockerfile
的結果是導致docker run
會建立一個新的掛載點/myvol
而且拷貝gretting
文件到新建立的卷。
關於Dockerfile
中的volumes
,請注意如下事項。
基於Windows
容器的Volumes
: 當使用基於Windows
的容器,容器內volume
的目標位置必須是如下之一:
C
盤之外的驅動器:Dockerfile
內更改卷: 若是任何構建步驟在volume
聲明以後修改了數據,這些修改將會被丟棄。JSON
數組解析。你必須使用雙引號(")而不是單引號(')將單詞包起來。Dockerfile
內掛載一個主機目錄。VOLUME
指令不支持指定一個主機目錄
參數。你必須在容器建立或運行時指定掛載點。你可使用ENTRYPOINT
的exec
形式設置至關穩定的默認命令和參數,而後使用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
優雅的退出。
如下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"]
若是你須要爲單個可執行程序寫一個啓動腳本,你可使用exec
和gosu
命令來確保最終執行程序能夠收到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 "$@"
最後,若是你須要在退出時作一些額外的清理(或者與其餘容器通訊),或者配合執行多個可執行文件,你可能須要確保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
配置,可是這隻會將二進制設置爲exec
(sh -c
不會被使用)。注:
exec
形式被解析爲JSON
數組,意味着你必須使用雙引號(")包裹單詞而不是單引號(')。注:不像
shell
形式,exec
形式並不會調用shell
命令。這意味着不會作普通的shell
處理。例如,ENTRIPOIN ["echo", "$HOME"]
將不能對$HOME
作變量置換。若是你既想shell
處理又想使用shell
形式或直接執行一shell
,例如:ENTRYPOINT ["sh", "-c", "echo $HOME"]
。當使用exec
形式和直接執行shell
時,在shell
形式這種狀況下,是shell
作的環境變量擴展,而不是docker
。
你能夠爲ENTRYPOINT
指定一個純文本的字符串,它會以/bin/sh -c
的形式運行。這種形式將使用shell
處理shell
代替shell
環境變量,而且將忽略任何CMD
或者docker run
命令的命令行參數。爲了確保docker stop
可以正常發出信號給任何長時間運行的ENTRYPOINT
可執行文件,您須要記住使用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
它將會在執行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。
若是你接下來執行docker stop test
,容器不會被完全退出 - 超時之後top
命令會被髮送一個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
指令都定義了當啓動一個容器時執行什麼命令。描述他們如何一塊兒工做的規則不多。
Dockerfile
至少應該指定一個CMD
或ENTRYPOINT
命令。ENTRYPOINT
應該被定義。CMD
應該被用做一種給ENTRYPOINT
定義默認參數的方式,或在容器中執行ad-hoc
命令的方式。CMD
將被會被覆蓋。下表顯示了對不一樣ENTRYPOINT
/ CMD
組合執行的命令:
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 |