前幾篇我們介紹過怎麼打包成 Docker image,但是今天看了一下,發現 image 大小居然超過 500 MB,明明檔案不大,可是 image 大小卻這麼大,嗯,是該來最佳化一下。
首先我們要先做分析,我們可以使用 dive 這個工具來做分析,看到底是哪個步驟產出了大量的檔案。
安裝 dive 非常簡單,兩行就搞定了。
wget https://github.com/wagoodman/dive/releases/download/v0.8.1/dive_0.8.1_linux_amd64.deb
sudo dpkg -i dive_0.8.1_linux_amd64.deb
然後執行 dive ,就可以看到分析的結果,按上或下方向鍵,可以察看每個步驟的影響 (按 ctrl+c 可以離開)。
從執行的結果來看,整個 image 大小是 519MB,我們可以發現光是選用的 golang:1.13-alpine 就用掉 353 MB,之後安裝 go 的 std library 佔用了 98MB,beego 應用程式的原始碼以及建置後的結果,則佔用了 30MB。
已經知道哪幾個步驟比較有問題之後,就可以來一一處理了。
首先,Docker 最近有提出 Multi-Stage build,這可以避免處理肥大的建置環境問題。
我們對 Dockerfile 做調整,第一個是加了 base,當作最終結果的基礎
#
# base
#
FROM alpine:3.10 AS base
RUN apk add --no-cache curl wget
再來,之前分析的結果,建置所需的函式庫佔了三百多 MB。我們仍然要建置 (從 # builder 該行開始到 # final ),但是只要建置後的結果,所以在 final 那層 ( # final 該行之後),就只有複製 builder 層的結果過來到 base。
#
# builder,只為了建置而使用
#
FROM golang:1.13-alpine3.10 AS builder
# git
RUN apk add --no-cache git
# Recompile the standard library without CGO
RUN CGO_ENABLED=0 go install -a std
ENV APP_DIR /app
RUN mkdir -p $APP_DIR
# Set the entrypoint
ADD . $APP_DIR
# Compile the binary and statically link
RUN cd $APP_DIR && CGO_ENABLED=0 go build -ldflags '-d -w -s'
#
# final
#
FROM base AS final
ENV APP_DIR /app
RUN mkdir -p $APP_DIR
# 只複製我們需要的部份
COPY --from=builder /app/ithome-iron-beego $APP_DIR/ithome-iron-beego
COPY --from=builder /app/conf $APP_DIR/conf
COPY --from=builder /app/views $APP_DIR/views
ENTRYPOINT (cd $APP_DIR && ./ithome-iron-beego)
EXPOSE 8080
改完 Dockerfile 以後,重新建置看看
docker build -t elleryq/ithome-iron-beego:0.2.0 .
# p.s. 也可以用 dive 來 build,build 完後會直接帶出分析結果
dive build -t elleryq/ithome-iron-beego:0.2.0 .
分析的結果
我們可以看到,整個 image 大小變成只有 19MB 了。
這次只有改 Dockerfile 而已,完整的程式碼可以參考 Github