當(dāng)我們?cè)谕耆褂胓itlab runner,或者其他工具,借助完整的Dockerfile完成項(xiàng)目鏡像制作中時(shí),大大提高了我們的運(yùn)維發(fā)布效率,但是越來越長(zhǎng)的docker build時(shí)間也成為快速發(fā)布上線的障礙了,我們就來總結(jié)一下有哪些優(yōu)化docker build的方法。
1. 充分利用docker build鏡像分層緩存策略
- 這也是我們最常用的第一種加速構(gòu)建鏡像的方式,以nodejs項(xiàng)目為例:
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項(xiàng)目的pom.xml等
COPY package.json ./
COPY yarn.lock ./
COPY .yarnrc ./
RUN yarn --no-cache
# 在完成依賴安裝后,我們?cè)赾opy代碼進(jìn)來,如此一來
# 當(dāng)依賴未變化時(shí),就不需要重復(fù)運(yùn)行以來安裝過程了。
COPY ./ ./
EXPOSE 8080
ENTRYPOINT [ "/entrypoint.sh" ]
CMD ["yarn", "start"]
2. 使用多階段構(gòu)建鏡像
- 以react前端項(xiàng)目為例
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
# 關(guān)鍵步驟,我們從上一階段的 node鏡像中,copy出我們需要的最終編譯好的前端靜態(tài)文件
# 放置到nginx鏡像中即可,最終景象將只包含nginx以及靜態(tài)文件
COPY --from=builder /data/dist /usr/share/nginx/html
RUN chown -R nginx:nginx /usr/share/nginx/html/
EXPOSE 80
3. 使用docker buildkit在build階段掛載緩存
- 這是本文的重點(diǎn),做了很多的CI項(xiàng)目中后,大家都在思考,如果在
docker build階段,能夠掛在上volume來做緩存,那該多好呀,那么,現(xiàn)在,他來了
在 docker 18.09以上版本,有一個(gè)Experimental特性, buildkit工具,默認(rèn)是沒有打開的,我們可以通過export DOCKER_BUILDKIT=1之后在進(jìn)行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
我們掛在了一個(gè)id為yarn_cache的卷到 yarn cache dir下,那么每次安裝的依賴本地緩存文件接回寫入到緩存中,并在docker build完成之后從運(yùn)行時(shí)中卸載并保存,下載我們就有機(jī)會(huì)體驗(yàn)擁有本地緩存的完美docker build了。
- 更多內(nèi)容我們可以去翻閱官方的docker buildkit相關(guān)文檔了
https://docs.docker.com/develop/develop-images/build_enhancements/
https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md
目前以上就是簡(jiǎn)單介紹我目前使用到的所有優(yōu)化方案了,歡迎小伙伴們來補(bǔ)充。