gitlab+docker+jenkins基于dockerfile持续集成
篇幅使用的组件docker,dockerfile,docker-compose,registry,jenkins,gitlab,钉钉通知,篇幅有限,有些未详细写到的东西可能需要大家自行摸索。
来介绍下这套自动发布的工作流程及搭建步骤,此文档只为记录及展示,为了篇幅不过长,docker,docker-compose,不做赘述,其余组件均使用docker运行,
初始环境:
IP1 : 192.168.18.221,jenkins+gitlab+docker-registry
IP2:192.168.18.222,web
关闭selinux
关闭防火墙
一,安装docker(两台机器都装)
# step 1: 安装必要的一些系统工具 yum install -y yum-utils device-mapper-persistent-data lvm2 # Step 2: 添加软件源信息 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # Step 3: 更新并安装Docker-CE yum makecache fast yum -y install docker-ce # Step 4: 开启Docker服务 systemctl start docker
#这里还是添加下镜像加速
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://8****lj0.mirror.aliyuncs.com"]
}
二,安装gtitlab
# 不加 tag 则默认为最新版本 latest docker pull gitlab/gitlab-ce #通常会将 GitLab 的配置 (etc) 、 日志 (log) 、数据 (data) 放到容器之外, 便于日后升级, 因此请先准备这三个目录。 mkdir -p /srv/gitlab/config mkdir -p /srv/gitlab/logs mkdir -p /srv/gitlab/data #启动运行gitlab docker run --detach \ --hostname gitlab.example.com \ --publish 8443:443 --publish 8880:80 --publish 8222:22 \ --name gitlab \ --restart always \ --volume /srv/gitlab/config:/etc/gitlab \ --volume /srv/gitlab/logs:/var/log/gitlab \ --volume /srv/gitlab/data:/var/opt/gitlab \
--add-host code.shiji.com:192.168.18.221 \ --privileged=true \ gitlab/gitlab-ce:latest
#这里能成功访问后就不做额外的配置了,注意修改下配置文件里面的默认访问地址
#配置下nginx代理后的访问地址 http://code.shiji.com (这里域名是使用的本地解析,当需要拉取代码的时候必须要能解析这个域名,)
三,安装jenkins(这里放上官方文档 https://jenkins.io/zh/doc/pipeline/tour/deployment/)
#拉取镜像(这里建议大家使用官方推介的镜像) docker pull jenkinsci/blueocean:lts
#创建挂载目录并修改权限
mkdir /home/jenkins
#创建并运行 docker run \ -u root \ -d \ -p 8080:8080 \ -p 50000:50000 \ -v /home/jenkins:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ #如果需要在容器中运行docker命令,这条必须加上
--add-host code.shiji.com:192.168.18.221 \ #这里我给jenkins添加了一条本地解析
--restart always \
--name jenkins \ jenkinsci/blueocean:latest
#在log中找到初始密码
docker logs jenkins
#修改密码后jenkins安装部分完成
#访问地址,http://192.168.18.221:8080
#备注,安装完成记得安装插件,这里用docker构建,需要安装 CloudBees Docker Build and Publish
四,搭建registary私仓(需要把把代码用dockerfile构建后上传到私仓库,然后web服务器在拉下来重构,如果希望便捷操作可以使用云上的私人仓库)
#拉取镜像 docker pull registry #创建registry镜像存储目录 mkdir -p /data/registry #创建启动registry docker run -d -p 5000:5000 --restart=always --name registry -v /data/registry:/var/lib/registry registry:latest
#修改web服务的docker配置文件daemon.json,添加http
vim /etc/docker/daemon.json
{
"insecure-registries": ["http://192.168.18.221:5000"],
"registry-mirrors": ["https://8****lj0.mirror.aliyuncs.com"]
}
#构建完成后registry地址 http://192.168.18.221:5000
五,配置持续集成,这里再次梳理下工作流程,开发人员提交代码 --> 触发gitlab钩子 --jenkins拉取代码构建 -->构建成功,推送镜像至私仓 -->web服务器拉取私仓镜像创建容器 -->通知用户;当然,失败的时候也会通知用户。
1,配置pipeline,
我们在jenkins里创建一个名为多分支的流水线,并且配置好代码仓,并且让他每次自动检出分支,以及检出前后都清理工作目录,其他选项使用默认即可,Build Configuration选择jenkinsfile;
注意:此处配置完成后,scan流水线时会自动从gtilab里识别jenkinsfile文件,
2,配置jenkinsfile文件,语法参考 https://jenkins.io/zh/doc/book/pipeline/,这里直接放出这边配置好的文件
pipeline { agent any parameters { string(name:'BRANCH_FOR_BODY',defaultValue:"${BRANCH_NAME}",description:'parameters used by ding talk') #此处的两个参数是为了后面钉钉通知的时候使用,这里后面再说 string(name:'BUILD_URL_FOR_BODY',defaultValue:"${BUILD_URL}",description:'build uri for body') } stages { stage('Deploy-Production') { when { branch 'master' } steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:latest -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:latest' #这里选择每次都推送为lastest标签 sh 'docker rmi ${DOCKER_IMAGE_NAME}:latest' #同时删除本地构建打好标签的镜像 } post { #根据执行标记来决定处理内容 success { sh 'sh notice.sh "test生产环境镜像推送成功通知" "nginx-test" "推送镜像成功" ${BRANCH_NAME} ${BUILD_URL}' #此处的钉钉推送脚本最后会放出 } failure{ sh 'sh notice.sh "test生产环境镜像推送失败通知" "nginx-test" "推送镜像失败" ${BRANCH_NAME} ${BUILD_URL}' } } } } environment { DOCKER_DEPLOY_URI = 'http://nginx.test.shiji.com' #这里只是为了个人使用,此篇幅未用到 DOCKER_IMAGE_NAME = '192.168.18.221:5000/test/nginx-test' #镜像名称 DOCKER_SERVICE_NAME = 'TestService' #项目名称 } }
3,在上面的步骤中我们在构建的时候使用了dockerfile,这里使用个简单的nginx作为测试
FROM nginx RUN echo 'This is the first version' > /usr/share/nginx/html/index.html
4,接下来我们把dockerfile也上传至代码仓,这时构建当然是失败的,因为后续的钉钉通知脚本还没有上传,
查看输出,可以看到镜像已经上传成功
5,至此,持续构建算初步完成,放上钉钉推送信息的脚本,记得把tocken换成自己的,(注意新版本的钉钉机器人要加签了)
gitAuthor='' gitAuthor=`git show --stat | awk '$0~/Author/{print $2}'` response=`curl -X POST -H 'Content-Type:application/json; charset=utf-8' \ -d '{"msgtype":"markdown",\ "markdown":{"title":"'$1'",\ "text":"## '$1'\n\n**项目名称**:'$2'\n\n**提交人**:'$gitAuthor'\n\n**状态**:'$3'\n\n**分支**:'$4'\\n\\n有关更多构建的过程、错误信息、单元测试覆盖率报告请参照 [构建日志]('$5')"\ }}' https://oapi.dingtalk.com/robot/send?access_token=d7f17229b054200xxxxxxxxxxxxxxxxxxxx3204e4dee` echo $response
6,gitlab自动推送,自动构建
1,在jenkins安装gitlab插件,注意这里并不是哪个gitlabhook的插件
&插件安装成功后我们修改jenkinsfile增加tigger,关于tigger的语法,官方文档和往上都给的不太详细,这里如果想过滤分支等操作参考下这两篇文章
https://blog.51cto.com/ygqygq2/2461766
http://www.eryajf.net/3298.html
&放上修改完成的jenkinsfile
pipeline { agent any parameters { string(name:'BRANCH_FOR_BODY',defaultValue:"${BRANCH_NAME}",description:'parameters used by ding talk') string(name:'BUILD_URL_FOR_BODY',defaultValue:"${BUILD_URL}",description:'build uri for body') } triggers{ gitlab( triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: "NameBasedFilter", includeBranchesSpec: "master,dev", secretToken: "028d848ab64f" ) } stages { stage('Deploy-Production') { when { branch 'master' } steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:latest -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:latest' sh 'docker rmi ${DOCKER_IMAGE_NAME}:latest' } post { success { sh 'sh notice.sh "test生产环境镜像推送成功通知" "nginx-test" "推送镜像成功" ${BRANCH_NAME} ${BUILD_URL}' } failure{ sh 'sh notice.sh "test生产环境镜像推送失败通知" "nginx-test" "推送镜像失败" ${BRANCH_NAME} ${BUILD_URL}' } } } } environment { DOCKER_DEPLOY_URI = 'http://nginx.test.shiji.com' DOCKER_IMAGE_NAME = '192.168.18.221:5000/test/nginx-test' DOCKER_SERVICE_NAME = 'TestService' } }
2,jenkins设置里添加仓库(这里的tocken需要去gitlab里生成)
3,gitlab项目里创建webhook
4,最后提交一次测试效果(钉钉通知)
7,到这里为止算是初步完成了自动构建,接下来要说说自动发布了,我们已经把镜像推送到了私仓,接下来只需要在应用服务器上执行命令构建就行,这里说说我们是怎么做的。
应用服务器发布脚本,脚本使用compose发布,脚本执行也是放在Jenkins file里,(这里配置了两条是为了后续的pipeline多分支),脚本接受两个参数,一个名称及标签,标签是为了多分支的pipeline准备的,后续再说。
脚本:
tag="$2" # test if [ $1 == "test" ] then cd /docker/compose/test pwd docker pull 192.168.18.221:5000/test/nginx-test:$tag docker-compose up -d test echo "success" elif [ $1 == "test1" ] then cd /docker/compose/test1 docker pull 192.168.18.221:5000/test/nginx-test:$tag docker-compose up -d test2 echo "success" else echo "no equal service" fi
jenkinsfile:(写在setp阶段执行,这里我们使用的是接口的方式,需要在应用服务器上写个接口去执行上面的脚本,当然你也可以直接远程执行脚本,过程就不在赘述)
steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:latest -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:latest' sh 'docker rmi ${DOCKER_IMAGE_NAME}:latest'
sh 'curl ${DOCKER_DEPLOY_URI}/staging?service=${DOCKER_SERVICE_NAME}' #请求接口去执行上面的脚本发布,接口怎么写的这里我就不放出来了,大家可以省略这一步直接远程执行脚本(要配置ssh互信)
}
最后:多分支pipeline
上面内容设置了一些变量,就是为此准备的,在这里我们可以对应环境分成多个流水线分支,主要还是修改jenkinsfile:
pipeline { agent any parameters { string(name:'BRANCH_FOR_BODY',defaultValue:"${BRANCH_NAME}",description:'parameters used by ding talk') string(name:'BUILD_URL_FOR_BODY',defaultValue:"${BUILD_URL}",description:'build uri for body') } triggers{ gitlab( triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: "NameBasedFilter", includeBranchesSpec: "master,dev", secretToken: "028d848ab64f" ) } stages { stage('Deploy-Production') { when { branch 'master' } steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:latest -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:latest' sh 'docker rmi ${DOCKER_IMAGE_NAME}:latest' sh 'curl ${DOCKER_DEPLOY_URI}/staging?service=${DOCKER_SERVICE_NAME}&tags=latest' } post { success { sh 'sh notice.sh "test生产环境镜像推送成功通知" "nginx-test" "推送镜像成功" ${BRANCH_NAME} ${BUILD_URL}' } failure{ sh 'sh notice.sh "test生产环境镜像推送失败通知" "nginx-test" "推送镜像失败" ${BRANCH_NAME} ${BUILD_URL}' } } } stage('Deploy-Dev') { when { branch 'dev' } steps { sh ''' docker build -t ${DOCKER_IMAGE_NAME}:dev -f Dockerfile . ''' sh 'docker push ${DOCKER_IMAGE_NAME}:dev' sh 'docker rmi ${DOCKER_IMAGE_NAME}:dev' sh 'curl ${DOCKER_DEPLOY_URI}/dev?service=${DOCKER_SERVICE_NAME}&tags=dev' } post { success { sh 'sh notice.sh "test测试环境部署成功通知" "nginx-test" "成功" ${BRANCH_NAME} ${BUILD_URL}' } failure{ sh 'sh notice.sh "test测试环境部署失败通知" "nginx-test" "失败" ${BRANCH_NAME} ${BUILD_URL}' } } } } environment { DOCKER_DEPLOY_URI = 'http://dockerup.test.shiji.com' DOCKER_IMAGE_NAME = '192.168.18.221:5000/test/nginx-test' DOCKER_SERVICE_NAME = 'TestService' } }
最后效果
jenkins:
钉钉通知:(这里在实际的生产环境中,并没有持续部署,所以通知是有区别的)
写在最后:这篇是使用dockerfile的持续集成,当然还有其他方式,上面文中的连接作了更详细的讲解,各位看官如果能看到最后,欢迎留言指出文中不足的地方。