用Jenkins pipeline(流水线)实现SpringBoot Application的docker构建和持续集成(CI)
写在前面
在看了许多CI的内容之后,正好碰上公司尝试把应用容器化以及进行持续集成(之前还是需要手动执行启停脚本),然后我便成了第一个吃螃蟹的人,在一阵折腾之后也勉强算是把整个流程给走通了便在这里记录一下大致的流程和踩到的坑,也是对最近许久不更新的博客增加一些新东西吧.
部署流程
首先描述一下整个部署的流程来理清一下整个逻辑,这里仅仅是给出我自己的暂时的解决方案,由于业务和环境的不同必定没有完全一样的流程,并且这也只是暂时的方案还是有很多可以优化的地方。
1 | 更新代码 ==> 触发Jenkins流水线的构建 ==> Maven打包项目 ==> 制作docker image ==> |
需要注意的是:
- 项目的仓库中包含了Jenkinsfile和部署的脚本(全部交由版本控制)
- 由于线上服务器为阿里ECS并且外网无法访问,所以使用了部署服务器(外网IP)来做跳转和部署
- 因为项目使用了SpringCloud的微服务框架并且使用了NACOS注册中心,所以在服务的优雅下线重启阶段使用了nacos的服务调度API并没有使用SpringCloud自带的端点,当然本质都是通过接口调用告知注册中心下线服务
- 由于线上服务器均没有使用root用户来发布应用所以在这里踩了小坑,暂时的解决方案可能并不完美
Jenkins
安装
官方教程的链接:Installing Jenkins
当然这里还是用了docker安装的方式,官方的命令如下:
1 | docker run \ |
最主要的命令还是两个-v的参数了,一个是指定Jenkins文件的存放位置,第二个则是docker in docker的关键命令了,这个挂载能够让安装在docker里的Jenkins使用docker命令。
not work?
没错,这个命令在我司的服务器上并没有生效,可能是因为安装的docker版本过低的原因,在一番面向Google编程之后找到了如下的方式:How to build docker images inside a Jenkins container.,本质还是docker in docker,不过需要自己制作镜像,Dockerfile文件如下:
1 | FROM docker.io/jenkins/jenkins:latest |
构建镜像命令:
1 | docker image build -t jenkins-docker . |
docker run 命令和上面一样
pipeline(流水线)
官方的文档:流水线语法
在自己实践的过程中踩了不少的坑,到最后还是发现官方文档最靠谱,所以有什么解决不了的问题还是先求助官方文档为上。
这里给出测试和生产两个环境的Jenkinsfile用于参考:
测试环境
1 | /* |
生产环境:
1 | pipeline { |
docker
下面命令在需要部署的服务器上执行:
1 | $ curl -fsSL get.docker.com -o get-docker.sh |
常用命令
- docker ps : 查看运行中的容器
- docker ps -a: 查看全部容器
- docker start [容器id]: 启动容器
- docker stop [容器id]: 停止容器
- docker rm [容器id]: 删除容器
- docker iamge ls: 查看本地iamge
- docker rmi [镜像id]: 删除本地image
注意: 所有 [容器id] 的地方都可以用空格分割来对多个容器进行操作
Dockerfile
1 | FROM java:8 |
部署脚本
deploy.sh
1 | # 准备变量 |
停止spring应用和查看服务是否启动并不是必需的,但是也算是为了服务能够优雅下线做的尝试吧,也可以看到大部分的参数也是这两个步骤带进来的,如果只对docker容器进行操作的话整个脚本会简单很多
这也可以说是第一次写这么多行的脚本,但是实质还是不是很难的,主要用到的是awk
,grep
,if
和管道|
,还有一个一行处理json的python(还挺不错)
总体使用流程
- 在项目中编写Jenkinsfile和deploy.sh
- 在Jenkins中新建流水线项目,填写项目的地址并选择Jenkinsfile
- 需要部署项目的服务器安装docker并配置ssh免密登陆
- Jenkins中点击构建
总结
这次项目向docker化的持续集成的迁移改造,前前后后也大致是花费了一个多星期了,但是整个流程下来也算是能够对Jenkins和docker更加的熟悉一点了吧
不足
当然由于每个组的技术不可能完全一致,CI的方式也肯定不尽相同,上面的方案也是草草交了的答卷,肯定是有很多优化的地方的。
比如像构建并不是在监测到分支改动之后自动执行而是需要手动执行,代码并没有进行从单测到集成测试的任何测试,也没有经过代码质量审查,当然还有一些构建完成之后的工作也没有进行(比如没有通知构建),等等….
并且对上面的解决方案自我感觉也并不是特别良好,或者说感觉不够优雅,也是局限于业务规模,并不需要深入使用compose或者容器编排之类的技术,毕竟ci也是代码,是代码就决定它肯定不是一成不变的,也只能说多多自勉吧
吾尝终日而思矣 不如须臾之所学也