Docker 能夠經過 Dockerfile 的內容來自動構建鏡像。python
Dockerfile 是一個包含建立鏡像全部命令的文本文件,經過docker build命令能夠根據 Dockerfile 的內容構建鏡像,在介紹如何構建以前先介紹下 Dockerfile 的基本語法結構。mysql
Dockerfile 有如下指令選項:nginx
用法:git
FROM <image>
用法:github
MAINTAINER <name>
指定建立鏡像的用戶golang
RUN 有兩種使用方式sql
每條RUN指令將在當前鏡像基礎上執行指定命令,並提交爲新的鏡像,後續的RUN都在以前RUN提交後的鏡像爲基礎,鏡像是分層的,能夠經過一個鏡像的任何一個歷史提交點來建立,相似源碼的 版本控制 。docker
exec 方式會被解析爲一個 JSON 數組,因此必須使用雙引號而不是單引號。exec 方式不會調用一個命令 shell,因此也就不會繼承相應的變量,如:shell
RUN [ "echo", "$HOME" ]
這種方式是不會達到輸出 HOME 變量的,正確的方式應該是這樣的數據庫
RUN [ "sh", "-c", "echo", "$HOME" ]
RUN產生的緩存在下一次構建的時候是不會失效的,會被重用,可使用--no-cache選項,即docker build --no-cache,如此便不會緩存。
CMD有三種使用方式:
CMD指定在 Dockerfile 中只能使用一次,若是有多個,則只有最後一個會生效。
CMD的目的是爲了在啓動容器時提供一個默認的命令執行選項。若是用戶啓動容器時指定了運行的命令,則會覆蓋掉CMD指定的命令。
CMD會在啓動容器的時候執行,build 時不執行,而RUN只是在構建鏡像的時候執行,後續鏡像構建完成以後,啓動容器就與RUN無關了,這個初學者容易弄混這個概念,這裏簡單註解一下。
EXPOSE <port> [<port>...]
告訴 Docker 服務端容器對外映射的本地端口,須要在 docker run 的時候使用-p或者-P選項生效。
ENV <key> <value> # 只能設置一個變量 ENV <key>=<value> ... # 容許一次設置多個變量
指定一個環節變量,會被後續RUN指令使用,並在容器運行時保留。
例子:
ENV myName="John Doe" myDog=Rex\ The\ Dog \ myCat=fluffy
等同於
ENV myName John Doe ENV myDog Rex The Dog ENV myCat fluffy
ADD <src>... <dest>
ADD複製本地主機文件、目錄或者遠程文件 URLS 從 而且添加到容器指定路徑中 。
支持經過 Go 的正則模糊匹配,具體規則可參見 Go filepath.Match
ADD hom* /mydir/ # adds all files starting with "hom" ADD hom?.txt /mydir/ # ? is replaced with any single character
COPY <src>... <dest>
COPY複製新文件或者目錄從 而且添加到容器指定路徑中 。用法同ADD,惟一的不一樣是不能指定遠程文件 URLS。
配置容器啓動後執行的命令,而且不可被 docker run 提供的參數覆蓋,而CMD是能夠被覆蓋的。若是須要覆蓋,則可使用docker run --entrypoint選項。
每一個 Dockerfile 中只能有一個ENTRYPOINT,當指定多個時,只有最後一個生效。
經過ENTRYPOINT使用 exec form 方式設置穩定的默認命令和選項,而使用CMD添加默認以外常常被改動的選項。
FROM ubuntu ENTRYPOINT ["top", "-b"] CMD ["-c"]
經過 Dockerfile 使用ENTRYPOINT展現前臺運行 Apache 服務
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"]
這種方式會在/bin/sh -c中執行,會忽略任何CMD或者docker run命令行選項,爲了確保docker stop可以中止長時間運行ENTRYPOINT的容器,確保執行的時候使用exec選項。
FROM ubuntu ENTRYPOINT exec top -b
若是在ENTRYPOINT忘記使用exec選項,則可使用CMD補上:
FROM ubuntu ENTRYPOINT top -b CMD --ignored-param1 # --ignored-param2 ... --ignored-param3 ... 依此類推
VOLUME ["/data"]
建立一個能夠從本地主機或其餘容器掛載的掛載點,後續具體介紹。
USER daemon
指定運行容器時的用戶名或 UID,後續的RUN、CMD、ENTRYPOINT也會使用指定用戶。
WORKDIR /path/to/workdir
爲後續的RUN、CMD、ENTRYPOINT指令配置工做目錄。可使用多個WORKDIR指令,後續命令若是參數是相對路徑,則會基於以前命令指定的路徑。
WORKDIR /a WORKDIR b WORKDIR c RUN pwd
最終路徑是/a/b/c。
WORKDIR指令能夠在ENV設置變量以後調用環境變量:
ENV DIRPATH /path WORKDIR $DIRPATH/$DIRNAME
最終路徑則爲 /path/$DIRNAME。
ONBUILD [INSTRUCTION]
配置當所建立的鏡像做爲其它新建立鏡像的基礎鏡像時,所執行的操做指令。
例如,Dockerfile 使用以下的內容建立了鏡像 image-A:
[...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]
若是基於 image-A 建立新的鏡像時,新的 Dockerfile 中使用 FROM image-A 指定基礎鏡像時,會自動執行 ONBUILD 指令內容,等價於在後面添加了兩條指令。
# Automatically run the following ADD . /app/src RUN /usr/local/bin/python-build --dir /app/src
使用ONBUILD指令的鏡像,推薦在標籤中註明,例如 ruby:1.9-onbuild。
# Nginx # # VERSION 0.0.1 FROM ubuntu MAINTAINER Victor Vieux <victor@docker.com> RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server # Firefox over VNC # # VERSION 0.3 FROM ubuntu # Install vnc, xvfb in order to create a 'fake' display and firefox RUN apt-get update && apt-get install -y x11vnc xvfb firefox RUN mkdir ~/.vnc # Setup a password RUN x11vnc -storepasswd 1234 ~/.vnc/passwd # Autostart firefox (might not be the best way, but it does the trick) RUN bash -c 'echo "firefox" >> /.bashrc' EXPOSE 5900 CMD ["x11vnc", "-forever", "-usepw", "-create"] # Multiple images example # # VERSION 0.1 FROM ubuntu RUN echo foo > bar # Will output something like ===> 907ad6c2736f FROM ubuntu RUN echo moo > oink # Will output something like ===> 695d7793cbe4 # You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with # /oink.
$ docker build --help Usage: docker build [OPTIONS] PATH | URL | - Build a new image from the source code at PATH --force-rm=false Always remove intermediate containers, even after unsuccessful builds # 移除過渡容器,即便構建失敗 --no-cache=false Do not use cache when building the image # 不實用 cache -q, --quiet=false Suppress the verbose output generated by the containers --rm=true Remove intermediate containers after a successful build # 構建成功後移除過渡層容器 -t, --tag="" Repository name (and optionally a tag) to be applied to the resulting image in case of success
參考文檔: Dockerfile Reference
爲了在docker build過程當中更快上傳和更加高效,應該使用一個.dockerignore文件用來排除構建鏡像時不須要的文件或目錄。例如,除非. Git 在構建過程當中須要用到,不然你應該將它添加到.dockerignore文件中,這樣能夠節省不少時間。
爲了下降複雜性、依賴性、文件大小以及構建時間,應該避免安裝額外的或沒必要要的包。例如,不須要在一個 數據庫 鏡像中安裝一個文本編輯器。
在大多數狀況下,一個容器應該只單獨跑一個程序。解耦應用到多個容器使其更容易橫向擴展和重用。若是一個服務依賴另一個服務,能夠參考 Linking Containers Together 。
咱們知道每執行一個指令,都會有一次鏡像的提交,鏡像是分層的結構,對於Dockerfile,應該找到可讀性和最小化層之間的平衡。
若是可能,經過字母順序來排序,這樣能夠避免安裝包的重複而且更容易更新列表,另外可讀性也會更強,添加一個空行使用\換行:
RUN apt-get update && apt-get install -y \ bzr \ cvs \ git \ mercurial \ subversion
鏡像構建過程當中會按照Dockerfile的順序依次執行,每執行一次指令 Docker 會尋找是否有存在的鏡像緩存可複用,若是沒有則建立新的鏡像。若是不想使用緩存,則能夠在docker build時添加--no-cache=true選項。
從基礎鏡像開始就已經在緩存中了,下一個指令會對比全部的子鏡像尋找是否執行相同的指令,若是沒有則緩存失效。在大多數狀況下只對比Dockerfile指令和子鏡像就足夠了。ADD和COPY指令除外,執行ADD和COPY時存放到鏡像的文件也是須要檢查的,完成一個文件的校驗以後再利用這個校驗在緩存中查找,若是檢測的文件改變則緩存失效。RUN apt-get -y update命令只檢查命令是否匹配,若是匹配就不會再執行更新了。
爲了有效地利用緩存,你須要保持你的 Dockerfile 一致,而且儘可能在末尾修改。
例子:
RUN apt-get update && apt-get install -y \ aufs-tools \ automake \ btrfs-tools \ build-essential \ curl \ dpkg-sig \ git \ iptables \ libapparmor-dev \ libcap-dev \ libsqlite3-dev \ lxc=1.0* \ mercurial \ parallel \ reprepro \ ruby1.9.1 \ ruby1.9.1-dev \ s3cmd=1.1.0*
ENV也能夠這樣定義變量:
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
如不推薦這種方式:
ADD http://example.com/big.tar.xz /usr/src/things/ RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things RUN make -C /usr/src/things all
推薦使用 curl 或者 wget 替換,使用以下方式:
RUN mkdir -p /usr/src/things \ && curl -SL http://example.com/big.tar.gz \ | tar -xJC /usr/src/things \ && make -C /usr/src/things all
若是不須要添加 tar 文件,推薦使用COPY。