当我们在完全使用gitlab runner,或者其他工具,借助完整的Dockerfile完成项目镜像制作中时,大大提高了我们的运维发布效率,但是越来越长的docker build时间也成为快速发布上线的障碍了,我们就来总结一下有哪些优化docker build的方法。
1. 充分利用docker build镜像分层缓存策略
- 这也是我们最常用的第一种加速构建镜像的方式,以nodejs项目为例:
FROM node:12.18-alpine
LABEL maintainer="xxx<xx@xxx.com>"
# 安装常用工具链
RUN \
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk add --no-cache \
bash \
vim \
make \
tzdata \
git python make gcc g++ && \
cp -r -f /usr/share/zoneinfo/Hongkong /etc/localtime
ENV NODE_ENV=production
WORKDIR /data/
# 先拷贝文件变化需要安装依赖的文件,例如nodejs的package.json,java项目的pom.xml等
COPY package.json ./
COPY yarn.lock ./
COPY .yarnrc ./
RUN yarn --no-cache
# 在完成依赖安装后,我们在copy代码进来,如此一来
# 当依赖未变化时,就不需要重复运行以来安装过程了。
COPY ./ ./
EXPOSE 8080
ENTRYPOINT [ "/entrypoint.sh" ]
CMD ["yarn", "start"]
2. 使用多阶段构建镜像
- 以react前端项目为例
FROM node:12.16-alpine as builder
LABEL maintainer="xxx<xx@xxx.com>"
RUN \
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk add git python make gcc g++
ENV NODE_ENV development
WORKDIR /data/
COPY package.json ./
COPY .yarnrc ./
COPY yarn.lock ./
RUN yarn install --silent --no-cache
COPY ./ ./
RUN NODE_ENV=production yarn build
FROM nginx:1.20.1-alpine
LABEL maintainer="xxx<xx@xxx.com>"
RUN \
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf
# 关键步骤,我们从上一阶段的 node镜像中,copy出我们需要的最终编译好的前端静态文件
# 放置到nginx镜像中即可,最终景象将只包含nginx以及静态文件
COPY --from=builder /data/dist /usr/share/nginx/html
RUN chown -R nginx:nginx /usr/share/nginx/html/
EXPOSE 80
3. 使用docker buildkit在build阶段挂载缓存
- 这是本文的重点,做了很多的CI项目中后,大家都在思考,如果在
docker build
阶段,能够挂在上volume来做缓存,那该多好呀,那么,现在,他来了
在 docker 18.09以上版本,有一个Experimental特性, buildkit工具,默认是没有打开的,我们可以通过export DOCKER_BUILDKIT=1
之后在进行docker build,或者在/etc/docker/daemon.json
中配置开启:
{
"log-driver": "json-file",
"exec-opts": ["native.cgroupdriver=systemd"],
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
],
"features": { "buildkit": true }
}
开启之后我们就可以修改上面的Dockerfile,来完成一次速度的飞跃:
# syntax=docker/dockerfile:1.3
FROM node:12.16-alpine as builder
LABEL maintainer="xxx<xx@xxx.com>"
RUN \
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk add git python make gcc g++
ENV NODE_ENV development
WORKDIR /data/
COPY package.json ./
COPY .yarnrc ./
COPY yarn.lock ./
RUN yarn install --silent --no-cache
COPY ./ ./
# 需要开启docker Experimental特性支持,docker version > 18.09 , export DOCKER_BUILDKIT=1
RUN --mount=type=cache,id=yarn_cache,sharing=shared,target=/usr/local/share/.cache \
NODE_ENV=production yarn build
FROM nginx:1.20.1-alpine
LABEL maintainer="xxx<xx@xxx.com>"
RUN \
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /data/dist /usr/share/nginx/html
RUN chown -R nginx:nginx /usr/share/nginx/html/
EXPOSE 80
我们挂在了一个id为yarn_cache的卷到 yarn cache dir
下,那么每次安装的依赖本地缓存文件接回写入到缓存中,并在docker build完成之后从运行时中卸载并保存,下载我们就有机会体验拥有本地缓存的完美docker build了。
- 更多内容我们可以去翻阅官方的docker buildkit相关文档了
https://docs.docker.com/develop/develop-images/build_enhancements/
https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md
目前以上就是简单介绍我目前使用到的所有优化方案了,欢迎小伙伴们来补充。