1. 程式人生 > >Docker學習筆記(三):Dockerfile及多步驟構建映象

Docker學習筆記(三):Dockerfile及多步驟構建映象

## Dockerfile指令 官方文件地址:https://docs.docker.com/engine/reference/builder/ Dockerfile是一個文字格式的配置檔案,其內容包含眾多指令,使用者可以使用它快速的建立自定義映象。 ### 部分指令列表 指令|作用|備註 -|-|- FROM|指定基礎映象|任何Dockerfile中的第一條指令都必須是FROM
一個檔案中可以存在多個FROM指令。 LABEL|為映象新增元資料標籤資訊。 ARG|定義建立映象過程中使用的變數,編譯成功後不存在。|在執行docker build時,指定--builder-arg為變數賦值。 ENV|設定環境變數|在映象啟動時也會存在。
docker run --env key=value 會覆蓋同名變數 WORKDIR|指定工作目錄|可以使用多個,建議使用絕對路徑。 VOLUME|建立資料卷掛載點|例如`VOLUME ["/data/a","/data/b"]` EXPOSE|宣告映象內服務監聽的埠|只起宣告作用,不會自動完成對映。 USER|指定執行容器時的使用者名稱或ID|後續RUN指令也會以這個使用者身份執行。 STOPSIGNAL|指定所建立映象啟動的容器接收退出的訊號值 ### COPY/ADD COPY src dst / ADD src dst 其相同點是:作用都是複製內容到映象中;dst不存在時會建立;路徑支援正則。 不同點在於: - ADD的src可以是相對於Dockerfile的相對路徑;也可以是一個URL;還可以是一個tar檔案(自動解壓)。 - COPY的src只能是檔案或者目錄。 除了目的明確是要將一個URL或者tar檔案作為src的情況下,其他情況推薦使用COPY。 ### CMD/ENTRYPOINT #### 命令格式 - exec方式: ["executable","param1","param2"](JSON陣列,所以一定要是雙引號) - shell方式: command param1 param2 CMD與ENTRYPOINT兩種方式都支援,但推薦使用exec方式。 #### 作用 在任意一個Dockerfile下: - 只有最後一條CMD才會被執行。用來指定容器啟動時預設執行的命令及引數。但是會被docker run命令列引數覆蓋。 - 只有最後一條ENTRYPOINT才會被執行。用來配置容器啟動時的執行命令。並且會將docker run的命令列引數或者CMD的所有引數追加在ENTRYPOINT指令後作為引數。執行時可以被--entrypoint引數覆蓋。 #### 虛擬碼 ``` finallyCommand = "" if exists(ENTRYPOINT) { finallyCommand = ENTRYPOINT if exists(dockerRunCommandParam){ // 情景一 finallyCommand += dockerRunCommandParam }elseif exists(CMD) { // 情景二。除了CMD指令本身,包括後面JSON陣列所有 finallyCommand += CMDParams } // 情景三 }elseif exists(dockerRunCommandParam){ // 情景四 finallyCommand = dockerRunCommandParams }elseif exists(CMD){ // 情景五 finallyCommand = CMD } ``` 總結起來一句話:有ENTRYPOINT,CMD和docker run指定的命令都作為引數追加到ENTRYPOINT的引數後;沒有ENTRYPOINT,docker run指定了命令就執行,否則執行CMD(如果有的話)。 #### 實操 Dockerfile內容、構建映象 ``` FROM alpine:latest ENTRYPOINT ["/bin/echo","entrypoint"] -> [[email protected]] [~/work/docker] docker build -t test . // 情景三 -> [[email protected]] [~/work/docker] docker run --rm test entrypoint // 情景一 -> [[email protected]] [~/work/docker] docker run --rm test 12 34 entrypoint 12 34 ``` Dockerfile新增CMD指令、構建映象 ``` FROM alpine:latest ENTRYPOINT ["/bin/echo","entrypoint"] CMD ["/bin/echo","cmd"] -> [[email protected]] [~/work/docker] docker build -t test . // 情景二:CMD中的 "/bin/echo" 沒有被當做命令執行,而是與"cmd"一起成為了ENTRYPOINT的引數。 -> [[email protected]] [~/work/docker] docker run --rm test entrypoint /bin/echo cmd ``` Dockerfile刪除ENTRYPOINT指令、構建映象 ``` FROM alpine:latest CMD ["/bin/echo","cmd"] -> [[email protected]] [~/work/docker] docker build -t test . // 情景五 -> [[email protected]] [~/work/docker] docker run --rm test cmd // 情景四 -> [[email protected]] [~/work/docker] docker run --rm test echo 33 33 ``` ### RUN exec方式:RUN ["executable","param1","param2"] shell方式:RUN command param1 param2 每條RUN指令將在當前映象基礎上執行指令,並且提交為新的映象層。當命令較長時可以使用\來換行 ### ONBUILD ONBUILD [INSTRUCTION] 作為父映象被使用時自動執行的命令。對孫子映象無效。可用於自動編譯,檢查等。 假如父映象ParentImage的Dockerfile中有如下指令: ``` ONBUILD RUN mkdir /root/test ``` 使用docker build基於ParentImage建立子映象ChildImage的時候,會先執行ParentImage中的ONBUILD指令。等價於在ChildImage中添加了: ``` RUN mkdir /root/test ``` ### HEALTHCHECK 健康檢查 HEALTHCHECK [OPTIONS] CMD command :根據執行命令返回值判斷,0是成功,1是不健康。 HEALTHCHECK NONE :禁止健康檢查 OPTIONS引數如下: - --interval=DURATION (default: 30s) 多長時間檢查一次 - --timeout=DURATION (default: 30s) 檢查一次的超時時間 - --start-period=DURATION (default: 0s) 開始階段時長,此階段內第一次成功之前的失敗不計入retries。 - --retries=N (default: 3) 確定最終失敗的重試次數 ## 構建映象 ### docker build docker build [OPTIONS] PATH | URL | - 該命令預設讀取指定路徑下的Dockerfile(也可使用 -f 指定),並將該路徑下的所有資料作為上下文傳送給Docker服務端。逐條執行指令,生成映象。 ### 選擇父映象 一般情況下都需要使用FROM來指定父映象,所以父映象會影響到新生成映象的大小和功能。 通常有兩種映象可作為父映象:基礎映象和普通映象(由第三方建立,基於基礎映象)。基礎映象一般是基於scratch或者Dockerfile中不存在FROM指令。 ### 多步驟構建 對於編譯型語言通常需要編譯環境和執行環境兩個映象: - 編譯環境映象:包括完整的編譯環境、依賴庫等,體積較大。作用是將程式碼編譯為二進位制程式。 - 執行環境映象:執行二進位制程式,而不需要與編譯環境,體積比較小。 app.go ``` package main import "fmt" func main() { fmt.Println("Hello World") } ``` Dockerfile中使用兩次FROM ``` FROM golang:1.14-alpine as builder WORKDIR /go/src/test COPY app.go . RUN CGO_ENABLED=0 GOOS=linux go build -o app app.go FROM alpine:latest COPY --from=builder /go/src/test/app /root/ #此處 --from=builder 也可以改為 --from=0 CMD ["/root/app"] ``` 構建、執行 ``` -> [[email protected]] [~/work/docker] docker build -t hello . -> [[email protected]] [~/work/docker] docker run --rm hello Hello World ``` ## 小技巧 ### 清理untagged映象 多階段構建會生成編譯環境映象,也會將之前的同名映象變為`:`,清理此類映象可執行以下命令: ``` docker rmi $(docker images --filter dangling=true -q) ``` ### COPY --from指定其他映象 COPY指令的--from選項也可以指定本地或者遠端倉庫的映象 準備一個Dockerfile,內容是從ubuntu映象中COPY一個檔案到新映象的/root/下 ``` FROM alpine:latest COPY --from=ubuntu:latest /bin/bash /root/ CMD ["/bin/ls","/root/"] ``` dokcer build 構建映象 ``` -> [[email protected]] [~/work/docker] docker build -t test . Sending build context to Docker daemon 19.46kB Step 1/3 : FROM alpine:latest ---> f70734b6a266 Step 2/3 : COPY --from=ubuntu:latest /bin/bash /root/ latest: Pulling from library/ubuntu d51af753c3d3: Pull complete fc878cd0a91c: Pull complete 6154df8ff988: Pull complete fee5db0ff82f: Pull complete Digest: sha256:747d2dbbaaee995098c9792d99bd333c6783ce56150d1b11e333bbceed5c54d7 Status: Downloaded newer image for ubuntu:latest ---> Using cache ---> 082f95ffaa69 Step 3/3 : CMD ["/bin/ls","/root/"] ---> Using cache ---> 76fa9d9a1abd Successfully built 76fa9d9a1abd Successfully tagged test:latest ``` dokcer run 執行映象 ``` -> [[email protected]] [~/work/docker] docker run --rm test bash ``` ## 注意事項 - 使用`.dockerignore`檔案,避免傳送不必要的資料 - 提供註釋和維護者資訊 - 正確使用映象版本號 - 每條RUN都會提交為新的映象層,儘量合併RUN指令 - 刪除快取和臨