go專案dockerfile最佳實踐

寶樹吶發表於2020-07-29

1. 前言

這幾天在構建golang編寫的web專案中,關於dockerfile編寫的一些總結

可能是單純我比較菜(大霧

由於go應用在go build之後會生成一個二進位制檔案,且Go宣稱自己只需要Linux核心

大多數程式語言都依賴於直譯器,VM和/或系統庫

剛開始我按照常理思考,寫出瞭如下的dockerfile, 但是最終docker build出來的映象高達300多M, 這是由於golang這個基礎映象中的工具鏈及其依賴項(gitmercurial等)重達幾百MB,而這一部分我們在執行的時候是不需要的

FROM golang:1.14

ENV GO111MODULE=on \
    GOPROXY=https://goproxy.cn,direct \
    GIN_MODE=release \
    PORT=80
    
WORKDIR /app

COPY . .

RUN go build .

EXPOSE 80

ENTRYPOINT ["./toc-generator"]

2. 不需要cgo情況下的最佳實踐

docker有一個基本映象叫做scratch,它是一個空的映象,在臨時基礎映象上執行的應用程式只能訪問核心

至少在容器提供隔離的範圍內

所以此時我們的思路是

  1. golang基礎映象下build出二進位制檔案
  2. 然後使用scratch作為執行時的基礎映象
  3. 並且將上一個stage build出來的二進位制檔案它的相關依賴檔案copy到scratch下

所以我們現在的dockerfile大概如下

# 打包依賴階段使用golang作為基礎映象
FROM golang:1.14 as builder

# 啟用go module
ENV GO111MODULE=on \
    GOPROXY=https://goproxy.cn,direct

WORKDIR /app

COPY . .

# CGO_ENABLED禁用cgo 然後指定OS等,並go build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .

# 由於我不止依賴二進位制檔案,還依賴views資料夾下的html檔案還有assets資料夾下的一些靜態檔案
# 所以我將這些檔案放到了publish資料夾
RUN mkdir publish && cp toc-generator publish && \
    cp -r views publish && cp -r assets publish

# 執行階段指定scratch作為基礎映象
FROM scratch

WORKDIR /app

# 將上一個階段publish資料夾下的所有檔案複製進來
COPY --from=builder /app/publish .

# 為了防止程式碼中請求https連結報錯,我們需要將證書納入到scratch中
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/cert

# 指定執行時環境變數
ENV GIN_MODE=release \
    PORT=80

EXPOSE 80

ENTRYPOINT ["./toc-generator"]

3. 依賴cgo情況下的最佳實踐

由於需要依賴cgo,所以我們使用scratch無法滿足需求,我們需要另外一個執行時基礎映象alpine,看下dockerhub官方的介紹,它也僅僅只有5MB大小

所以替換下基礎映象,我們的dockerfile變成了如下的樣子:

# 打包依賴階段使用golang作為基礎映象
FROM golang:1.14 as builder

# 啟用go module
ENV GO111MODULE=on \
    GOPROXY=https://goproxy.cn,direct

WORKDIR /app

COPY . .

# 指定OS等,並go build
RUN GOOS=linux GOARCH=amd64 go build .

# 由於我不止依賴二進位制檔案,還依賴views資料夾下的html檔案還有assets資料夾下的一些靜態檔案
# 所以我將這些檔案放到了publish資料夾
RUN mkdir publish && cp toc-generator publish && \
    cp -r views publish && cp -r assets publish

# 執行階段指定scratch作為基礎映象
FROM alpine

WORKDIR /app

# 將上一個階段publish資料夾下的所有檔案複製進來
COPY --from=builder /app/publish .

# 指定執行時環境變數
ENV GIN_MODE=release \
    PORT=80

EXPOSE 80

ENTRYPOINT ["./toc-generator"]

參考連結

https://baijiahao.baidu.com/s?id=1617163590078677512&wfr=spider&for=pc

相關文章