跳转至

如何减少 golang 项目 docker 镜像的大小?


2024-05-07 by dongnan

环境描述

  • OS: Ubuntu Server 20.04 LTS
  • Docker: v20.10.12
  • App: 使用 golang 开发的项目,运行在 docker环境。

问题描述

下载的 golang 镜像 大小为 860MB

$ docker images | grep golang

golang                          1.21.5              e11dfa244376   3 weeks ago     815MB

编译的应用镜像 大小为 1.2GB

$ docker images | grep ade-server

ade_ade-server                  latest              b25caeb154d6   3 days ago      1.2GB

每次编译程序都要下载依赖包,例如:

$ docker-compose up -d --build

.

Building ade-server
Step 1/9 : FROM golang:1.21.5
 ---> e11dfa244376
Step 2/9 : MAINTAINER "dongnan"
 ---> Using cache
 ---> bc73e12f45e2
Step 3/9 : ENV GO111MODULE=on
 ---> Using cache
 ---> c81552632a8d
Step 4/9 : ENV GOPROXY=https://goproxy.cn,direct
 ---> Using cache
 ---> 8560be56a430
Step 5/9 : WORKDIR /opt
 ---> Using cache
 ---> c29f05adfe00
Step 6/9 : ADD .  /opt
 ---> Using cache
 ---> c3582af0b104
Step 7/9 : RUN go build -o main ./main.go
 ---> Running in 0ab89aa177d8
go: downloading github.com/gin-gonic/gin v1.9.1
# 省略30行
Removing intermediate container 0ab89aa177d8
 ---> 8ee2c83ecc8b
Step 8/9 : EXPOSE 8000
 ---> Running in f7c7fa56bd04
Removing intermediate container f7c7fa56bd04
 ---> dfae7d54f087
Step 9/9 : CMD ["/opt/main"]
 ---> Running in 5f50b1d099c0
Removing intermediate container 5f50b1d099c0
 ---> 8692607af8d4
Successfully built 8692607af8d4
Successfully tagged ade_ade-server:latest

Dockerfile(第1版)

FROM golang:1.21.5

MAINTAINER "dongnan"

# proxy
ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn,direct

# work
WORKDIR /opt
ADD .  /opt

# build
RUN go build -o main ./main.go

# port
EXPOSE 8000

# cmd
CMD ["/opt/main"]

这个 Dockerfile 有两个问题:

  • 每次 build 时都需要重新下载依赖包,浪费时间与带宽。
  • 每次 build 后的镜像太过臃肿,达到 1.2GB

解决方法

目标是,解决应用镜像 build时间长,build后镜像体积臃肿,这两个问题。

Dockerfile(第2版)

# builder
FROM golang:1.21.5 as builder

# proxy
ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn,direct

# build cache
WORKDIR /go/cache
ADD go.mod .
ADD go.sum .
RUN go mod download

# build app
WORKDIR /go/app
ADD . .
RUN GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o server main.go


# prod
#FROM scratch as prod
FROM alpine:3.19.0 as prod
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
        && apk update \
        && apk upgrade \
        && apk add --no-cache tzdata \
        && cp /usr/share/zoneinfo/Asia/Chongqing /etc/localtime
WORKDIR /ade
COPY --from=builder /go/app .

# port
EXPOSE 8000

# cmd
CMD ["/ade/server"]

第2版的 Dockerfile 有如下优化:

  1. 使用 多阶段构建 Docker镜像,主要分为builderprod
  2. builder 阶段,将go下载的模块缓存起来,只要go.modgo.sum文件没有变化,就会使用该缓存层。
  3. prod 阶段,使用轻量级的alpine基础镜像 ,而不是完整的Debian系统镜像 。
  4. go 编译时增加了-ldflags="-s -w"参数,禁用调试信息,以减小镜像大小。

验证

构建花费时间

再次build镜像,花费时间35秒 (使用缓存)

$ time docker-compose up -d --build

.

Building ade-server
Step 1/16 : FROM golang:1.21.5 as builder
 ---> e11dfa244376
Step 2/16 : ENV GO111MODULE=on
 ---> Using cache
 ---> b56e54272dcc
Step 3/16 : ENV GOPROXY=https://goproxy.cn,direct
 ---> Using cache
 ---> 3b39a04000f6
Step 4/16 : WORKDIR /go/cache
 ---> Using cache
 ---> bd805342f276
Step 5/16 : ADD go.mod .
 ---> Using cache
 ---> 99ea693efa5d
Step 6/16 : ADD go.sum .
 ---> Using cache
 ---> 92f56934d29f
Step 7/16 : RUN go mod download
 ---> Using cache
 ---> 26d4380cd883
Step 8/16 : WORKDIR /go/app
 ---> Using cache
 ---> 1785cf489d1e
Step 9/16 : ADD . .
 ---> 22fe961577d4
Step 10/16 : RUN GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o server main.go
 ---> Running in 4845069fdcce
Removing intermediate container 4845069fdcce
 ---> 65e9249e6012
Step 11/16 : FROM alpine:3.19.0 as prod
 ---> f8c20f8bbcb6
# 省略...
Step 13/16 : WORKDIR /ade
 ---> Running in 5afcfbac6683
Removing intermediate container 5afcfbac6683
 ---> dc3bdf6257f0
Step 14/16 : COPY --from=builder /go/app .
 ---> 708111f907c2
Step 15/16 : EXPOSE 8000
 ---> Running in 318581fd6a30
Removing intermediate container 318581fd6a30
 ---> f17f7a7ba87f
Step 16/16 : CMD ["/ade/server"]
 ---> Running in 7fcae6721855
Removing intermediate container 7fcae6721855
 ---> c9a42f5c909e
Successfully built c9a42f5c909e
Successfully tagged ade_ade-server:latest
Recreating ade_ade-server_1 ... done

real    0m34.606s
user    0m0.482s
sys 0m0.070s

注意

  • 这里使用 time 命令测试 build 构建镜像的时间。
  • 镜像构建过程中,注意 Using cache 关键字,特别是 go mod download 最重要的缓存层。

构建镜像大小

再次build镜像,大小为 28.5MB

$ docker images

.

REPOSITORY                      TAG                 IMAGE ID       CREATED          SIZE
ade_ade-server                  latest              c9a42f5c909e   2 minutes ago       28.5MB

其它

关于 golang 编译参数,有请 chatGPT 回答一下:

参考文档

回到页面顶部