使用Dockerfile創建鏡像
Dockerfile是一個文本格式的配置文件,用戶可以使用Dockerfile來快速創建自定義的鏡像。
基本結構
Dockerfile由一行行命令語句組成,並且支持以#開頭的註釋行。
一般而言,Dockerfile主體內容分爲四部分:
- 基礎鏡像信息;
- 維護者信息;
- 鏡像操作指令;
- 容器啓動時執行指令;
例:一個簡單的示例
【文檔解析】
首行可以通過註釋來指定解析器命令,後續通過註釋說明鏡像的相關信息。主體部分首先使用FROM指定指明所基於的鏡像名稱,接下來一般是使用LABEL指令說明維護者信息。後面則是鏡像操作指令,例如RUN指令對鏡像執行跟隨的命令。每運行一行RUN指令,鏡像添加新的一層,並提交。最後是CMD指令,來指定運行容器時的操作指令。
例:下面是Docker Hub上兩個熱門鏡像nginx和Go的Dockerfile例子
- 第一個是在debian:jessie基礎鏡像基礎上安裝Nginx環境,從而創建一個新的nginx鏡像:
FROM debian:jessie
LABEL maintainer docker_user<[email protected]>
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/packages/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/error.log
EXPOSE 80 443
CMD ["nginx","-g","daemon off;"]
- 第二個是基於buildpack-deps:jessie-scm基礎鏡像,安裝Golang相關環境,只做一個Go語言的運行環境鏡像:
FROM buildpack-deps:jessie-scm
#gcc for 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_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 cdde5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd7561275a87aeb
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -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 /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
COPY go-wrapper /usr/local/bin/
指令說明
Dockerfile中指令的一般格式爲INSTRUCTION arguments,包括“配置指令”(配置鏡像信息)和“操作指令”(具體執行操作),參見表8-1。
-
配置指令
1、ARG:定義創建鏡像過程中使用的變量
格式:ARG <name> [=<default value>]
在執行docker build時,可以通過-build-arg[=]來爲變量賦值。當鏡像編譯成功後,ARG指定的變量將不再存在(ENV指定的變量將在鏡像中保留)
2、FROM:指定所創建鏡像的基礎鏡像
格式:FROM <image> [AS <name>] 或 FROM <image>:<tag> [AS <name>] 或 FROM <image>@<digest> [AS <name>]
任何Dockerfile中第一條指令必須爲FROM指令。並且,如果在同一個Dockerfile中創建多個鏡像時,可以使用多個FROM指令(每個鏡像一次)。
爲了保證鏡像精簡,可以使用體積較小的鏡像如:
- Alpine;
- Debian;
3、LABEL:可以爲生成的鏡像添加元數據標籤信息。這些信息可以用來輔助過濾出特定鏡像。
格式:LABEL <key>=<value> <key>=<value> <key>=<value>...
例:
LABEL version="1.0.0-rc3"
LABEL author="yeasy@github" date="2020-01-01"
LABEL description="This text illistrates that label-values can span multiple lines."
4、ERPOSE:聲明鏡像內服務監聽的端口
格式:EXPOSE <port> [<port>/<protocol>...]
【注】
- 該指令只是起到聲明作用,並不會自動完成端口映射;
- 若要映射端口出來,在啓動容器時可以使用-P參數(Docker主機會自動分配一個宿主機的臨時端口)或-p HOST_PORT:CONTAINER_PORT參數(具體指定所映射的本地端口)
5、ENV
指定環境變量,在鏡像生成過程中會被後續RUN指令使用,在鏡像啓動的容器中也會存在
格式:ENV <key> <value> 或 ENV <key>=<value>...
例:
ENV APP_VERSION=1.0.0
ENV APP_HOME=/usr/local/app
ENV PATH $PATH:/usr/local/bin
指令指定的環境變量在運行時可以被覆蓋掉,如docker run --env <key>=<value> built_image
【注】
注意當一條ENV指令中同時爲多個環境變量賦值並且值也是從環境變量讀取時,會爲變量都賦值後再更新。如下面指令,最終結果爲key1=value1 AND key2=value2:
ENV key1=value2
ENV key1=value1 key2=${key1}
6、ENTRYPOINT:指定鏡像的默認入口命令,該入口命令會在啓動容器時作爲根命令執行,所有傳入值作爲該命令的參數。
格式:
- ENTRYPOINT ["executable","param1","param2"]: exec調用執行;
- ENTRYPOINT command param1 param2: shell中執行;
此時,CMD指令指定值將作爲根命令的參數。
【注】每個Dockerfile中只能有一個ENTRYPOINT,當指定多個時,只有最後一個起效。在運行時候,可被--entrypoint覆蓋。
7、VOLUME:創建一個數據掛載點
格式:VOLUME ["/data"]
運行容器時可以從本地主機或其他容器掛載數據卷,一般用來存放數據庫和需要保持的數據等。
8、USER:指定運行容器時的用戶名或UID,後續的RUN等指令也會使用指定的用戶身份
格式:USER daemon
當服務不需要管理員權限時,可以通過該命令指定運行用戶,並且可以在Dockerfile中創建所需要的用戶。
例:
RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres
【注】要臨時獲取管理員權限可以使用gosu命令。
9、WORKDIR:爲後續的RUN、CMD、ENTRYPOINT指令配置工作目錄
格式:WORKDIR /path/to/workdir
可以使用多個WORKDIR指令,後續命令如果參數是相對路徑,則會基於之前命令指定的路徑。
例:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
則最終路徑爲/a/b/c
【注】爲了避免出錯,推薦WORKDIR指令中只使用絕對路徑。
10、ONBUILD:指定當基於所生成鏡像創建子鏡像時,自動執行的操作指令
格式:ONBUILD [INSTRUCTION]
11、STOPSIGNAL:指定所創建鏡像啓動的容器接收退出的信號值
格式:STOPSIGNAL signal
12、HEALTHCHECK:配置所啓動容器如何進行健康檢查(如何判斷健康與否)
格式:HEALTHCHECK [OPTIONS] CMD command:根據所執行指令返回值是否爲0來判斷;
HEALTHCHECKK NONE:禁止基礎鏡像中的健康檢查;
[OPTIONS]參數解析:
- --interval=DURATION (default:30s):過多久檢查一次;
- --timeout=DURATION (dafalut:30s):每次檢查等待結果的超時;
- -retries=N (default:3):如果失敗了,重試幾次才最終確定失敗;
13、SHELL:指定其他命令使用shell時的默認shell類型
格式:SHELL ["executable","parameters"]
默認值爲["/bin/sh","-c"]
-
操作指令
1、RUN:運行指定命令
格式:RUN <command> 或 RUN ["executable","param1","param2"]
【注】
- 後者指令會被解析爲JSON數組,因此必須使用雙引號;
- 前者默認將在shell終端中運行命令,即/bin/sh -c;
- 後者使用exec執行,不會啓動shell環境;
指定使用其他終端類型課可以通過第二種方式實現:RUN ["/bin/bash","-c","echo hello"]
2、CMD:用來指定啓動容器時默認執行的命令
支持三種格式:
- CMD ["executable","param1","param2"]:相當於執行executable param1 param2【推薦】;
- CMD command param1 param2:在默認的Shell中執行,提供給需要交互的應用;
- CMD ["param1","param2"]:提供給ENTRYPOINT的默認參數;
【注】
- 每個Dockerfile只能有一條CMD命令。如果指定了多條命令,只有最後一條會被執行;
- 如果用戶確定容器時手動指定了運行的命令(作爲run的參數),則會覆蓋CMD指定的命令;
3、ADD:添加內容到鏡像
格式:ADD <src> <dest>
格式解析:這條命令將複製指定的<src>路徑下內容到容器中的<dest>路徑下;同時,src可以是相對路徑、URL、tar文件(自動解壓爲目錄),dest可以是鏡像內絕對路徑或者相對於工作目錄(WORKDIR)的相對路徑(支持正則格式)。
4、COPY:複製內容到鏡像
格式:COPY <src> <dest>
複製本地主機的<src>(爲Dockerfile所在目錄的相對路徑、文件或目錄)下內容到鏡像中的<dest>;目標路徑不存在時,會自動創建;路徑同樣支持正則格式。
【注】COPY和ADD指令功能相似,當使用本地目錄爲源目錄時,推薦使用COPY。
-
創建鏡像
編寫完成Dockerfile之後,可以通過docker [image] build命令來創建鏡像。
格式:docker build [OPTIONS] PATH | URL | -
該命令讀取指定路徑下的Dockerfile,並將該路徑下所有數據作爲上下文發送給Docker服務端。Docker服務端在校驗Dockerfile格式通過後,逐條執行其中定義的指令,碰到ADD、COPY和RUN指令會生成一層新的鏡像。最終如果創建成功,會返回最終鏡像的ID。
如果上下文過大,會導致發送大量數據給服務端,延緩創建過程。因此除非是生成鏡像所必須的文件,不然不要放到上下文路徑下。如果使用非上下文路徑下的Dockerfile,可以通過-f選項來指定其路徑。
例:上下文路徑爲/tmp/docker_builder/,並且希望生成鏡像標籤爲builder/first_image:1.0.0,可以使用如下
docker build -t builder/first_image:1.0.0 /tmp/docker_builder/
1、命令選項
2、選擇父鏡像
大部分情況下,生成新的鏡像都需要通過FROM指令來指定父鏡像。父鏡像是生成鏡像的基礎,會直接影響到所生成鏡像的大小和功能。
用戶可選擇兩種鏡像作爲父鏡像:
- 基礎鏡像;
- 普通的鏡像(由第三方創建,基於基礎鏡像);
基礎鏡像比較特殊,其Dockerfile中往往不存在FROM指令,或者基於scratch鏡像,這意味着其在整個鏡像處於根的位置。
例:下面定義了一個簡單的基礎鏡像,將用戶提前編譯好的二進制可執行文件binary複製到鏡像中,運行容器時執行binary指令
FROM scratch
ADD binary /
CMD ["/binary"]