开篇
为什么写这篇文章
作为一名合格的全栈开发工程师(外加运维、UI设计……),在开发软件的时候,需要处理很多的事务,有些操作是频繁的、重复的、可程序化的,如果能通过脚本或工具来自动实现这些步骤,那开发者所操心的就只有如何写出高效可靠的代码了。
多人/多端开发环境诟病
倘若是个单人小型项目,使用我之前文章中的实践方针已经基本可以达到目的。但是多人开发或者是大型的项目需要考虑到联调环境以及其他不同的情况如下:
- 后端本地测试:考虑到电脑性能以及网络限制问题,不打算在本地跑数据库、缓存和消息队列等,需要远程云服务器。但是阿里云服务器限制性较多,经过测试发现 Mysql8 只能通过 SSH 连,否则不给本地回传数据。Redis 可以直连,但是可能会被服务器中断连接。
- 前端本地测试:前端若要安装后端项目的环境,会比较麻烦,如果能直接在阿里云服务器上部署后端项目,前端再启动 node 访问服务器的接口,对于前端来说就是无感联调了。
- 生产环境部署:当开发完一个 Release 版本后,需要发布到服务器部署,这个时候再使用前后端本地测试时的环境配置就不适合了,部分配置需要修改为 localhost 或者直接上域名。所以前后端都得准备至少两套配置。
抛砖引玉
基于上面的情况,使用 Jenkins 实现自动化的持续集成就最好不过了,有了这个工具,后端写完项目只要提交到 git ,就会被监听触发构建,根据配置的命令上传到服务器网站目录下并实现自动部署,方便前端联调。若是生产环境也只需要修改打包的环境变量即可。所以写一篇文章来记录一下整个流程。
前提条件
- 一个存储在 Gitee 的前后端分离项目
- 一台配置还可以的云服务器(不够 4GB 内存构建前端可能会溢出)
实战
Jenkins 配置
关于容器方面本篇不做教学,博主使用的是 1Panel
面板,自带容器环境。
默认端口8777
进入,一路安装默认插件注册管理员账号。然后在插件页面根据实际需求下载所需的插件。
403 问题处理
如果容器部署的 Jenkins 遇到了 403 的问题,可以进容器内部,先装个 vim,再编辑 /usr/local/bin/jenkins.sh
文件,在 exec java
这一行加上一个参数-Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true
,解除跨站请求改造的拦截。(高版本引入的这个问题)
引入 Gitee 凭证
直接进【系统管理】-【系统配置】,拉到下面填写 Gitee 相关信息和凭证。
添加凭证点击后,获取方式如下图中的链接,转到码云里面生成一个 token。
Maven 安装
由于是容器部署的,还要额外在容器里安装maven,或者直接用 Jenkins 自动安装。
NodeJs 安装
为了加快国内依赖包下载速度,建议使用 cnpm 并添加淘宝镜像源,不过此镜像不是完全稳定,如果打包遇到问题,也可以考虑使用 yarn、pnpm,或其他镜像。
cnpm --registry=https://registry.npm.taobao.org
SSH 配置
如果非容器化本地部署的 Jenkins,无需考虑这一步的操作,可以直接在后续的构建后置操作中写脚本来完成。但是对于容器部署的环境,以及源码、流水线、成果物三者不在同一个环境,则需要使用到SSH工具来远程连接并进行操作。
我这个 Jenkins 版本不支持 pem 格式的密钥,所以需要使用 rsa 在容器内生成密钥,并将密钥填写至系统管理中。
ssh-keygen -m PEM -t rsa -f id_rsa
别忘了把公钥放到你要连接的服务器上。
最后添加一个 SSH 服务并测试连接即可。
创建任务并配置
返回首页点击新建任务后,选择构建一个maven项目
由于上面配置了 Gitee 的凭证,这里就无需选择了,而且本来也选不到。只需填写代码仓库路径和打包分支。
勾选 webhook 触发构建,并用这里的 url 在码云中创建。
构建环境中需要选上 node,这样后续才能用之前配置的 cnpm 打包。
同理配置 maven 打包命令。此处跳过 test,并且使用 prod 环境变量来匹配我的项目中的 application-prod.yml,请根据实际项目对应生产环境的打包命令填写。
在构建后置操作中添加 shell 脚本来打包前端文件,具体脚本请根据实际来填写。例如你的 Jenkins 和部署的成果物在同一个环境,那么可以直接在这里打包完 dist 之后,将文件 cp 到网站运行目录下,并且通过 sh 脚本启动 Java 项目。由于我的 Jenkins 在容器中,所以后续通过 SSH 来操作主机。
# 第一行和最后一行是为了防止构建过程被 Jenkins 终止
BUILD_ID=dontKillMe
cd ctb-ui
rm -rf dist
# 有时候遇到网络等问题,可以关闭 ssl 或者在这里切换镜像
cnpm config set strict-ssl false
cnpm install
# 根据实际生产环境打包命令填写
cnpm run build:prod
export BUILD_ID=dontKillMe
最后根据需要创建 SSH 步骤,由于传送文件过于缓慢,实测一个 100 MB 的 jar 包要传半小时,而容器部署的 Jenkins 原本就会持久化构建后的成果物目录,因此我写了个脚本,直接将挂载目录下的文件 cp 到项目路径下。
特别注意:此处的脚本和文件传送的三个参数,至少有一种被填写,也可以都填写。都填写的情况下是先执行脚本再传文件的,一般来说我们的操作都是先传完文件再执行某些脚本,所以如果希望脚本后执行,第一个步骤可以不填,然后再添加一个 SSH 步骤,里面不填传文件的参数,只填脚本。
Gitee 配置
凭证获取
生成令牌后填写至 Jenkins 中。
WebHooks
此处的密码是在 Jenkins 中生成的,点击生成按钮即可,Url 也填写 Jenkins 配置页面上提示的即可。如果我们点击测试失败,不要紧,这是码云的问题。你也可以把请求 copy 到 postman 里,将 header 里的 X-Gitee-Event
和X-GIT-OSCHINA-EVENT
修改为Push Hook
后再测试调用,或者直接触发推送来测试。
结论
通过如上的步骤,我们就可以实现自动化的生产环境持续集成。
- 程序员提交代码(可指定分支,评论或 PR)
- Jenkins 拉取 Gitee 代码构建前后端成果物
- 将成果物拷贝到网站目录下(或使用 dockerfile 制作成镜像)
- 自动覆盖前端静态文件,启动后端程序(或启动容器部署)
整个过程从程序员提交代码的那一刻起,到生产环境环境的更新,只需短短五分钟时间。配合其他优雅的操作,可以使整个流程更加简单高效。相比之前纯手工的本地打包,不再受限于本地环境的限制,也无需再考虑文件传输的费时与流量,更不用手动编写命令或执行脚本重启服务。