在测试环境部署这块, 经历过以下几个阶段:
- 阶段一
有一台测试服务器把项目放上面测试, 当初也没有什么相关的经验, 每次改完代码本地打包上传到服务器上, 然后一顿命令启动项目, 完成了最原始的部署。
这种方式构建和部署全靠人肉, 项目简单的时候还好说, 项目一多配置一多 ( 比如微服务 ) 中间哪个环节粗心出点错那简直就是灾难。
同时还要专门有人对运维相关的技术比较了解, 不然哪天我不在测试工作就完全停滞了。
- 阶段二
既然都是重复工作, 那就整理下步骤写个脚本
- 从 SVN 拉代码
- Maven 构建打包
- 重启 Tomcat
- 从 SVN 拉代码
- 阶段三
了解到 Jenkins 是个不错的工具, 那就把脚本的内容迁移到 Jenkins 上, 不管是开发还是测试只要在 web 界面上点击一下按钮即可完成构建部署, 很 easy。
- 阶段四
容器化: 使用 Docker 来部署项目, 这样就可以干掉原来服务器上散落各地参差不齐的 Tomcat ( 不同项目依赖不同 ) , 利用 Docker Compose 对项目进行编排, 提供一种规范的构建配置 ( 同时也是一份文档 ) , 大大减小了后期维护和交接的成本。
- 阶段五
上面的阶段已经能解决日常需求了, 但是还有一点问题就是每次提交完代码还要手动去 Jenkins 上发布, 能更自动点就更好了 ( 嗯, 就是懒 ) 。
于是就引出了本文的目标 —— 自动持续构建, 不需要人工操作 ( 留人工操作用于处理特殊情况 )
文章图片
流程图
- 开发提交代码
- 开发对需要发布的版本打上 Tag
- 触发 GitLab 的 tag push 事件, 调用 Webhook
- Webhook 触发 Jenkins 的构建任务
- Jenkins 构建完项目可以按版本号上传到仓库、部署、通知相关人员等等
GitLab 官方文档 已经介绍的比较详细了, 这里不再赘述, 下面给出最终调整过的 Docker Compose 配置:
gitlab:
image: "twang2218/gitlab-ce-zh:11.0.2"
restart: always
hostname: 'gitlab'
ports:
- "10022:22"
- "10080:10080"
# postgresql 端口
- "5432:5432"
volumes:
- ./gitlab/data:/var/opt/gitlab
- ./gitlab/log:/var/log/gitlab
- ./gitlab/config:/etc/gitlab
environment:
GITLAB_OMNIBUS_CONFIG: |
# 仓库路径, 填写宿主机的域名或 IP
external_url 'http://192.168.xxx.xxx:10080'
# 调整工作进程数减小内存占用,最小为 2
unicorn['worker_processes'] = 2
gitlab_rails['time_zone'] = 'Asia/Shanghai'# 邮箱配置
gitlab_rails['gitlab_email_from'] = ''
gitlab_rails['gitlab_email_display_name'] = ''
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = 'smtp.163.com'
gitlab_rails['smtp_port'] = 25
gitlab_rails['smtp_user_name'] = ""
gitlab_rails['smtp_password'] = ""
gitlab_rails['smtp_domain'] = 'smtp.163.com'
gitlab_rails['smtp_tls'] = false
gitlab_rails['smtp_openssl_verify_mode'] = 'none'
gitlab_rails['smtp_enable_starttls_auto'] = false
gitlab_rails['smtp_ssl'] = false
gitlab_rails['smtp_force_ssl'] = false# 数据库配置
gitlab_rails['db_host'] = '127.0.0.1'
gitlab_rails['db_port'] = 5432
gitlab_rails['db_username'] = "gitlab"
gitlab_rails['db_password'] = "gitlab"postgresql['listen_address'] = '0.0.0.0'
postgresql['port'] = 5432
postgresql['md5_auth_cidr_addresses'] = %w()
postgresql['trust_auth_cidr_addresses'] = %w(0.0.0.0/0)
postgresql['sql_user'] = "gitlab"
postgresql['sql_user_password'] = Digest::MD5.hexdigest "gitlab" << postgresql['sql_user']# 备份设置-保留7天
gitlab_rails['backup_keep_time'] = 604800
GITLAB_BACKUPS: "daily"
GITLAB_SIGNUP: "true"
GITLAB_ROOT_PASSWORD: "lb80h&85"
GITLAB_GRAVATAR_ENABLED: "true"
说明:
- 这里使用 汉化版 镜像, 如果不适应可以换回 官方原版 镜像
gitlab/gitlab-ce:11.0.2-ce.0
- 项目初始配置 + 启动很慢, 需要一段时间, 日志中出现 Reconfigured 时表示启动成功
- 192.168.xxx.xxx 替换为宿主机的 IP 地址
- 初始管理员帐号密码:
root
/lb80h&85
( 自行修改配置文件中的密码 )
- 该配置为 乞丐版 , 内存占用 2G+ ( worker_processes 越多内存占用越大, 默认为 8G )
- postgresql 为容器中内置的数据库 ( 帐号:
gitlab
/gitlab
) , 没必要就不用暴露端口了
- 邮箱填写用于发送找回密码和通知的发件人帐号 ( 收不到邮件? ) , 不想配置就删掉相关配置好了, 不影响正常使用
为了测试方便, 使用 Docker 化的 Jenkins , 如果需要调用一些特殊的命令或脚本就不是很方便, 实际使用过程中可以换成普通版的。
Docker Compose 配置如下:
version: '3'
services:
jenkins:
image: jenkins/jenkins:2.151
container_name: jenkins
networks:
- net
user: "root"
restart: always
ports:
- 9000:8080
environment:
- JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
volumes:
- /etc/localtime:/etc/localtime:ro
- ./data:/var/jenkins_home:rw
- ./backup:/var/jenkins_backup:rw
# 网络配置
networks:
net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.23.0.0/16
说明:
- 初次启动请打印日志, 日志中有管理员帐号的初始密码, 第一次登陆的时候需要用到
- 为了方便, 使用 root 帐号启动容器, 如果使用默认帐号启动需要修改本地目录 ( data、backup ) 的权限
注册账号什么的就不赘述了, 建一个测试项目 test , 随便 commit 几条内容
文章图片
新建测试项目
按下图步骤创建账号的 access token , 用于 Jenkins 调用 GitLab 的 API
文章图片
创建 access token
文章图片
获取 access token
记下这里生成的 access token (
gRCtwVWU8cxwHdxxVZJD
) , 后面要用到。配置 Jenkins
- 安装插件 ( 安装过程可能会失败,多试几次就好了 )
- Git Parameter ( 用于参数化构建中动态获取项目分支 )
- Generic Webhook Trigger ( 用于解析 Webhook 传过来的参数 )
- GitLab ( 用于推送构建结果给 GitLab )
- Git Parameter ( 用于参数化构建中动态获取项目分支 )
- 添加 GitLab 凭据
文章图片
首页 -> 凭据 -> 系统 -> 全局凭据 -> 添加凭据, 把上面 GitLab 中生成的 access token 填进去
- 配置 GitLab 连接
文章图片
首页 -> 系统管理 -> 系统设置 -> Gitlab 配置项, 填入 GitLab 相关的配置, 后面配置项目时用到
- 新建项目 test
文章图片
Jenkins项目完整配置
- 勾选 参数化构建过程, 添加 Git Parameter 类型的参数 ref , 这样构建的时候就可以指定分支进行构建。
- Source Code Management 选择 Git , 添加项目地址和授权方式 ( 帐号密码 或者 ssh key ) , 分支填写构建参数 $ref。
- Build Triggers 选择 Generic Webhook Trigger 方式用于解析 GitLab 推过来的详细参数 ( jsonpath 在线测试 ) 。其他触发方式中: Trigger builds remotely 是 Jenkins 自带的, Build when a change is pushed to GitLab 是 GitLab 插件 提供的, 都属于简单的触发构建, 无法做复杂的处理。
- 虽然 Generic Webhook Trigger 提供了 Token 参数进行鉴权, 但为了避免不同项目进行混调 ( 比如 A 项目提交代码却触发了 B 项目的构建) , 还要对请求做下过滤。Optional filter 中 Text 填写需要校验的内容 ( 可使用变量 ) , Expression 使用正则表达式对 Text 进行匹配, 匹配成功才允许触发构建。
- Build 内容按自己实际的项目类型进行调整, 使用 Maven 插件 或 脚本 等等。
- GitLab Connection 选择上面添加的 GitLab 连接 (
Jenkins
) , Post-build Actions 添加 Publish build status to GitLab 动作, 实现构建结束后通知构建结果给 GitLab。
- 勾选 参数化构建过程, 添加 Git Parameter 类型的参数 ref , 这样构建的时候就可以指定分支进行构建。
- 回到 GitLab 的项目页面中, 添加一个 Webhook ( http://JENKINS_URL/generic-webhook-trigger/invoke?token=<上面 Jenkins 项目配置中的 token> ) , 触发器选择 标签推送事件。因为日常开发中 push 操作比较频繁而且不是每个版本都需要构建, 所以只针对需要构建的版本打上 Tag 就好了。
文章图片
gitlab添加 Webhook
创建完使用 test 按钮 先测试下, 可能会出现下面的错误
Hook execution failed: URL 'http://192.168.xxx.xxx:9000/generic-webhook-trigger/invoke?token=d63ad84eb18cb04d4459ec347a196dce' is blocked: Requests to the local network are not allowed
解决办法: 允许 GitLab 本地网络发送 Webhook 请求
可以在 GitLab 直接添加 Tag , 不过我觉得用 IDEA 上操作更方便点, 就把代码拉下来在本地操作
文章图片
针对每个commit添加tag
然后使用快捷键 Ctrl + Shift + K 调出 Push 窗口 , 把 Tag 推送到 GitLab 中
文章图片
push tag
回到 GitLab 页面可以看到触发了 Webhook , View details 查看请求详情, Response body 中
triggered
字段值为 true
则表示成功触发了 Jenkins 进行构建文章图片
Webhook 触发历史
再看下构建结果
文章图片
gitlab 查看构建结果 — 流水线
文章图片
gitlab 中查看构建结果 — commits
注意: 每添加一个 Tag 就会触发一次事件, 不管是不是一起 push 的。所以一次 push 多个 Tag 会触发 Jenkins 进行多次构建。不过 Jenkins 已经做了处理, 默认串行执行任务 ( 一个任务结束再执行下一个 ) , 而且在构建前有一个 pending 状态, 此时被多次触发会进行合并, 并取首次触发的参数, 如下图所示:
文章图片
同时触发多次事件
关于 Tag 的几点说明
- 推送 Tag 到远端的时候, 远端已存在 ( 同名 ) 的 Tag 不会被添加到远端
- 拉取远端的 Tag 时, 本地已存在 ( 同名 ) 的 Tag 不会添加到本地
- 拉取远端的 Tag 时, 本地不会删除远端已删除的 Tag , 需要同步远端的 Tag 可以先删除本地所有 Tag 再 pull
- 删除 Tag 也会推送事件, 要做好过滤 ( 上面配置中已使用 commitsId 字段进行过滤 )
通过上面的步骤已经初步实现了想要的效果, 还有几个点后续可以再考虑下:
- 上文只包含自动构建的内容, 对于项目的部署可以考虑几种方式: 手动选择指定的版本进行发布、构建任务结束后直接触发部署任务、定时部署最新版本 ( 根据实际需求调整 )。
- 测试发版的频率会比较高, 会生成大量的 Tag , 可以约定 Tag 的格式, 比如
test 0.0.1
表示触发测试环境的项目构建,online 1.0.0
表示触发正式版本构建, 隔离之后可以方便后续的维护和清理。
- 构建部分可以整合 Docker , 把构建结果打包到 Docker 镜像中 ( 代码版本库的 Tag 正好可以作为镜像的 Tag ) , 再上传到 Docker 镜像仓库 ( 私服 或者第三方仓库 ) 中, 后续部署就可以直接从镜像仓库拉取镜像直接运行了。
- 集成自动化测试 , 比如 这个
- 尝试配置 GitLab 自带的 CI / CD
以上就是对曾经踩过的一些坑进行的整合, 也没什么好总结的。总之, 合理地利用现有工具来解放双手, 就能有更多时间做其他想做的事!
【Jenkins|Jenkins + GitLab 自动化构建部署项目】时间有限一些基础的步骤就不细讲直接一笔带过了, 方案上可能有些细节方面也没考虑全, 欢迎评论留言。
推荐阅读
- docker|docker+wordpress搭建个人博客(如何在阿里云服务器上线部署个人博客)
- centos8安装docker
- docker|Centos8的docker安装教程
- Centsos7 安装Docker 及使用过程
- centos8|centos8 安装docker_Centos8下安装docker
- java|云原生爱好者周刊(Grafana Loki 免费电子书)
- kubernetes|云原生爱好者周刊(好家伙,Rust 也成立云原生组织了)
- docker|基于Rust-vmm实现Kubernetes运行时
- V2P|搭建V2P及中青看点教程