本文要点:
设计一条 Spring Boot 最基本的流水线:包括构建、制品上传、部署。
使用 Docker 容器运行构建逻辑。
自动化整个实验环境:包括 Jenkins 的配置,Jenkins agent 的配置等。

1. 代码仓库安排

本次实验涉及以下多个代码仓库:
% tree -L 1
├── 1-cd-platform # 实验环境相关代码
├── 1-env-conf # 环境配置代码-实现配置独立
└── 1-springboot # Spring Boot 应用的代码及其部署代码
1-springboot 的目录结构如下:
% cd 1-springboot
% tree -L 1 
├── Jenkinsfile # 流水线代码
├── README.md
├── deploy # 部署代码
├── pom.xml 
└── src # 业务代码
所有代码,均放在 GitHub:https://github.com/cd-in-practice

2. 实验环境准备

笔者使用 Docker Compose + Vagrant 进行实验。环境包括以下几个系统:
Jenkins * 1 Jenkins master,全自动安装插件、默认用户名密码:admin/admin。
Jenkins agent * 2 Jenkins agent 运行在 Docker 容器中,共启动两个。
Artifactory * 1 一个商业版的制品库。笔者申请了一个 30 天的商业版。
使用 Vagrant 是为了启动虚拟机,用于部署 Spring Boot 应用。如果你的开发机器无法使用 Vagrant,使用 VirtualBox 也可以达到同样的效果。但是有一点需要注意,那就是网络。如果在虚拟机中要访问 Docker 容器内提供的服务,需要在 DNS 上或者 hosts 上做相应的调整。所有的虚拟机的镜像使用 Centos7。
另,接下来笔者的所有教程都将使用 Artifactory 作为制品库。在此申明,笔者没有收 JFrog——研发 Artifactory 产品的公司——任何广告费。 笔者只是想试用商业产品,以便了解商业产品是如何应对制品管理问题的。
启动 Artifactory 后,需要添加 “Virtual Repository” 及 “Local Repository”。具体请查看 Artifactory 的官方文档。如果你当前使用的是 Nexus,参考本教程,做一些调整,问题也不大。
如果想使用已有制品库,可以修改 1-cd-platform 仓库中的 settings-docker.xml 文件,指向自己的制品库。
实验环境近期的总体结构图如下:

之所以说是“近期的”,是因为上图与本篇介绍的结构有小差异。本篇文章还没有介绍 Nginx 与 Springboot 配置共用,但是总体不影响读者理解。

3. Springboot 应用流水线介绍

Springboot 流水线有两个阶段:

构建并上传制品
部署应用
流水线的所有逻辑都写在 Jenkinsfile 文件。接下来,分别介绍这两个阶段。
3.1 构建并上传制品
此阶段核心代码:

docker.image('jenkins-docker-maven:3.6.1-jdk8')
.inside("--network 1-cd-platform_cd-in-practice -v $HOME/.m2:/root/.m2") {
sh """
mvn versions:set -DnewVersion=${APP_VERSION}
mvn clean test package
mvn deploy
"""
}

  

它首先启动一个装有 Maven 的容器,然后在容器内执行编译、单元测试、发布制品的操作。
而 mvn versions:set -DnewVersion=${APP_VERSION} 的作用是更改 pom.xml 文件中的版本。这样就可以实现每次提交对应一个版本的效果。
3.2 部署应用
注意: 这部分需要一些 Ansible 的知识。
首先看部署脚本的入口 1-springboot/deploy/playbook.yaml:

