1. 程式人生 > >使用 Docker 開發 - 使用多階段構建映象

使用 Docker 開發 - 使用多階段構建映象

多階段構建是一個新特性,需要 Docker 17.05 或更高版本的守護程序和客戶端。對於那些努力優化 Dockerfiles 並使其易於閱讀和維護的人來說,多階段構建非常有用。 ## 在多階段構建之前 構建映象時最具挑戰性的事情之一就是縮小映象大小。Dockerfile 中的每一條指令都會在映象中新增一個層,在進入下一層之前,您需要記住清除所有不需要的工件。要編寫一個真正高效的 Dockerfile,傳統上需要使用 shell 技巧和其他邏輯來保持層儘可能小,並確保每一層都有它需要的來自前一層的工件,而沒有其他東西。 實際上,有一個 Dockerfile 用於開發環境(包含構建應用程式所需的所有內容),同時有一個精簡的 Dockerfile 用於生產環境(僅包含應用程式和執行應用程式所需的內容)是非常常見的。這被稱為“建造者模式”。維護兩個 Dockerfiles 並不理想。 這裡有一個例子 `Dockerfile.build` 檔案以及符合上述建造者模式的 `Dockerfile`: `Dockerfile.build`: ```BASH FROM golang:1.7.3 WORKDIR /go/src/github.com/alexellis/href-counter/ COPY app.go . RUN go get -d -v golang.org/x/net/html \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . ``` 請注意,此示例還使用 Bash 操作符 `&&` 將兩個 `RUN` 命令人為壓縮在一起,以避免在映象中建立額外的層。這很容易發生故障,也很難維護。例如,很容易插入另一個命令而忘記使用 `\` 字元繼續行。 `Dockerfile`: ```BASH FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY app . CMD ["./app"] ``` `build.sh`: ```BASH #!/bin/sh echo Building alexellis2/href-counter:build docker build --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy \ -t alexellis2/href-counter:build . -f Dockerfile.build docker container create --name extract alexellis2/href-counter:build docker container cp extract:/go/src/github.com/alexellis/href-counter/app ./app docker container rm -f extract echo Building alexellis2/href-counter:latest docker build --no-cache -t alexellis2/href-counter:latest . rm ./app ``` 當你執行 `build.sh` 指令碼,它需要構建第一個映象,從中建立一個容器來複制工件,然後構建第二個映象。這兩個映象在您的系統上佔用空間,並且您的本地磁碟上仍然有 `app` 工件。 多階段構建極大地簡化了這種情況! ## 使用多階段構建 對於多階段構建,可以在 Dockerfile 中使用多個 `FROM` 語句。每個 `FROM` 指令都可以使用不同的基映象,並且它們都開始了構建的新階段。您可以選擇性地將工件從一個階段複製到另一個階段,捨棄在最終映象中您不想要的所有內容。為了說明這是如何工作的,讓我們使用多階段構建調整前一節中的 Dockerfile。 `Dockerfile`: ``` FROM golang:1.7.3 WORKDIR /go/src/github.com/alexellis/href-counter/ RUN go get -d -v golang.org/x/net/html COPY app.go . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=0 /go/src/github.com/alexellis/href-counter/app . CMD ["./app"] ``` 您只需要一個 Dockerfile。您也不需要單獨的構建指令碼。只要執行 `docker build`。 ```BASH $ docker build -t alexellis2/href-counter:latest . ``` 最終的結果是與前面相同的微小生產映象,並且顯著降低了複雜性。您不需要建立任何中間映象,也不需要將任何工件提取到本地系統中。 它是如何工作的?第二個 `FROM` 指令用 `alpine:latest` 映象作為基礎,開始一個新的構建階段。`COPY --from=0` 行只將前一階段的構建工件複製到這個新階段。Go SDK 和任何中間工件都會被留下,不會儲存在最終的映象中。 ## 為構建階段命名 預設情況下,沒有對階段進行命名,可以通過它們的整數來引用它們,`FROM` 指令的第一個整數從 0 開始。但是,您可以通過新增一