gitlab CI/CD优化
标签:gitlab-CI-CD,docker
我的配置
docker image cache
docker-in-docker
docker-in-docker(dind)顾名思义,就是在docker里面运行docker.由于要在docker里控制里面的docker,所以要开启privileged mode
/etc/gitlab-runner/config.toml
配置
[[runners]]
...
executor = "docker"
[runners.docker]
...
privileged = true
volumes = ["/cache"]
[runners.cache]
另外,.gitlab-ci.yml
需要配置services为dind
image: docker:stable
services:
- docker:dind
dind会保证每次创建的job
都是一个干净的环境,之前执行job
所build的镜像都不会保存.比如,我的配置中,build stage里的$CACHE_IMAGE_URL,$BUILD_IMAGE_URL,node:8.11.2-alpine都不会缓存在docker executor,当然,更不可能在gitlab runner的host上了。下次有job执行时,只能重新从registry拉取,无法利用docker缓存
这里能优化的地方,只有创建一个tag为cache的镜像,在构建docker镜像时,先拉取tag为cache的镜像,在build
的时候,使用--cache-from参数,像这样
docker pull your_image:cache || true
docker build --cache-from your_image:cache -t your_image:your_tag -t your_image:cache .
docker push your_image:cache
docker push your_image:your_tag
Docker socket binding
如果觉得docker in docker
每次都需要pull,浪费时间,可以使用docker socket bind
.
/etc/gitlab-runner/config.toml
配置
[[runners]]
...
executor = "docker"
[runners.docker]
...
privileged = false
volumes = ["/cache","/var/run/docker.sock:/var/run/docker.sock"]
[runners.cache]
.gitlab-ci.yml
不需要配置services
docker socket bind
和gitlab runner host共用docker daemon,所以build的镜像都会缓存在host,这样job执行时不用每次都去registry pull
nodejs module cache
我的博客在gitlab ci构建的时候,需要nodejs编译.而编译需要一些nodejs package,我们当然不想每次构建的时候,都npm install
重新下载包.这就需要将node_modules目录
缓存起来.
shell executor
如果gitlab runner executors设置的是shell
The Shell executor is a simple executor that allows you to execute builds locally to the machine that the Runner is installed
构建的时候,相当于在装有gitlab runner
的机器上执行.gitlab-ci.yml的script
.npm install
后,node_modules目录会在gitlab runner
的工作目录里.使用gitlab CI配置里的cache,就可以在不同的job
里使用缓存的node_modules目录.
docker executor
docker executor的话,就不能使用缓存在gitlab runner机器上的node_modules目录,因为每次构建都会创建新的容器
The Docker executs when used with GitLab CI, connects to Docker Engine and runs each build in a separate and isolated container
怎么办?好在docker layer是可以缓存的
After building the image, all layers are in the Docker cache.
In Docker 1.10 and higher, only RUN, COPY, and ADD instructions create layers. Other instructions create temporary intermediate images, and no longer directly increase the size of the build.
将npm install
和后面的命令分开,不用&&拼接命令,对npm install
单独一行RUN
指令。
FROM node:alpine
WORKDIR /blog
ADD package.json /tmp/package.json
RUN cd /tmp && npm install --only=production \
&& cp -a /tmp/node_modules /blog
ADD . /blog
RUN ./node_modules/.bin/gulp --gulpfile gulpfile-prod.js \
&& mv html/index.html . \
&& rm -r node_modules src package* gulpfile* /tmp
这样在构建的时候,node_modules目录会成为一层layer
,被缓存起来.
注意如果用的是dind
,需要和上面docker-in-docker executor那的--cache-from
那段代码一起使用才能缓存node_modules目录
,因为dind
不会在docker executor缓存镜像
multi-stage builds
multi-stage builds可以让我们在构建docker镜像时,使用不同的基础镜像
比如我的博客需要nodejs环境编译,但是部署,上线不需要nodejs环境,需要openresty
.Dockerfile可以这样写
FROM node:alpine as node
#编译博客
...
FROM openresty:alpine
COPY --from=node src dst
copy指令将nodejs编译好的目录拷贝到openresty
里
OverlayFS driver
如果使用的是docker executor的docker in docker mode
,storage-driver用的是vfs,可以使用更好的storage-driver,参见
apk add --virtual
alpine
安装的时候,可以将部署,上线时不需要的包安装到一个目录,最后再删除这个目录
apk add --no-cache --virtual .build-deps package...
apk del .build-deps
参考
Building Docker images with GitLab CI/CD
Best practices for writing Dockerfiles
不定期更新