---
-hosts: "springboot" become: yes roles: {"role": "ansible-role-java", "java_home": "{{JAVA_HOME}}"}
- springboot }}}
先安装 JDK,再安装 Spring Boot。JDK 的安装,使用了现成 Ansible role: https://github.com/geerlingguy/ansible-role-java。
重点在 Spring Boot 部署的核心逻辑。它主要包含以下几部分:
创建应用目录。
从制品库下载指定版本的制品。
生成 Systemd service 文件(实现服务化)。
启动服务。
以上步骤实现在 1-springboot/deploy/roles/springboot 中。
流水线的部署阶段的核心代码如下:
{{{
docker.image('williamyeh/ansible:centos7').inside("--network 1-cd-platform_cd-in-practice") { checkout([$class: 'GitSCM', branches: [[name: "master"]], doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: "env-conf"]], submoduleCfg: [],
userRemoteConfigs: [[url: "https://github.com/cd-in-practice/1-env-conf.git"]]]) sh "ls -al" sh """
ansible-playbook --syntax-check deploy/playbook.yaml -i env-conf/dev
ansible-playbook deploy/playbook.yaml -i env-conf/dev --extra-vars '{"app_version": "${APP_VERSION}"}'
"""
}

它首先将配置变量仓库的代码 clone 下来,然后对 playbook 进行语法上的检查,最后执行 ansible-playbook 命令进行部署。--extra-vars 参数的 app_version 用于指定将要部署的应用的版本。

3.3 实现简易指定版本部署

在 1-springboot/Jenkinsfile 中实现了简易的指定版本部署。核心代码如下:
流水线接受参数
parameters { string(name: 'SPECIFIC_APP_VERSION', 
defaultValue: '', description: '') }
如果指定了版本,则跳过构建阶段,直接执行部署阶段

stage("build and upload"){
// 如果不指定部署版本,则执行构建
when {
expression{ return params.SPECIFIC_APP_VERSION == "" }
}
// 构建并上传制品的逻辑
steps{...}
}

之所以说是“简易”,是因为部署时只指定了制品的版本,并没有指定的部署逻辑和配置的版本。这三者的版本要同步,部署才真正做到准确。

4. 配置管理

所有的配置项都放在 1-env-conf 仓库中。Ansible 执行部署时会读取此仓库的配置。
将配置放在 Git 仓库中有两个好处:
配置版本化。
任何配置的更改都可以被审查。
有好处并不代表没有成本。那就是开发人员必须开始关心软件的配置(笔者发现不少开发者忽视配置项管理的重要性。)。
本文重点不在配置管理,后面会有文章重点介绍。

5. 实验环境详细介绍

事实上,整个实验,工作量大的地方有两处:一是 Spring Boot 流水线本身的设计;二是整个实验环境的自动化。读者朋友之所以能一两条简单的命令就能启动整个实验环境,是因为笔者做了很多自动化的工作。笔者认为有必要在本篇介绍这些工作。接下来的文章将不再详细介绍。

5.1 解决流水线中启动的 Docker 容器无法访问 http://artifactory

流水线中,我们需要将制品上传到 artifactory(settings.xml 配置的仓库地址是 http://artifactory:8081),但是发现无法解析 host。这是因为流水线中的 Docker 容器所在网络与 Docker compose 创建的网络不同。所以,解决办法就是让流水线中的 Docker 容器加入到 Docker compose 的网络。
具体解决办法就是在启动容器时,加入参数:--network 1-cd-platform_cd-in-practice

5.2 Jenkins 初次启动初始化

在没有做任何设置的情况启动 Jenkins,会出现一个配置向导。这个过程必须是手工的。笔者希望这一步也是自动化的。Jenkins 启动时会执行 init.groovy.d/目录下的 Groovy 脚本。
5.3 虚拟机中如何能访问到 http://artifactory ?
http://artifactory 部署在 Docker 容器中。Spring Boot 应用的制品要部署到虚拟机中,需要从 http://artifactory 中拉取制品,也就是要在虚拟机里访问容器里提供的服务。虚拟机与容器之间的网络是不通的。那怎么办呢?笔者的解决方案是使用宿主机的 IP 做中转。具体做法就是在虚拟机中加一条 host 记录:

machine.vm.provision "shell" do |s|
s.inline = "echo '192.168.52.1 artifactory' >> /etc/hosts"
end

以上是使用了 Vagrant 的 provision 技术,在执行命令 vagrant up 启动虚拟机时,就自动执行那段内联 shell。192.168.52.1 是虚拟宿主机的 IP。所以,虚拟机里访问 http://artifactory:8081 时,实际上访问的是 http://192.168.52.1:8081
网络结构可以总结为下图:

后记

目前遗留问题:
部署时制品版本、配置版本、部署代码版本没有同步。
Springboot 的配置是写死在制品中的,没有实现制品与配置项的分离。
这些遗留问题在后期会逐个解决。就像现实一样,经常需要面对各种遗留项目的遗留问题。
附录
使用 Jenkins + Ansible 实现自动化部署 Nginx:https://jenkins-zh.cn/wechat/a ... ginx/
简单易懂 Ansible 系列 —— 解决了什么:https://showme.codes/2017-06-12/ansible-introduce/

本文转自公众号 jenkins 
作者 翟志军

使用 Jenkins + Ansible 实现 Spring Boot 自动化部署101的更多相关文章

  1. Sping Boot入门到实战之入门篇(四):Spring Boot自动化配置

    该篇为Sping Boot入门到实战系列入门篇的第四篇.介绍Spring Boot自动化配置的基本原理与实现.   Spring Boot之所以受开发者欢迎, 其中最重要的一个因素就是其自动化配置特性 ...

  2. Spring Boot 系列(六)web开发-Spring Boot 热部署

    Spring Boot 热部署 实际开发中,修改某个页面数据或逻辑功能都需要重启应用.这无形中降低了开发效率,所以使用热部署是十分必要的. 什么是热部署? 应用启动后会把编译好的Class文件加载的虚 ...

  3. 持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本

    持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本 一:本文通过jenkins调用shell脚本的的方式完成从Git服务器获取代码.打包.部署到web服务器.将web服务器从负 ...

  4. 玩转spring boot——war部署

    前言 之前部署spring boot应用是通过直接输入命令“java -jar”来实现的.而有些情况,由于部署环境的制约,只能把项目从jar转换成war才能部署,如新浪云sae的java环境容器.那怎 ...

  5. AWS DevOps – 配合Jenkins和CodeDeploy实现代码自动化部署

    AWS DevOps – 配合Jenkins和CodeDeploy实现代码自动化部署 Amazon ElastiCache 连接至 Redis 节点 通过 AWS Command Line Inter ...

  6. jenkins结合脚本实现代码自动化部署及一键回滚至上一版本

    持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本 一:本文通过jenkins调用shell脚本的的方式完成从Git服务器获取代码.打包.部署到web服务器.将web服务器从负 ...

  7. spring boot: 热部署spring-boot-devtools

    spring boot: 热部署spring-boot-devtools 1引入spring-boot-devtools依赖包 <!-- spring boot devtools 热部署 --& ...

  8. spring boot: 热部署(一) run as – java application (spring-loader-1.2.4.RELEASE.jar)

    spring boot: 热部署(一) run as – java application (spring-loader-1.2.4.RELEASE.jar) 如果使用的run as – java a ...

  9. 从零开始通过idea插件将一个spring boot项目部署到docker容器里运行

    实操:将一个spring boot项目部署到docker容器里运行 实验需要的环境: 腾讯云+Ubuntu 16.04 x64+idea+插件docker integration+daocloud 第 ...

随机推荐

  1. 什么是JMS规范?

    一.简介 JMS是什么:JMS是Java提供的一套技术规范和关于消息中间件的协议 JMS干什么用:通过生产者Producer,消息服务器,以及消费者通力合作,使异构系统能进行集成通信,缓解系统瓶颈,提 ...

  2. ios http 同步异步请求处理

    转自:http://www.cnblogs.com/edisonfeng/p/3830224.html 一.服务端 1.主要结构:

  3. PDF补丁丁将发布开放源代码的1.0版本

    近况 一个月前的今天,母亲永远离开了我. 想起四个月前,我送她了去住院.入院后,做了检查.检查结果没出,我的生日就到了.母亲很关心我的生日.在电话里,她祝我身体健康,又问媳妇有没有给我做生日餐桌的菜肴 ...

  4. LuoguP2382 化学分子式 题解

    Description 你的任务是编写一个能处理在虚拟的化学里分子式的程序,具体地说,给定你所有原子的相对原子质量,求出所有询问的分子的相对分子质量,或者报告不存在. 数据范围:原子质量 \(\leq ...

  5. Python 属性方法、类方法、静态方法、 特殊属性__doc__ (内建属性)

    总结:和类的关联性讲:属性方法>类方法>静态方法 属性方法@property:仅仅是调用方式不用+括号. 类方法@classmethod:访问不了累的属性变量,只可以访问类变量. 静态方法 ...

  6. windows10源码编译llvm

    准备 cmake, 我目前使用的版本是3.18 llvm 源码, 我下载的是 11.0 我已经具备Vs2015和Vs2017的开发环境. debug模式编译需要较多内存和较多硬盘存储空间. (debu ...

  7. Python处理utf-8 添加和删除BOM头

    以下代码只处理了assic和utf8文件.其它文件编码为保险起见并未加入支持. 参数 exts 需要处理文件的扩展名 folders 需要处理的文件夹及子目录 处理目录为当前目录运行:添加bom头 p ...

  8. 【LeetCode】234. Palindrome Linked List 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  9. 【LeetCode】632. Smallest Range 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/smallest ...

  10. 【LeetCode】886. Possible Bipartition 解题报告(Python)

    [LeetCode]886. Possible Bipartition 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu ...