層
Dockerfile 指令的順序很重要。Docker 構建由一系列有序的構建指令組成。Dockerfile 中的每個指令大致對應於映象中的一個層。下圖說明了 Dockerfile 如何轉換為容器映象中的層堆疊。


快取層
當你執行構建時,構建器會嘗試重用來自之前構建的層。如果映象中的一個層沒有改變,構建器會從構建快取中獲取它。如果一個層自上次構建以來發生了改變,那麼該層及其之後的層都必須重新構建。
上一節中的 Dockerfile 將所有專案檔案複製到容器中(COPY . .
),然後在接下來的步驟中下載應用程式依賴項(RUN go mod download
)。如果你要更改任何專案檔案,那麼這將使 COPY
層的快取失效。它還會使之後所有層的快取失效。


由於 Dockerfile 指令的當前順序,構建器必須再次下載 Go 模組,即使自上次下載以來沒有一個包發生改變。
更新指令順序
你可以透過重新排序 Dockerfile 中的指令來避免這種冗餘。更改指令順序,使下載和安裝依賴項發生在原始碼複製到容器之前。這樣,構建器就可以重用快取中的“依賴項”層,即使你對原始碼進行了更改。
Go 使用兩個名為 go.mod
和 go.sum
的檔案來跟蹤專案的依賴項。這些檔案對於 Go 來說就像 package.json
和 package-lock.json
對於 JavaScript 一樣。為了讓 Go 知道要下載哪些依賴項,你需要將 go.mod
和 go.sum
檔案複製到容器中。在 RUN go mod download
之前新增另一個 COPY
指令,這次只複製 go.mod
和 go.sum
檔案。
# syntax=docker/dockerfile:1
FROM golang:1.21-alpine
WORKDIR /src
- COPY . .
+ COPY go.mod go.sum .
RUN go mod download
+ COPY . .
RUN go build -o /bin/client ./cmd/client
RUN go build -o /bin/server ./cmd/server
ENTRYPOINT [ "/bin/server" ]
現在,如果你編輯你的原始碼,構建映象不會導致構建器每次都下載依賴項。COPY . .
指令出現在包管理指令之後,因此構建器可以重用 RUN go mod download
層。


總結
適當地排序 Dockerfile 指令可以幫助你在構建時避免不必要的步驟。
相關資訊
下一步
下一節將介紹如何使用多階段構建使構建執行得更快,並使最終輸出更小。