1、基本結構
# This dockerfile uses the ubuntu image # VERSION 2 - EDITION 1 # Author: docker_user # Command format: Instruction [arguments / command ] .. # Base image to use, this nust be set as the first line FROM ubuntu # Maintainer: docker_user <docker_user at email.com> (@docker_user) MAINTAINER docker_user docker_user@email.com # Commands to update the image RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list RUN apt-get update && apt-get install -y nginx RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf # Commands when creating a new container CMD /usr/sbin/nginx
其中,開始必須指明所基於的鏡像名稱,接下來一般是說明維護者信息。后面則是鏡像操作指令,例如RUN指令,RUN指令將對鏡像執行跟隨的命令。每運行一條RUN指令,鏡像就添加新的一層,並提交。最后是CMD指令,用來指定運行容器時的操作命令。
Docker Hub上兩個熱門Dockerfile:
1.在debian:jessie基礎鏡像上安裝nginx環境,從而創建一個新的nginx鏡像:
FROM debian:jessie MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com" ENV NGINX_VERSION 1.10.1-1~jessie RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && \ echo "deb http://nginx.org/package/debian/ jessie nginx" >> /etc/apt/source.list && apt-get update && \ apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=$(NGINX_VERSION) \ nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && \ rm -rf /var/lib/apt/lists/* # forward request and error logs to docker log collector RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/err.log EXPOSE 80 443 CMD ["nginx","-g","daemon off;"]
2.基於buildpack-deps:jessie-scm基礎鏡像,安裝golang相關環境,制作一個GO語言的運行環境。
FROM buildpack-deps:jessie-scm # gcc fo cgo RUN apt-get update && apt-get install -y --no-install-recommends g++ gcc libc6-dev make && rm -rf /var/lib/apt/lists* ENV GOLANG_VERSION 1.6.3 ENV GOLANG_DOWNLOAD_RUL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz ENV GOLANG_DOWNLOAD_SHA256 cdd5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd7561275a87aeb RUN curl -fssL "$GOLANG_DOWNLOAD_RUL" -o golang.tar.gz && \ echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && tar -C /usr/local -xzf golang.tar.gz && rm golang.tar.gz ENV GOPATH $GOPATH/bin:/usr/local/go/bin:$PATH RUN mkdir -p "$GOPATH/bin" && chmod -R 777 "$GOPATH" WORKDIR $GOPATH COPY go-wrapper /usr/local/bin
2、指令說明
指令的一般格式為INSTRUNCTION arguments,指令包括FROM、MAINTAINER、RUN等。具體指令及說明如下:
指令 | 說明 |
---|---|
FROM | 指定所創建鏡像的基礎鏡像 |
MAINTAINER | 指定維護者信息 |
RUN | 運行命令 |
CMD | 指定啟動容器時默認執行的命令 |
LABEL | 指定生成鏡像的元數據標簽信息 |
EXPOSE | 聲明鏡像內服務所監聽的端口 |
ENV | 指定環境變量 |
ADD | 賦值指定的<src>路徑下的內容到容器中的<dest>路徑下,<src>可以為URL;如果為tar文件,會自動解壓到<dest>路徑下 |
COPY | 賦值本地主機的<scr>路徑下的內容到容器中的<dest>路徑下;一般情況下推薦使用COPY而不是ADD |
ENTRYPOINT | 指定鏡像的默認入口 |
VOLUME | 創建數據掛載點 |
USER | 指定運行容器時的用戶名或UID |
WORKDIR | 配置工作目錄 |
ARG | 指定鏡像內使用的參數(例如版本號信息等) |
ONBUILD | 配置當前所創建的鏡像作為其他鏡像的基礎鏡像時,所執行的創建操作的命令 |
STOPSIGNAL | 容器退出的信號 |
HEALTHCHECK | 如何進行健康檢查 |
SHELL | 指定使用SHELL時的默認SHELL類型 |
1.FROM
指定所創建的鏡像的基礎鏡像,如果本地不存在,則默認會去Docker Hub下載指定鏡像。
格式為:FROM<image>,或FROM<image>:<tag>,或FROM<image>@<digest>。
任何Dockerfile中的第一條指令必須為FROM指令。並且,如果在同一個Dockerfile文件中創建多個鏡像,可以使用多個FROM指令(每個鏡像一次)。
2.MAINTAINER
指定維護者信息,格式為MAINTAINER<name>。例如:
MAINTAINER image_creator@docker.com
該信息將會寫入生成鏡像的Author屬性域中。
3.RUN
運行指定命令。
格式為:RUN<command>或RUN ["executable","param1","param2"]。
注意:
后一個指令會被解析為json數組,所以必須使用雙引號。
前者默認將在shell終端中運行命令,即/bin/sh -c;后者則使用exec執行,不會啟動shell環境。
指定使用其他終端類型可以通過第二種方式實現,例如:
RUN ["/bin/bash","-c","echo hello"]
每條RUN指令將在當前鏡像的基礎上執行指定命令,並提交為新的鏡像。當命令較長時可以使用\換行。例如:
RUN apt-get update \ && apt-get install -y libsnappy-dev zliblg-dev libbz2-dev \ && rm -rf /var/cache/apt
4.CMD
CMD指令用來指定啟動容器時默認執行的命令。它支持三種格式:
1.CMD ["executable","param1","param2"] 使用exec執行,是推薦使用的方式;
2.CMD param1 param2 在/bin/sh中執行,提供給需要交互的應用;
3.CMD ["param1","param2"] 提供給ENTRYPOINT的默認參數。
每個Dockerfile只能有一條CMD命令。如果指定了多條命令,只有最后一條會被執行。入股用戶啟動容器時指定了運行的命令(作為run的參數),則會覆蓋掉CMD指定的命令。
5.LABEL
LABEL指令用來生成用於生成鏡像的元數據的標簽信息。
格式為:LABEL <key>=<value> <key>=<value> <key>=<value> ...。
例如:
LABEL version="1.0" LABEL description="This text illustrates \ that label-values can span multiple lines."
6.EXPOSE
聲明鏡像內服務所監聽的端口。
格式為:EXPOSE <port> [<port>...]
例如:
EXPOSE 22 80 443 3306
注意:
該命令只是起到聲明租用,並不會自動完成端口映射。
在容器啟動時需要使用-P(大寫P),Docker主機會自動分配一個宿主機未被使用的臨時端口轉發到指定的端口;使用-p(小寫p),則可以具體指定哪個宿主機的本地端口映射過來。
7.ENV
指定環境變量,在鏡像生成過程中會被后續RUN指令使用,在鏡像啟動的容器中也會存在。
格式為:ENV <key><value>或ENV<key>=<value>...。
例如:
ENV GOLANG_VERSION 1.6.3 ENV GOLANG_DOWNLOAD_RUL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz ENV GOLANG_DOWNLOAD_SHA256 cdd5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd7561275a87aeb RUN curl -fssL "$GOLANG_DOWNLOAD_RUL" -o golang.tar.gz && echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && tar -C /usr/local -xzf golang.tar.gz && rm golang.tar.gz ENV GOPATH $GOPATH/bin:/usr/local/go/bin:$PATH RUN mkdir -p "$GOPATH/bin" && chmod -R 777 "$GOPATH"
指令指定的環境變量在運行時可以被覆蓋掉,如docker run --env <key>=<value> built_image。
8.ADD
該指令將復制指定的<src>路徑下的內容到容器中的<dest>路徑下。
格式為:ADD<src> <dest>
其中<src>可以使Dockerfile所在目錄的一個相對路徑(文件或目錄),也可以是一個URL,還可以是一個tar文件(如果是tar文件,會自動解壓到<dest>路徑下)。<dest>可以使鏡像內的絕對路徑,或者相當於工作目錄(WORKDIR)的相對路徑。路徑支持正則表達式,例如:
ADD *.c /code/
9.COPY
復制本地主機的<src>(為Dockerfile所在目錄的一個相對路徑、文件或目錄)下的內容到鏡像中的<dest>下。目標路徑不存在時,會自動創建。路徑同樣支持正則。
格式為:COPY <src> <dest>
當使用本地目錄為源目錄時,推薦使用COPY。
10.ENTRYPOINT
指定鏡像的默認入口命令,該入口命令會在啟動容器時作為根命令執行,所有傳入值作為該命令的參數。
支持兩種格式:
1.ENTRYPOINT ["executable","param1","param2"] (exec調用執行);
2.ENTRYPOINT command param1 param2(shell中執行)。
此時,CMD指令指定值將作為根命令的參數。
每個Dockerfile中只能有一個ENTRYPOINT,當指定多個時,只有最后一個有效。
在運行時可以被--entrypoint參數覆蓋掉,如docker run --entrypoint。
11.VOLUME
創建一個數據卷掛載點。
格式為:VOLUME ["/data"]
可以從本地主機或者其他容器掛載數據卷,一般用來存放數據庫和需要保存的數據等。
12.USER
指定運行容器時的用戶名或UID,后續的RUN等指令也會使用特定的用戶身份。
格式為:USER daemon
當服務不需要管理員權限時,可以通過該指令指定運行用戶,並且可以在之前創建所需要的用戶。例如:
RUN groupadd -r nginx && useradd -r -g nginx nginx
要臨時獲取管理員權限可以用gosu或者sudo。
13.WORKDIR
為后續的RUN、CMD和ENTRYPOINT指令配置工作目錄。
格式為:WORKDIR /path/to/workdir。
可以使用多個WORKDIR指令,后續命令如果參數是相對的,則會基於之前命令指定的路徑。例如:
WORKDIR /a WORKDIR b WORKDIR c RUN pwd
則最終路徑為/a/b/c
14.ARG
指定一些鏡像內使用的參數(例如版本號信息等),這些參數在執行docker build命令時才以--build-arg<varname>=<value>格式傳入。
格式為:ARG<name>[=<default value>]。
則可以用docker build --build-arg<name>=<value>來指定參數值。
15.ONBUILD
配置當所創建的鏡像作為其他鏡像的基礎鏡像的時候,所執行創建操作指令。
格式為: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指令的內容,等價於在后面添加了兩條指令:
FROM image-A # Automatically run the following ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src
使用ONBUILD指令的鏡像,推薦在標簽中注明,例如:ruby:1.9-onbuild。
16.STOPSIGNAL
指定所創建鏡像啟動的容器接收退出的信號值。例如:
STOPSIGNAL singnal
17.HEALTHCHECK
配置所啟動容器如何進行健康檢查(如何判斷是否健康),自Docker 1.12開始支持。
格式有兩種:
1.HEALTHCHECK [OPTIONS] CMD command :根據所執行命令返回值是否為0判斷;
2.HEALTHCHECK NONE :禁止基礎鏡像中的健康檢查。
[OPTION]支持:
1.--inerval=DURATION (默認為:30s):多久檢查一次;
2.--timeout=DURATION (默認為:30s):每次檢查等待結果的超時時間;
3.--retries=N (默認為:3):如果失敗了,重試幾次才最終確定失敗。
18.SHELL
指定其他命令使用shell時的默認shell類型。
格式為: SHELL ["executable","parameters"]
默認值為 ["bin/sh","-c"]。
注意:
對於Windows系統,建議在Dockerfile開頭添加# escape=`來指定轉移信息。
3、創建鏡像
編寫玩Dockerfile之后,可以通過docker build命令來創建鏡像。
基本的docker build [選項] 內容路徑,該命令將讀取指定路徑下(包括子目錄)的Dockerfile,並將該路徑下的所有內容發送給Docker服務端,由服務端來創建鏡像。因此除非生成鏡像需要,否則一般建議放置Dockerfile的目錄為空目錄。
1.如果使用非內容路徑下的Dockerfile,可以通過-f選項來指定其路徑; 2.要指定生成鏡像的標簽信息,可以使用-t選項。
例如:指定Dockerfile所在路徑為 /tmp/docker_builder/,並且希望生成鏡像標簽為build_repo/first_image,可以使用下面的命令:
docker build -t build_repo/first_image /tmp/docker_builder
4、使用 .dockerignore文件
可以通過 .dockeringore文件(每一行添加一條匹配模式)來讓Docker忽略匹配模式路徑下的目錄和文件。例如:
# comment */tmp* */*/tmp* tmp? ~*
5、Dockerfile編寫小結
從需求出發,定制適合自己需求、高效方便的鏡像,可以參考他人優秀的Dockerfile文件,在構建中慢慢優化Dockerfile文件:
1.精簡鏡像用途: 盡量讓每個鏡像的用途都比較集中、單一,避免構造大而復雜、多功能的鏡像; 2.選用合適的基礎鏡像: 過大的基礎鏡像會造成構建出臃腫的鏡像,一般推薦比較小巧的鏡像作為基礎鏡像; 3.提供詳細的注釋和維護者信息: Dockerfile也是一種代碼,需要考慮方便后續擴展和他人使用; 4.正確使用版本號: 使用明確的具體數字信息的版本號信息,而非latest,可以避免無法確認具體版本號,統一環境; 5.減少鏡像層數: 減少鏡像層數建議盡量合並RUN指令,可以將多條RUN指令的內容通過&&連接; 6.及時刪除臨時和緩存文件: 這樣可以避免構造的鏡像過於臃腫,並且這些緩存文件並沒有實際用途; 7.提高生產速度: 合理使用緩存、減少目錄下的使用文件,使用.dockeringore文件等; 8.調整合理的指令順序: 在開啟緩存的情況下,內容不變的指令盡量放在前面,這樣可以提高指令的復用性; 9.減少外部源的干擾: 如果確實要從外部引入數據,需要制定持久的地址,並帶有版本信息,讓他人可以重復使用而不出錯。