工作中发现项目在镜像构建时,即使没有修改 go.mod 也依然会执行 go mod download 来拉取依赖,而不是使用镜像缓存,导致每次构建时间都很长
经过排查发现是使用 ARG 导致的镜像缓存失效
构建镜像时可以使用 ARG
指令来设置构建环境的环境变量
- 首先在 Dockerfile 中
ARG
指令定义参数名称,设置默认值
ARG <name>[=<default value>]
docker build
时使用--build-arg <name>=<value>
来传递参数
ARG
虽然和 ENV
指令一样都是设置环境变量,不过 ARG
设置的是构建环境时的环境变量,在容器运行时不会存在这些环境变量
ARG
指令可以在 FROM
指令前指定,也可以在 FROM
指令后使用
ARG
指令在 FROM 指令前
ARG
在 FROM
指令前指定,那么参数只能在 FROM
指令中使用
并且 ARG
的参数可以用在每个 FROM
指令中
ARG TAG=1.13.0
FROM golang:${TAG}
RUN echo tag:${TAG}
FROM golang:${TAG}
RUN echo tag:${TAG}
镜像构建时,FROM
指令会使用 TAG 的值,但是 RUN
指令并不会打印出 TAG 的值
$ docker build --build-arg TAG=latest --no-cache .
Sending build context to Docker daemon 2.048kB
Step 1/5 : ARG TAG=1.14.0
Step 2/5 : FROM golang:${TAG}
---> c4d6fdf2260a
Step 3/5 : RUN echo tag:${TAG}
---> Running in 9ee89387b298
tag:
Removing intermediate container 9ee89387b298
---> 8cd6b2627cad
Step 4/5 : FROM golang:${TAG}
---> c4d6fdf2260a
Step 5/5 : RUN echo tag:${TAG}
---> Running in d3f2673a7f71
tag:
Removing intermediate container d3f2673a7f71
---> e1a926150795
Successfully built e1a926150795
ARG
指令在 FROM
指令后
ARG
在 FROM
指令后的话,只会对当前的构建阶段有效
并且如果 ARG
参数的值修改,那么后续指令都可能不会使用镜像缓存
ARG
可能会使缓存失效这个问题就导致在使用的时候需要特别注意,如何过早的使用 ARG 指令可能会使后续一些依赖拉取之类的 RUN
指令强制执行,而不是使用之前的镜像缓存
ARG
导致镜像缓存失效
构建 golang 项目时,make build
时会使用 BUILD_VERSION
这个环境变量,所以需要在 docker build
时将 BUILD_VERSION
传递进去
以下 Dockerfile 为精简版示例,不可用于生产开发
FROM golang:1.15.0
ARG BUILD_VERSION
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN make build
问题
对于拉取依赖,只有在 go.mod,go.sum 修改时再去执行即可,其他情况应该使用镜像缓存
但是如果 BUILD_VERSION
发生修改,那么后续指令都不会使用镜像缓存,需要再次执行 RUN go mod downlond
建议
ARG
指令应该在接近使用的地方去执行,防止其他指令的镜像缓存失效
COPY . .
ARG BUILD_VERSION
RUN make build