Docker Dockerfile 指令
Dockerfile 指令
CMD
CMD指令用於指定一個容器啟動時要運行的命令。這有點兒類似於RUN指令,只是RUN指令是指定鏡像被構建時要運行的命令,而CMD是指定容器被啟動時要運行的命令。這和使用docker run命令啟動容器時指定要運行的命令非常類似
$ sudo docker run -i -t jamtur01/static_web /bin/true
可以認為上述命令和在Dockerfile中使用如下的CMD 指令是等效的。
CMD ["/bin/true"]
選項和命令一起構成數組的形式
CMD ["/bin/bash", "-1"]
需要註意的是,要運行的命令是存放在一個數組結構中的。這將告訴Docker按指定的原 樣來運行該命令。當然也可以不使用數組形式指定CMD指令,這時候Docker會在指定的 命令前加上/bin/sh -c這在執行該命令的時候可能會導致意料之外的行為,所以Docker推薦一直使用以數組語法來設置要執行的命令。
最後,還需牢記,使用docker run命令可以覆蓋CMD指令。如果我們在Dockerfile 裏指定了CMD指令,而同時在docker run命令行中也指定了要運行的命令,命令行中指 定的命令會覆蓋Dockerfile中的CMD指令。
CMD [ "/bin/bash"]
基於上述Dockerfile構建的鏡像在生成容器啟動時會有如下的表現
$ sudo docker run -t -i jamturOl/test
root0e643e6218589:/#
在docker run命令的末尾並未指定要運行什麽命令。實際上,Docker使用了 CMD指令中指定的命令。
如果指定:
$ sudo docker run -i -t jamturOl/test /bin/ps
PID TTY TIME CMD
1 ? 00:00:00 ps
$
可以看到,在這裏指定了想要運行的命令/bin/ps,該命令會列出所有正在運行的進程。容器並沒有啟動shell,而是通過命令行參數覆蓋了CMD指令中指 定的命令,容器運行後列出了正在運行的進程的列表,之後停止了容器。
在Dockerfile中只能指定一條CMD指令。如果指定了多條CMD指令,也只有最後一條 CMD指令會被使用。如果想在啟動容器時運行多個進程或者多條命令,可以考慮使用類似 Supervisor這樣的服務管理工具。
ENTRYPOINT
ENTRYPOINT指令與CMD指令非常類似,也很容易和CMD指令弄混。ENTRYPOINT指令提供的命令則不容易在啟動容器時被覆蓋。 實際上,docker run命令行中指定的任何參數都會被當做參數再次傳遞給ENTRYPOINT指令中指定的命令。
ENTRYPOINT ["/usr/sbin/nginx"]
類似於CMD指令也可以在該指令中通過數組的方式為命令指定相應的參數
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
重構鏡像,並將ENTRYPOINT設置為ENTRYPOINT ["/usr/sbin/nginx"]
$ sudo docker run -t -i image_name -g "daemon off;"
指定了-g "daemon off;”參數,這個參數會傳遞給用ENTRYPOINT指定的命令,
在這裏該命令為 /usr/sbin/nginx -g "daemon off;"。該命令會以前臺運行的方式啟動Nginx守護進程,此時這個容器就會作為一臺Web服務器來運行。
組合使用ENTRYPOINT和CMD指令
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-h"]
當啟動一個容器時,任何在命令行中指定的參數都會被傳遞給Nginx守護進 程。比如,我們可以指定-g "daemon off";參數讓Nginx守護進程以前臺方式運行。如果在啟動容器時不指定任何參數,則在CMD指令中指定的-h參數會被傳遞給Nginx守護進程,即Nginx服務器會以/usr/sbin/nginx-h的方式啟動,該命令用來顯示Nginx的幫助信息。這使我們可以構建一個鏡像,該鏡像既可以運行一個默認的命令,同時它也支持通過 docker run命令行為該命令指定可覆蓋的選項或者標誌。
如果確實需要,你也可以在運行時通過docker run的--entrypoint標誌覆蓋 ENTRYPOINT 指令。
WORKDIR
WORKDIR指令用來在從鏡像創建一個新容器時,在容器內部設置一個工作目錄, ENTRYPOINT和域CMD指定的程序會在這個目錄下執行。可以使用該指令為Dockerfile中後續的一系列指令設置工作目錄,也可以為最終的容器設置工作目錄。
WORKDIR /opt/webapp/db
RUN bundle install
WORKDIR /opt/webapp
ENTRYPOINT [ "rackup"]
這裏將工作目錄切換為/opt/webapp/db後運行了 bundle install命令,之後又將工作目錄設置/opt/webapp,最後設置了ENTRYPOINT指令來啟動rackup命令。可以通過-w標誌在運行時覆蓋工作目錄
$ sudo docker run -ti -w /var/log ubuntu pwd
/var/log
ENV
ENV指令用來在鏡像構建過程中設置環境變量
ENV RVM_PATH /home/rvm/
這個新的環境變量可以在後續的任何RUN指令中使用,這就如同在命令前面指定了環境變量前綴一樣
RUN gem install unicorn
在其他指令中直接使用這些環境變量。
ENV TARGET_DIR /opt/app
WORKDIR $TARGET_DIR
在這裏設定了一個新的環境變量TARGET_DIR,並在WORKDIR中使用了它的值。因此實際上WORKDIR指令的值會被設為/opt/app。
如果需要,可以通過在環境變量前加上一個反斜線來進行轉義。
這些環境變量也會被持久保存到從我們的鏡像創建的任何容器中。如果我們在使用ENV RVM_PATH /home/rvm/指令構建的容器中運行env命令
root@bf42aadc7f09:~# env
...
RVM_ PATH= /home/rvm/
...
也可以使用docker run命令行的-e標誌來傳遞環境變量。這些變量將只會在運行時有效
$ sudo docker run -ti -e "WEB_PORT=8080" ubuntu env
HOME=/
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=792bl71c5e9f
TERM=xterm
WEB_PORT=8080
USER
USER指令用來指定該鏡像會以什麽樣的用戶去運行
USER nginx
基於該鏡像啟動的容器會以nginx用戶的身份來運行。我們可以指定用戶名或UID以及組或GID,甚至是兩者的組合。
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
也可以在docker run命令中通過-u選項來覆蓋該指令指定的值。
如果不指定用戶,默認為root
VOLUME
VOLUME指令用來向基於鏡像創建的容器添加卷。一個卷是可以存在於一個或者多個容器內的特定的目錄,這個目錄可以繞過聯合文件系統,並提供如下共享數據或者對數據進行持久化的功能。
卷可以在容器間共享和重用。
一個容器可以不是必須和其他容器共享卷。
對卷的修改是立時生效的。
對卷的修改不會對更新鏡像產生影響。
卷會一直存在直到沒有任何容器再使用它。
卷功能讓我們可以將數據(如源代碼)、數據庫或者其他內容添加到鏡像中而不是將這些內容提交到鏡像中,並且允許我們在多個容器間共享這些內容。我們可以利用此功能來測試容器和內部的應用程序代碼,管理日誌,或者處理容器內部的數據庫。
VOLUME ["/opt/project"]
這條指令將會為基於此鏡像創建的任何容器創建一個名為/opt/project的掛載點。也可以通過指定數組的方式指定多個卷
VOLUME ["/opt/project", "/data"]
至於掛載到了主機的哪個地方,可以通過docker inspect進行查看。
ADD
ADD指令用來將構建環境下的文件和目錄復制到鏡像中。比如,在安裝一個應用程序時。 ADD指令需要源文件位置和目的文件位置兩個參數,
ADD software.lic /opt/application/software.lic
這裏的ADD指令將會將構建目錄下的software.lic文件復制到鏡像中的 /opt/application/software.lic。指向源文件的位置參數可以是一個URL或者構建上下文或環境中文件名或者目錄。不能對構建目錄或者上下文之外的文件進行ADD操作。
在ADD文件時,Docker通過目的地址參數末尾的字符來判斷文件源是目錄還是文件。 如果目標地址以/結尾,那麽Docker就認為源位置指向的是一個目錄。如果目的地址不是以/結尾,那麽Docker就 認為源位置指向的是文件。文件源也可以使用URL的格式
ADD http://wordpress.org/latest.zip /root/wordpress.zip
最後值得一提的是,ADD在處理本地歸檔文件(tar archive)時還有一些小魔法。如果 將一個歸檔文件(合法的歸檔文件包括gzip、bzip2、xz)指定為源文件,Docker會自動將 .歸檔文件解開(unpack)
ADD latest.tar.gz /var/www/wordpress/
這條命令會將歸檔文件latest.tar.gz解開到/var/www/wordpress/目錄下。 Docker解開歸檔文件的行為和使用帶-x選項的tar命令一樣:該指令執行後的輸出是原目的目錄己經存在的內容加上歸檔文件中的內容。如果目的位置的目錄下己經存在了和歸檔文件同名的文件或者目錄,那麽目的位置中的文件或者目錄不會被覆蓋。
最後,如果目的位置不存在的話,Docker將會為我們創建這個全路徑,包括路徑中的 任何目錄。新創建的文件和目錄的模式為0755,並且UID和GID都是0。
ADD指令會使得構建緩存變得無效,這一點也非常重要。如果通過ADD指令向鏡像添加一 個文件或者目錄,那麽這將使Dockerfile中的後續指令都不能繼續使用之前的構建緩存
COPY
COPY指令非常類似於ADD,它們根本的不同是COPY只關心在構建上下文中復制本地文件,而不會去做文件提取(extraction)和解壓(decompression)的工作。
COPY conf.d/ /etc/apache2/
這條指令將會把本地conf.d目錄中的文件復制到/etc/apache2/目錄中。
文件源路徑必須是一個與當前構建環境相對的文件或者目錄,本地文件都放到和 Dockerfile同一個目錄下。不能復制該目錄之外的任何文件,因為構建環境將會上傳到 Docker守護進程,而復制是在Docker守護進程中進行的。任何位於構建環境之外的東西都 是不可用的。COPY指令的目的位置則必須是容器內部的一個絕對路徑。
任何由該指令創建的文件或者目錄的UID和GID都會設置為0。
如果源路徑是一個目錄,那麽這個目錄將整個被復制到容器中,包括文件系統元數據; 如果源文件為任何類型的文件,則該文件會隨同元數據一起被復制。在這個例子裏,源路徑 以/結尾,所以Docker會認為它是目錄,並將它復制到目的目錄中。
如果目的位置不存在,Docker將會自動創建所有需要的目錄結構,就像mkdir -p命令那樣。
ONBUILD
ONBUILD指令能為鏡像添加觸發器(trigger)。當一個鏡像被用做其他鏡像的基礎鏡像時(比如你的鏡像需要從某未準備好的位置添加源代碼,或者你需要執行特定於構建鏡像的 環境的構建腳本),該鏡像中的觸發器將會被執行。觸發器會在構建過程中插入新指令,我們可以認為這些指令是緊跟在FROM之後指定的。
ONBUILD ADD . /app/src
ONBUILD RUN cd /app/src && make
上面的代碼將會在創建的鏡像中加入ONBUILD觸發器,ONBUILD指令可以在鏡像上運 行docker inspect命令來查看
$ sudo docker inspect 508efa4e4bf8
"OnBuild":[
"ADD . /app/src",
"RUN cd /app/src/ && make"
為Apache2鏡像構建一個全新的Dockerfile,該鏡像名為jamturOl/apache2
FROM ubuntu:14.04
MAINTAINER James Turnbull "[email protected]"
RUN apt-get update
RUN apt-get install -y apache2
ENV APACHE—RUN一USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ONBUILD ADD . /var/www/
EXPOSE 80
ENTRYPOINT ["/usr/sbin/apache2"]
CMD ["-D", "FOREGROUND"]
構建該鏡像
$ sudo docker build -t="jamturOl/apache2".
Step 7 : ONBUILD ADD . /var/www/
> Running in 0ell7f6ea4ba
—> a79983575b86 Successfully built a79983575b86
在新構建的鏡像中包含一條ONBUILD指令,該指令會使用ADD指令將構建環境所在的目錄下的內容全部添加到鏡像中的/var/www/目錄下。我們可以輕而易舉地將這個Dockerfile作為一個通用的Web應用程序的模板,可以基於這個模板來構建Web應用程序。這種機制使我每次都會將本地源代碼添加到鏡像,也支持為不同的應用程序進行一些特定的配置或者設置構建信息。這時可以將jamtur01/apache2當做一個鏡像模板。
ONBUILD觸發器會按照在父鏡像中指定的順序執行,並且只能被繼承一次(也就是說只能在子鏡像中執行,而不會在孫子鏡像中執行)。如果我們再基於jamturOl/webapp構建一個鏡像,則新鏡像是jamtur01/apache2的孫子鏡像,因此在該鏡像的構建過程中ONBUILD觸發器是不會被執行的。
這裏有好幾條指令是不能用在ONBUILD指令中的,包括FROM、MAINTAINER和ONBUILD 本身。之所以這麽規定是為了防止在Dockerfile構建過程中產生遞歸調用的問題。
Docker Dockerfile 指令