文档章节

使用 Jenkins + Ansible 实现 Spring Boot 自动化部署101

Jenkins中文社区
 Jenkins中文社区
发布于 05/21 19:53
字数 2055
阅读 24
收藏 0

本文首发于:Jenkins 中文社区

本文要点:

  1. 设计一条 Spring Boot 最基本的流水线:包括构建、制品上传、部署。
  2. 使用 Docker 容器运行构建逻辑。
  3. 自动化整个实验环境:包括 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 流水线有两个阶段:

  1. 构建并上传制品
  2. 部署应用

流水线的所有逻辑都写在 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 部署的核心逻辑。它主要包含以下几部分:

  1. 创建应用目录。
  2. 从制品库下载指定版本的制品。
  3. 生成 Systemd service 文件(实现服务化)。
  4. 启动服务。

以上步骤实现在 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 中实现了简易的指定版本部署。核心代码如下:

  1. 流水线接受参数
parameters { string(name: 'SPECIFIC_APP_VERSION', 
defaultValue: '', description: '') }


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


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

4. 配置管理

所有的配置项都放在 1-env-conf 仓库中。Ansible 执行部署时会读取此仓库的配置。

将配置放在 Git 仓库中有两个好处:

  1. 配置版本化。
  2. 任何配置的更改都可以被审查。

有好处并不代表没有成本。那就是开发人员必须开始关心软件的配置(笔者发现不少开发者忽视配置项管理的重要性。)。

本文重点不在配置管理,后面会有文章重点介绍。

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

网络结构可以总结为下图:

后记

目前遗留问题:

  1. 部署时制品版本、配置版本、部署代码版本没有同步。
  2. Springboot 的配置是写死在制品中的,没有实现制品与配置项的分离。

这些遗留问题在后期会逐个解决。就像现实一样,经常需要面对各种遗留项目的遗留问题。

附录

  1. 使用 Jenkins + Ansible 实现自动化部署 Nginx:https://jenkins-zh.cn/wechat/articles/2019/04/2019-04-25-jenkins-ansible-nginx/
  2. 简单易懂 Ansible 系列 —— 解决了什么:https://showme.codes/2017-06-12/ansible-introduce/

作者:翟志军

© 著作权归作者所有

Jenkins中文社区

Jenkins中文社区

粉丝 25
博文 32
码字总数 52171
作品 0
杭州
私信 提问
spring-boot项目的docker集成化部署

spring-boot项目的docker集成化部署 [toc] 前言 据说流行的微服务和docker一起,更配哦!接下来,使用简单spring-boot项目演示docker的集成化部署的案例,在看过微笑的博客觉得不过瘾,自己动...

weir_will
2018/10/06
0
0
在微服务领域Spring Boot自动伸缩如何实现

自动伸缩是每个人都想要的,尤其是在微服务领域。让我们看看如何在基于Spring Boot的应用程序中实现。 我们决定使用 Kubernetes 、 Pivotal Cloud Foundry 或 HashiCorp's Nomad 等工具的一个...

微笑向暖wx
2018/10/14
0
0
使用 Jenkins X、Kubernetes 和 Spring Boot 实现 CI/CD

本文首发于:Jenkins 中文社区 过去五年中的变化,如迁移到公有云以及从虚拟机向容器的转变,已经彻底改变了构建和部署软件的意义。 以 Kubernetes 为例。Google 于2014年开源,现在所有主流...

Jenkins中文社区
05/27
0
0
一步一步用jenkins,ansible,supervisor打造一个web构建发布系统

新blog地址:http://hengyunabc.github.io/deploy-system-build-with-jenkins-ansible-supervisor/ 一步一步用jenkins,ansible,supervisor打造一个web构建发布系统。 本来应该还有gitlab这......

横云断岭
2015/03/05
0
0
使用 Jenkins + Ansible 实现自动化部署 Nginx

本文首发于:Jenkins 中文社区 本文介绍如何使用 Jenkins + Ansible 实现对 Nginx 的自动化部署。最终达到的效果有如下几点: 只要你将 Nginx 的配置推送到 GitHub 中,Jenkins 就会自动执行...

Jenkins中文社区
04/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java的线程同步和并发问题示例

并发问题 多线程是一个非常强大的工具,它使我们能够更好地利用系统的资源,但我们需要在读取和写入多个线程共享的数据时特别小心。 当多个线程尝试同时读取和写入共享数据时,会出现两种类型...

hiuh
今天
3
0
Spring Boot 常用注解说明

实体类 @Entity (实体类注解) @Table(可指定表名) @Data(可缺省get/set) @Id (指定属性主键) @GeneratedValue(指定主键生成规则)

兜兜毛毛
今天
3
0
局域网能互相ping通,ubuntu虚拟机不能上外网

【问题】 桥接模式老是无法上网,查看本机IP发现被分配了一个私网地址,猜测应该是虚拟DHCP服务器没有打开,于是查看Ubuntu的网络配置: /etc/network/interfaces 发现没有dhcp配置的信息,只...

tahiti_aa
今天
2
0
以太坊助记词PHP开发包简介

以太坊助记词PHP开发包用来为PHP以太坊应用增加助记词和层级确定密钥支持能力。下载地址:以太坊助记词php开发包 。 1、开发包概述 以太坊助记词PHP开发包主要包括以下特性: 生成符合BIP39...

汇智网教程
昨天
4
0
系统监控-分布式调用链Skywalking

1. 为什么要使用分布式调用链技术? 随着公司业务的高速发展,公司服务之间的调用关系愈加复杂,如何理清并跟踪它们之间的调用关系就显的比较关键。线上每一个请求会经过多个业务系统,并产生...

秋日芒草
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部