涉及知识:
- Docker、Dockerfile、Docker-compose
- Git、Gitlab-ci
本文记录了:
- 使用 Docker 安装 Gitlab-runner
- 使用 Docker 作为 Gitlab-runner 的执行器
- 使用 Dockerfile 编译生成镜像
- Gitlab-ci 文件的编写
- 将应用部署到服务器
安装Gitlab-runner
应为我们使用的是Docker来完成CI/CD的操作,所以需要提前准备安装好Docker。
利用dokcer安装Gitlab-runner只需要执行:
docker run -d --name gitlab-runner --restart always
-v /srv/gitlab-runner/config:/etc/gitlab-runner
-v /var/run/docker.sock:/var/run/docker.sock
gitlab/gitlab-runner:latest
我们来看下,在这个命令里面挂载了两个东西,第一个是gitlab-runner的配置文件、第二个是为了让runner里面可以执行宿主机的docker。
现在runner已经通过docker在运行了,接下来需要执行注册流程,将runner注册到Gitlab中:
docker exec -it gitlab-runner gitlab-ci-multi-runner register
这里就需要进入自己的gitlab仓库中的CI/CD设置里面。复制下自己仓库URL以及runner的token
Runtime platform arch=amd64 os=linux pid=19 revision=a998cacd version=13.2.2
Running in system-mode.
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://co*******com/
Please enter the gitlab-ci token for this runner:
bT*********ZcmD
Please enter the gitlab-ci description for this runner:
[b5f641f7df47]: runner
Please enter the gitlab-ci tags for this runner (comma separated):
prod
Registering runner... succeeded runner=bTYwz7Zf
Please enter the executor: custom, docker, parallels, ssh, docker-ssh, shell, virtualbox, docker+machine, docker-ssh+machine, kubernetes:
docker
Please enter the default Docker image (e.g. ruby:2.6):
ccchieh/centos-common
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
注意在Please enter the executor
中选择执行器为docker,然后选择默认的docker镜像,这里我用的是自己制作的基于centos的镜像,只是在官方的centos镜像基础上安装了openssh、git、nano,如果有其他需要的话也可以自己制作。
接下来需要编辑下我们的配置文件,因为我们吧配置文件挂载到宿主机了,所以我们只需要编辑宿主机的文件:
vim /srv/gitlab-runner/config/config.toml
这里先贴出我的配置
concurrent = 10
[[runners]]
name = "s****an"
url = "https://co*******m/"
token = "m********JFMHxD"
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.docker]
tls_verify = false
image = "ccchieh/centos-common"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock", "/usr/bin/docker:/usr/bin/docker", "/data/.m2:/root/.m2", "/root/.ssh:/root/.ssh", "/root/.docker/:/root/.docker/"]
pull_policy = "if-not-present"
shm_size = 0
这里修改的主要是concurrent
、volumes
、pull_policy
concurrent 表示这个runner可以并行执行多少任务,比较常见的就是同时提交多次任务时runner可以并行执行,或者在一次管道作业中同一个stage的任务可以并行完成,比如在图中的Build阶段,同时打包了4个子模块,在四个子模块中都会先下载依赖,这时如果最大并发数设置为默认1的时候会把花费很多时间,如果并发数大于4,那么Build阶段就可以并发完成。
volumes则是挂载的目录,就是docker run 的时候用的 -v 挂载的目录,应为我们后面需要编译Dockerfile,所以将docker的相关目录文件挂载上去,然后挂载下maven仓库(这里是直接挂载了,实际使用的时候也可以利用gitlab-ci文件里面的cache进行缓存)避免每次打包编译java项目的时候都要下载一次依赖(这里是针对maven的,其他依赖管理软件视情况而定)。最后我这里直接把宿主机的.ssh也挂载上去了,是为了后面可以操作远程部署的服务器,因为我这里都是内网机器,所以安全性暂时不考虑,这里再实际应用中请注意下,避免不必要的风险。
pull_policy则是表示只有当本地没镜像的时候才拉取镜像,避免每次都重新拉取镜像。
Dockerfile 编译生成镜像
对于每个项目我们都需要编写一个Dockerfile用于实现对项目的编译打包,这里我们以前端的项目为例简介的介绍下,首先来看下Dokcerfile文件:
# build stage
FROM node:12.14.0 as builder
COPY . /usr/src/app
WORKDIR /usr/src/app
RUN npm config set registry https://registry.npm.taobao.org
&& npm install
&& npm run build
# production stage
FROM nginx:1.19-alpine as prod
COPY --from=builder /usr/src/app/dist/spa /usr/share/nginx/html
COPY --from=builder /usr/src/app/nginx.conf /etc/nginx/conf.d
我们使用Dockerfile的多阶段构建的方式,再第一个build阶段使用node镜像编译打包前端项目,然后第二阶段中把第一编译好的文件移动到nginx镜像中,同时把我们自定义的nginx配置也复制过去。
编写gitlab-ci.yml
在gitlab-ci.yml中是支持变量的,这样我们可以把如主机ip等敏感信息设置为变量,防止信息泄露。
以我这里为例分别设置了容器名称、镜像私有仓库地址、部署服务器地址(如root@202.1.1.1)、服务器中的docker-compose的文件路径。
然后我们的gitlab-ci.yml:
cache:
untracked: true
key: $CONT_NAME
paths:
- node_modules/
- dist/
stages:
- build
- deploy
- cleanup
build: # 编译阶段
stage: build
only:
- prod # 只有prod更新的时候才执行命令
tags:
- ***
script:
- docker build -t $IMAGE_PROD .
- docker push $IMAGE_PROD
deploy: # 部署阶段
stage: deploy
only:
- prod
tags:
- ***
script:
- ssh $SERVER_ADDR docker-compose -f ${SERVER_PATH}/docker-compose.yml up -d
- ssh $SERVER_ADDR docker-compose -f ${SERVER_PATH}/docker-compose.yml stop $CONT_NAME
- ssh $SERVER_ADDR docker-compose -f ${SERVER_PATH}/docker-compose.yml pull $CONT_NAME
- ssh $SERVER_ADDR docker-compose -f ${SERVER_PATH}/docker-compose.yml up -d --build $CONT_NAME
cleanup: # 清理作业
stage: cleanup
only:
- prod
tags:
- ***
script:
- echo "回收垃圾"
when: always
上面cache我们设置缓存,之后分为三阶段(build、deploy、cleanup),而且我们通过only关键字设置只有在prod分支下的代码更新了才进入管道。
大致流程还是比较简单的,但是实际操作的时候还是有许多坑需要慢慢踩。