鏡像創(chuàng)建乏味耗時?為什么不用DockerFile
【編者的話】
Dockerfile是為快速構建Docker Image而設計的,它為構建鏡像提供了簡單的語法。Docker 會讀取當前目錄下的命名為Dockerfile的純文本文件并執(zhí)行里面的指令構建出一個Docker Image,這樣,在Docker中創(chuàng)建鏡像會更加簡單,并且易用。本篇文章對DockerFile入門知識及在實踐過程中的使用技巧進行整合,希望能夠幫助您在使用Dockerfiles以及構建鏡像時受益。
還記得我們介紹過的15個Docker命令嗎?那15個命令在手動創(chuàng)建鏡像時會用到,它們涵蓋鏡像的創(chuàng)建、提交、搜索、pull和push的功能。
現在問題來了,既然Docker能自動創(chuàng)建鏡像,那為什么要選擇耗時而又乏味的方式來創(chuàng)建鏡像呢?
Docker為我們提供了Dockerfile來解決自動化的問題。在這篇文章中,我們將討論什么是Dockerfile,它能夠做到的事情以及DockerFile一些基本語法。
命令為易于自動化
Dockerfile是包含創(chuàng)建鏡像所需要的全部指令?;谠贒ockerFile中的指令,我們可以使用Docker build命令來創(chuàng)建鏡像。通過減少鏡像和容器的創(chuàng)建過程來簡化部署。
Dockerfiles支持支持的語法命令如下:
- INSTRUCTION argument
指令不區(qū)分大小寫。但是,命名約定為全部大寫。
所有Dockerfile都必須以FROM命令開始。 FROM命令會指定鏡像基于哪個基礎鏡像創(chuàng)建,以及接下來的命令也會基于這個基礎鏡像(譯者注:CentOS和Ubuntu有些命令可是不一樣的)。FROM命令可以使用多次,表示會創(chuàng)建多個鏡像。具體語法如下:
- FROM <image name>
例如:
- FROM ubuntu
上面的指定告訴我們,新的鏡像將基于Ubuntu的鏡像來構建。
繼FROM命令,DockefFile還提供了一些其它的命令以實現自動化。在文本文件或Dockerfile文件中這些命令的順序就是它們被執(zhí)行的順序。
讓我們了解一下這些有趣的Dockerfile命令吧。
1. MAINTAINER:設置該鏡像的作者。語法如下:
- MAINTAINER <author name>
2. RUN:在shell或者exec的環(huán)境下執(zhí)行的命令。RUN指令會在新創(chuàng)建的鏡像上添加新的層,接下來提交的結果用于在Dockerfile的下一條指令。語法如下:
- RUN 《command》
3. ADD:復制文件指令,它有兩個參數<source>和<destination>。destination是容器內的路徑。source可以是URL或者是啟動配置上下文中的一個文件。語法如下:
- ADD 《src》 《destination》
4. CMD:提供了容器默認的執(zhí)行命令。 Dockerfile只允許CMD指令使用一次。 使用多個CMD會抵消之前所有的,只有最后一個生效。 CMD有三種形式:
- CMD ["executable","param1","param2"]
- CMD ["param1","param2"]
- CMD command param1 param2
5. EXPOSE:指定容器在運行時監(jiān)聽的端口。語法如下:
- EXPOSE <port>;
6. ENTRYPOINT:配置容器一個可執(zhí)行的命令,這意味著在每次使用鏡像創(chuàng)建容器時一個特定的應用程序可以被設置為默認程序。同時也意味著該鏡像每次被調用時僅能運行指定的應用。類似于CMD,Docker只允許一個ENTRYPOINT,多個ENTRYPOINT會抵消之前所有的,只執(zhí)行最后的ENTRYPOINT指令。語法如下:
- ENTRYPOINT [‘executable’, ‘param1’,’param2’]
- ENTRYPOINT command param1 param2
7. WORKDIR:指定RUN、CMD與ENTRYPOINT命令的工作目錄。語法如下:
- WORKDIR /path/to/workdir
8. ENV:設置環(huán)境變量。它們使用鍵值對,并增加運行的程序的靈活性。語法如下:
- ENV <key> <value>
9. USER:鏡像正在運行時設置一個UID。語法如下:
- USER <uid>
10. VOLUME:授權訪問從容器內到主機上的目錄。語法如下:
- VOLUME ['/data']
#p#
DockerFile最佳實踐
正如任何使用的應用程序,總會有遵循的最佳實踐。Dockerfiles為構建鏡像提供了簡單的語法。下面我們來看看在緩存、標簽、端口以及CMD與ENTRYPOINT這些方面,一些使用dockerfile的提示與技巧。
1:使用緩存
Dockerfile的每條指令都會將更改提交到新的鏡像,該鏡像將被用于下一個指令的基礎鏡像。如果一個鏡像存在相同的父類鏡像和指令(除了ADD)Docker將會使用鏡像而不是執(zhí)行該指令,即緩存。
為了有效地利用緩存,你需要保持你的Dockerfiles一致,并且改建在末尾添加。我所有的Dockerfiles開始于以下五行:
- FROM ubuntu
- MAINTAINER Michael Crosby <michael@crosbymichael.com>
- RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
- RUN apt-get update
- RUN apt-get upgrade -y
更改MAINTAINER指令會使Docker強制執(zhí)行RUN指令來更新apt,而不是使用緩存。
保持常用的Dockerfile指令在頂部來利用緩存。
2:使用標簽
除非你正在用Docker做實驗,否則你應當通過-t選項來docker build新的鏡像以便于標記構建的鏡像。一個簡單的可讀標簽將幫助您管理每個創(chuàng)建的鏡像。
docker build -t="crosbymichael/sentry" .
始終通過-t標記來構建鏡像。
3:公開端口
兩個Docker的核心概念是可重復和可移植。鏡像應該能運行在任何主機上并且能運行盡可能多的次數。在Dockerfiles中您有能力映射私有和公有端口,但是你永遠不要在Dockerfile中映射公有端口。通過映射公有端口到主機上,你將只能運行一個容器化應用程序實例。
- #private and public mapping
- EXPOSE 80:8080
- #private only
- EXPOSE 80
如果鏡像的消費者關心容器公有映射了哪個公有端口,他們可以在運行鏡像時設置-p選項,否則,Docker會給容器自動分配端口。
切勿在Dockerfile映射公有端口。
4:CMD與ENTRYPOINT的語法
無論CMD還是ENTRYPOINT都是直線前進的,但他們有一個隱藏的錯誤“功能”,如果你不知道的話他們可能會觸發(fā)問題。這些指令支持的兩種不同的語法。
- CMD /bin/echo
- #or
- CMD ["/bin/echo"]
這看起來好像沒什么問題,但深入細節(jié)里的魔鬼會將你絆倒。如果你使用第二個語法:CMD(或ENTRYPOINT)是一個數組,它執(zhí)行的命令完全像你期望的那樣。如果使用第一種語法,Docker會在你的命令前面加上/bin/sh -c。我記得一直都是這樣。
如果你不知道Docker修改了CMD命令,在命令前加上/bin/sh -c可能會導致一些意想不到的問題以及不容易理解的功能。因此,在使用這兩個指令你應當總是使用數組語法,因為兩者都會確切地執(zhí)行你打算執(zhí)行的命令。
使用CMD和ENTRYPOINT時,請務必使用數組語法。
5. CMD和ENTRYPOINT 聯合使用更好
以防你不知道ENTRYPOINT使您的容器化應用程序運行得像一個二進制文件,您可以在docker run期間給ENTRYPOINT參數傳遞,而不是擔心它被覆蓋(跟CMD不同)。當與CMD一起使用時ENTRYPOINT表現會更好。讓我們來研究一下我的Rethinkdb Dockerfile,看看如何使用它。
- #Dockerfile for Rethinkdb
- #http://www.rethinkdb.com/
- FROM ubuntu
- MAINTAINER Michael Crosby <michael@crosbymichael.com>
- RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
- RUN apt-get update
- RUN apt-get upgrade -y
- RUN apt-get install -y python-software-properties
- RUN add-apt-repository ppa:rethinkdb/ppa
- RUN apt-get update
- RUN apt-get install -y rethinkdb
- #Rethinkdb process
- EXPOSE 28015
- #Rethinkdb admin console
- EXPOSE 8080
- #Create the /rethinkdb_data dir structure
- RUN /usr/bin/rethinkdb create
- ENTRYPOINT ["/usr/bin/rethinkdb"]
- CMD ["--help"]
這是獲得容器化Rethinkdb全部所需。在頂部我們有標準的5行來確?;A鏡像是最新的,端口的公開等等......隨著ENTRYPOINT的設置,我們知道每當這個鏡像運行,在docker run過程中傳遞的所有參數將成為ENTRYPOINT(/usr/bin/rethinkdb)的參數。
在Dockerfile中我還設置了一個默認CMD參數--help。這樣做是為了docker run期間如果沒有參數的傳遞,rethinkdb將會給用戶顯示默認的幫助文檔。這是你所期望的與rethinkdb交互有著相同的功能。
- docker run crosbymichael/rethinkdb
輸出
- Running 'rethinkdb' will create a new data directory or use an existing one,
- and serve as a RethinkDB cluster node.
- File path options:
- -d [ --directory ] path specify directory to store data and metadata
- --io-threads n how many simultaneous I/O operations can happen
- at the same time
- Machine name options:
- -n [ --machine-name ] arg the name for this machine (as will appear in
- the metadata). If not specified, it will be
- randomly chosen from a short list of names.
- Network options:
- --bind {all | addr} add the address of a local interface to listen
- on when accepting connections; loopback
- addresses are enabled by default
- --cluster-port port port for receiving connections from other nodes
- --driver-port port port for rethinkdb protocol client drivers
- -o [ --port-offset ] offset all ports used locally will have this value
- added
- -j [ --join ] host:port host and port of a rethinkdb node to connect to
- .................
現在,讓我們帶上--bind all參數來運行容器。
- docker run crosbymichael/rethinkdb --bind all
輸出
- info: Running rethinkdb 1.7.1-0ubuntu1~precise (GCC 4.6.3)...
- info: Running on Linux 3.2.0-45-virtual x86_64
- info: Loading data from directory /rethinkdb_data
- warn: Could not turn off filesystem caching for database file: "/rethinkdb_data/metadata" (Is the file located on a filesystem that doesn't support direct I/O (e.g. some encrypted or journaled file systems)?) This can cause performance problems.
- warn: Could not turn off filesystem caching for database file: "/rethinkdb_data/auth_metadata" (Is the file located on a filesystem that doesn't support direct I/O (e.g. some encrypted or journaled file systems)?) This can cause performance problems.
- info: Listening for intracluster connections on port 29015
- info: Listening for client driver connections on port 28015
- info: Listening for administrative HTTP connections on port 8080
- info: Listening on addresses: 127.0.0.1, 172.16.42.13
- info: Server ready
- info: Someone asked for the nonwhitelisted file /js/handlebars.runtime-1.0.0.beta.6.js, if this should be accessible add it to the whitelist.
就這樣,一個全面的可以訪問db和管理控制臺的Rethinkdb實例就運行起來了,你可以用與鏡像交互一樣的方式來與其交互。它功能非常強大但是簡單小巧。當然,我喜歡簡單。
CMD和ENTRYPOINT 結合在一起使用更好。
我希望這篇文章可以使您在使用Dockerfiles以及構建鏡像時受益。展望未來,我相信Dockerfiles會成為Docker的重要一部分:簡單而且使用方便無論你是消費或是生產鏡像。我打算投入更多的時間來提供一個完整的,功能強大,但簡單的解決方案來使用Dockerfile構建Docker鏡像。
本文整理自文章:http://dockerone.com/article/103 & http://dockerone.com/article/131