# Dockerfile改动一行代码,Jenkins编译速度提升了将近80倍

如上一篇文章所讲的,因为磁盘空间不足的问题,仔细学习了一下docker build cache相关的内容,学习到

  • Docker 构建过程是将 Dockerfile 中的指令转化为一个个构建层(Build Layer)。每一个指令都会生成一个构建层,而所有构建层组合在一起,形成一个完整的镜像。构建过程中的每一步都是无状态的,意味着在同一主机上,对相同的 Dockerfile 执行相同的指令应该得到相同的结果。
  • 通过.dockerignore文件排除掉日志,编译类库文件等。保证文件的一致性,可以提高缓存构建层的复用

发现项目的Dockerfile文件有待改造的地方。通过对项目的简单两部操作,将代码编译速度提升了将近80倍。具体步骤如下:

# 1. 优化Dockerfile文件

# 原Dockerfile文件
# 编译基础镜像为golang:alpine
FROM golang:alpine AS builder

# 标记当前阶段为编译阶段
LABEL stage=gobuilder

# 修改Alpine Linux的软件包源为阿里云镜像源
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

# 更新软件包索引并安装tzdata时区数据包和upx工具
RUN apk update --no-cache && apk add --no-cache tzdata && apk add --no-cache upx

# 指定工作目录
WORKDIR /builder

# 禁用CGO
ENV CGO_ENABLED=0

# 设置公司golang代理服务
ENV GOPROXY=http://goproxy.office.xxxxxx.com,direct

# 忽略私有包的sum验签
ENV GONOSUMDB=goproxy.office.xxxxxx.com/*

# 赋值当前项目所有文件到容器工作目录
COPY . .

# 编译项目可执行文件,并压缩生成的二进制文件
RUN go build -ldflags="-s -w" -tags=jsoniter -o api/bin/main api/main.go \
    && upx -q -9 /builder/api/bin/main

# 容器运行镜像为alpine
FROM alpine

# 标记当前阶段为运行阶段
LABEL stage=gorunner

# 参数指定配置文件名称
ARG config_file

# 从builder同步时区
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ=Asia/Shanghai

# 新建日志目录
# RUN mkdir /data/applogs && mkdir /data/weblogs

# 指定工作目录
WORKDIR /app

# 从编译容器复制运行二进制文件和配置信息
COPY --from=builder /builder/api/bin/main /app/main
COPY --from=builder /builder/api/etc/${config_file} /app/api.yaml

# 运行服务
CMD ["./main", "-f", "api.yaml"]

在上面的Dockerfile RUN go build ....这条命令前增加一个命令RUN go mod download 生成golang 模块下载的构建层。这样不用每一次去构建模块了。

# 修改后Dockerfile文件
# 编译基础镜像为golang:alpine
FROM golang:alpine AS builder

# 标记当前阶段为编译阶段
LABEL stage=gobuilder

# 修改Alpine Linux的软件包源为阿里云镜像源
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

# 更新软件包索引并安装tzdata时区数据包和upx工具
RUN apk update --no-cache && apk add --no-cache tzdata && apk add --no-cache upx

# 指定工作目录
WORKDIR /builder

# 禁用CGO
ENV CGO_ENABLED=0

# 设置公司golang代理服务
ENV GOPROXY=http://goproxy.office.xxxxxx.com,direct

# 忽略私有包的sum验签
ENV GONOSUMDB=goproxy.office.xxxxxx.com/*

# 赋值当前项目所有文件到容器工作目录
COPY . .

# 下载go依赖模块
RUN go mod download

# 编译项目可执行文件,并压缩生成的二进制文件
RUN go build -ldflags="-s -w" -tags=jsoniter -o api/bin/main api/main.go \
    && upx -q -9 /builder/api/bin/main

# 容器运行镜像为alpine
FROM alpine

# 标记当前阶段为运行阶段
LABEL stage=gorunner

# 参数指定配置文件名称
ARG config_file

# 从builder同步时区
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ=Asia/Shanghai

# 新建日志目录
# RUN mkdir /data/applogs && mkdir /data/weblogs

# 指定工作目录
WORKDIR /app

# 从编译容器复制运行二进制文件和配置信息
COPY --from=builder /builder/api/bin/main /app/main
COPY --from=builder /builder/api/etc/${config_file} /app/api.yaml

# 运行服务
CMD ["./main", "-f", "api.yaml"]

# 2. 新增.dockerignore文件排除掉日志,编译类库文件

排除掉相关文件的copy操作。

# Ignore development and editor-related files
.DS_Store

# Ignore version control directories
.git/

# Exclude specific directories and their contents
tmp/

# 效果

# 编译时间对比

docker-build-df

# 编译缓存

docker-build-df