利用Buildx和分段构建把docker构建的GO应用从1.xGB减少到22mb和构建时长压缩到10秒内

376 阅读2分钟

记录一下优化的过程吧,docker build应用有两个痛点,一个时间太长,一个应用太大,浏览了一下相关的文章都是复制黏贴,只能自己动手了。

准备,以下是需要先了解的东西

  • docker
  • docker buildx 一个新的构建工具
  • docker buildkit 一个新的构建引擎

优化.1

拆分为多段构建,示例代码

FROM node:16.19.1-alpine as react_build

WORKDIR /app

COPY . .

RUN npm i

RUN npm build

# 阶段2
FROM alpine:latest

WORKDIR /app

COPY --from=react_build /app/dist ./frontend

优化.2

docker版本需大于18.09

启用buildkit github.com/moby/buildk…

# syntax = docker/dockerfile:experimental

使用run --mount缓存(其余请自行查阅文档)

OptionDescription
idid 设置一个标志,以便区分缓存。
target (必填项)缓存的挂载目标文件夹。
ro,readonly只读,缓存文件夹不能被写入。
sharingshared private locked 值可供选择。sharing 设置当一个缓存被多次使用时的表现,由于 BuildKit 支持并行构建,当多个步骤使用同一缓存时(同一 id)会发生冲突。shared 表示多个步骤可以同时读写,private 表示当多个步骤使用同一缓存时,每个步骤使用不同的缓存,locked 表示当一个步骤完成释放缓存后,后一个步骤才能继续使用该缓存。
from缓存来源(构建阶段),不填写时为空文件夹。
source来源的文件夹路径。
RUN --mount=type=cache,target=/app/node_modules,id=neteasep_app_npm_module,sharing=locked \
    --mount=type=cache,target=/root/.npm,id=npm_cache \
    npm i --registry=https://registry.npm.taobao.org

使用docker buildx build代替docker build(mac desktop自带了无需开启特性,其他平台需要手动开启)

优化.3

在最后的步骤尽可能使用小的镜像

FROM scratch

FROM alpine:latest

具体用什么镜像自行选择

最终运行的效果

10s内完成,构建的任务是并发进行的 image.png 备注:初次构建的时间可能会长一点,但也会比优化前节省一半以上的时间。

image.png 初始包在1.2GB左右

完整代码

# syntax = docker/dockerfile:experimental
# 第一阶段:构建 React 前端
FROM node:16.19.1-alpine as react_build

WORKDIR /app

COPY ui/package*.json ./

RUN --mount=type=cache,target=/app/node_modules,id=neteasep_app_npm_module,sharing=locked \
    --mount=type=cache,target=/root/.npm,id=npm_cache \
    npm i --registry=https://registry.npm.taobao.org

#RUN npm i --registry=https://registry.npm.taobao.org
COPY ui ./

RUN --mount=type=cache,target=/app/node_modules,id=neteasep_app_npm_module,sharing=locked \
    npm run build

# 第二阶段:构建 Go 后端
FROM golang:1.20.2 as go_build

WORKDIR /app

COPY go.mod go.sum ./
RUN go env -w GOPROXY=https://goproxy.cn,direct
RUN go env -w GO111MODULE=on
RUN --mount=type=cache,target=/app/go-build,id=neteasep_app_gobuild,sharing=locked \
    go mod download

COPY . ./
RUN --mount=type=cache,target=/app/go-build,id=neteasep_app_gobuild,sharing=locked \
  CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -installsuffix cgo -o main .

# 第三阶段:生成最终镜像
FROM scratch

WORKDIR /app

COPY --from=react_build /app/dist ./frontend
COPY --from=go_build /app/main .

EXPOSE 7878

ENTRYPOINT ["./main"]