Jenkins、Docker、SpringClound持续集成
- 一、部署介绍
- 1.部署图
- 2.微服务项目结构
- 3.项目启动顺序
- 二、微服务项目在Windows运行
- 1.配置java、maven环境
- 2.初始化数据库表/数据
- 2.1 tensquare_gathering服务表
- 2.2 tensquare_gathering服务表
- 3.启动微服务
- 4.微服务接口测试
- 4.1 获取用户token
- 4.2 获取所有活动
- 三、本地打包和运行微服务
- 1.安装SpringBoot打包库
- 2.打包微服务
- 3.本地运行jar包
- 4.打包遇到的坑
- 四、打包前端代码
- 五、使用Dockerfile制作微服务镜像
- 1.Dockerfile常见命令
- 2.编写eureka服务Dockerfile
- 2.1 将jar包上传linux
- 2.2 编写Dockerfile
- 2.3 构建镜像
- 2.4 启动容器
- 2.5 访问容器
- 六、Docker部署Harbor
- 1.安装
- 2.访问
- 3.创建项目
- 4.创建用户
- 5.给用户分配项目
- 6.本地镜像上传
- 6.1 给镜像打上标签
- 6.2 将harbor地址添加到Docker白名单
- 6.3 命令行登录harbor
- 6.4 推送镜像
- 6.5 从Harbor下载镜像
- 6.5.1 命令行登录Harbor
- 6.5.2 拉取镜像
- 七、微服务持续集成-案例
- 1.项目上传到gitlab
- 1.1 创建git项目
- 1.2 IDEA上传后端项目
- 1.2.1 配置git程序
- 1.2.2 配置GitLab
- 1.2.3 上传代码
- 1.3 Git上传前端代码
- 2.在Jenkins从GitLab拉取源码
- 2.1 创建Jenkins微服务项目
- 2.1.1 创建后端Jenkins项目
- 2.1.2 编写Jenkins脚本文件
- 2.1.3 编写每个微服务harbor配置
- 2.1.3.1 zuul
- 2.1.3.2 eureka
- 2.1.3.3 admin_service
- 2.1.3.3 gathering
- 2.1.4 流水线添加harbor
- 3.微服务打包
- 3.1 Jenkins环境准备
- 3.1.1 安装项目java环境
- 3.1.2 安装maven环境
- 3.1.3 将父工程依赖文件放入maven环境
- 3.1.4 docker环境
- 3.2 对公共子工程打包
- 3.3 对微服务打包
- 4.使用Dockerfile编译、生成镜像
- 4.1 配置构建docker的插件
- 4.2 配置Dockerfile
- 5.上传到Harbor镜像库
- 6.拉取镜像和发布应用
- 6.1 Jenkins安装发布插件
- 6.2 ssh公钥配置
- 6.2.1 公钥传输
- 6.2.2 jenkins公钥配置
- 6.2.2 jenkins项目构建添加端口参数
- 6.2.3 Jenkinsfile添加部署命令
- 6.2.3 编写sh部署脚本
- 6.3 导入微服务的表和数据
- 6.4 修改所有微服务注册中心配置地址
- 6.4 按顺序构建docker并自动部署
- 6.5 测试接口
- 7.部署前端静态web网站
- 7.1 部署服务器安装nginx
- 7.2 Jenkins配置NodeJS
- 7.2.1 安装NodeJS插件
- 7.2.2 安装NodeJS版本
- 7.3 创建前端流水线
- 7.4 修改前端文件BASE_API地址
- 7.5 Jenkins构建
- 八、微服务持续集成-优化
- 1.存在的问题
- 2.集群版eureka配置
- 2.1 eureka微服务配置文件
- 2.2 其他微服务配置文件
- 2.3 Jenkins多选类型参数
- 2.3.1 安装多选框组件
- 2.3.2 创建流水线项目
- 2.3.3 添加微服务项目多选参数
- 2.3.4 添加部署服务器多选参数
- 2.4 Jenkinsfile编写
- 2.5 部署sh脚本编写
- 八、Nginx+zuul集群实现高可用网关
- 1.安装nginx
- 2.修改nginx配置
- 3.重启nginx
一、部署介绍
1.部署图
2.微服务项目结构
- tensquare_admin_service:权限认证服务(登录、注销、token分发等)
- tensquare_common:工具类
- tensquare_eureka_server:单机版eureka服务
- tensquare_gathering:业务服务
- tensquare_zuul:zuul网关服务
3.项目启动顺序
- tensquare_eureka_server
- tensquare_zuul
- tensquare_admin_service
- tensquare_gathering
二、微服务项目在Windows运行
1.配置java、maven环境
- IDEA配置java、maven环境
- 配置好环境后,使用maven下载好所有的依赖包
2.初始化数据库表/数据
2.1 tensquare_gathering服务表
/*
SQLyog 企业版 - MySQL GUI v8.14
MySQL - 5.7.4-m14 : Database - tensquare_gathering
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`tensquare_gathering` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `tensquare_gathering`;
/*Table structure for table `tb_city` */
DROP TABLE IF EXISTS `tb_city`;
CREATE TABLE `tb_city` (
`id` varchar(20) NOT NULL COMMENT 'ID',
`name` varchar(20) DEFAULT NULL COMMENT '城市名称',
`ishot` varchar(1) DEFAULT NULL COMMENT '是否热门',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='城市';
/*Data for the table `tb_city` */
insert into `tb_city`(`id`,`name`,`ishot`) values ('1','北京','1'),('2','上海','1'),('3','广州','1'),('4','深圳','1'),('5','天津','0'),('6','重庆','0'),('7','西安','0');
/*Table structure for table `tb_gathering` */
DROP TABLE IF EXISTS `tb_gathering`;
CREATE TABLE `tb_gathering` (
`id` varchar(20) NOT NULL COMMENT '编号',
`name` varchar(100) DEFAULT NULL COMMENT '活动名称',
`summary` text COMMENT '大会简介',
`detail` text COMMENT '详细说明',
`sponsor` varchar(100) DEFAULT NULL COMMENT '主办方',
`image` varchar(100) DEFAULT NULL COMMENT '活动图片',
`starttime` date DEFAULT NULL COMMENT '开始时间',
`endtime` date DEFAULT NULL COMMENT '截止时间',
`address` varchar(100) DEFAULT NULL COMMENT '举办地点',
`enrolltime` datetime DEFAULT NULL COMMENT '报名截止',
`state` varchar(1) DEFAULT NULL COMMENT '是否可见',
`city` varchar(20) DEFAULT NULL COMMENT '城市',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='活动';
/*Data for the table `tb_gathering` */
insert into `tb_gathering`(`id`,`name`,`summary`,`detail`,`sponsor`,`image`,`starttime`,`endtime`,`address`,`enrolltime`,`state`,`city`) values ('1','测试活动6666','喝茶看电影,不亦乐乎','喝茶看电影,不亦乐乎','黑马程序员',NULL,'2019-11-01','2019-11-01','广州市黑马程序员',NULL,'1','6'),('94377594140','aaaa',NULL,NULL,NULL,NULL,'2019-11-01','2019-11-01',NULL,NULL,'1','1'),('943776146707845','aaaa',NULL,NULL,'ssss',NULL,'2019-11-01','2019-11-01','cccc',NULL,'1','1'),('943776663576121344','aaaa',NULL,NULL,NULL,NULL,'2019-11-01','2019-11-01',NULL,NULL,'1','2'),('943783521749700608','2342423',NULL,NULL,'23454534',NULL,'2019-11-01','2019-11-01','545435435',NULL,'1','2'),('944085821768732672','JAVAEE茶话会',NULL,NULL,'传智',NULL,'2019-11-01','2019-11-01','金燕龙',NULL,'1','2'),('944086086991351808','是',NULL,NULL,'11',NULL,'2019-11-01','2019-11-01','11',NULL,'1','3'),('944090372710207488','大讨论',NULL,NULL,'小马',NULL,'2019-11-01','2019-11-01','消息',NULL,'1','3'),('944105652622594048','测试测试',NULL,NULL,'测试者',NULL,'2019-11-01','2019-11-01','测试地址',NULL,'1','4'),('945227340642914304','111',NULL,NULL,'222',NULL,'2019-11-01','2019-11-01','333',NULL,'1','5'),('945227678527655936','111',NULL,NULL,'222',NULL,'2019-11-01','2019-11-01','333',NULL,'1','5'),('945235087564345344','啊啊',NULL,NULL,'1',NULL,'2019-11-01','2019-11-01','1',NULL,'1','1'),('945235534329024512','1',NULL,NULL,'1',NULL,'2019-11-01','2019-11-01','1',NULL,'1','2'),('945235859786043392','1',NULL,NULL,'1',NULL,'2019-11-01','2019-11-01','1',NULL,'1','3');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
2.2 tensquare_gathering服务表
/*
SQLyog 企业版 - MySQL GUI v8.14
MySQL - 5.7.4-m14 : Database - tensquare_user
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`tensquare_user` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `tensquare_user`;
/*Table structure for table `tb_admin` */
DROP TABLE IF EXISTS `tb_admin`;
CREATE TABLE `tb_admin` (
`id` varchar(20) NOT NULL COMMENT 'ID',
`loginname` varchar(100) DEFAULT NULL COMMENT '登陆名称',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
`state` varchar(1) DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='管理员';
/*Data for the table `tb_admin` */
insert into `tb_admin`(`id`,`loginname`,`password`,`state`) values ('1194281533230419968','admin','$2a$10$PhnLmwA7QarH8M/Wc52Mfekoyqw74Vp619M2p2dnxq0Ltz6xXTWJu','1');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
3.启动微服务
按顺序执行以下服务的Application文件:
tensquare_eureka_server
tensquare_zuul
tensquare_admin_service
tensquare_gathering
- 查看注册中心
4.微服务接口测试
4.1 获取用户token
- Method:POST
- URL:http://localhost:10020/admin/admin/login
- Payload:
{"loginname": "admin", "password": "123456"}
- Response:
{
"flag": true,
"code": 20000,
"message": "管理员登录成功",
"data": {
"roles": "admin",
"name": "admin",
"id": "1194281533230419968",
"token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMTk0MjgxNTMzMjMwNDE5OTY4Iiwic3ViIjoiYWRtaW4iLCJpYXQiOjE3MTIzOTg5NDQsInJvbGVzIjoiYWRtaW4iLCJleHAiOjE3MTI0MDA3NDR9.59JOUrd8E4YlEZwZL3n-nxyOIL620cT2YqjA61N1sRg"
}
}
4.2 获取所有活动
- Method:GET
- URL:http://localhost:10020/gathering/gathering
- Header
token:eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMTk0MjgxNTMzMjMwNDE5OTY4Iiwic3ViIjoiYWRtaW4iLCJpYXQiOjE3MTIzOTg5NDQsInJvbGVzIjoiYWRtaW4iLCJleHAiOjE3MTI0MDA3NDR9.59JOUrd8E4YlEZwZL3n-nxyOIL620cT2YqjA61N1sRg
三、本地打包和运行微服务
1.安装SpringBoot打包库
- 如果不使用下面的插件,那么打包的jar包是不包含依赖包。
- 在父工程下的pom.xml写入下面的库
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.打包微服务
如果用的IDEA 2020,那么maven需要用3.6.3,否则会报错
- 总共有四个微服务,最终打包后有4个jar包
- 四个微服务都是如下图的操作
3.本地运行jar包
- jar -r xxx.jar
4.打包遇到的坑
- 在没有主文件的工程,在pom.xml需要加入以下
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
<executions>
<execution>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
四、打包前端代码
- 技术栈:NodeJS+VueJS+ElementUI
# 1.本地运行
npm run dev
# 2.打包静态web网站
npm run build
# 打包后,产生dist目录的静态文件
# 3.部署到nginx服务器把dist目录的静态文件拷贝到nginx的html目录,启动nginx
五、使用Dockerfile制作微服务镜像
1.Dockerfile常见命令
命令 | 作用 |
---|---|
FROM image_name:tag | |
MAINTAINER user_name | 声明镜像的作者 |
ENV key value | 设置环境变量 (可以写多条) |
RUN command | 编译镜像时运行的脚本(可以写多条) |
CMD | 设置容器的启动命令 |
ENTRYPOINT | 设置容器的入口程序 |
ADD source_dir/file dest_dir/file | 将宿主机的文件复制到容器内,如果是一个压缩文件,将会在复制后自动解压 |
COPY source_dir/file dest_dir/file | 和ADD相似,但是如果有压缩文件并不能解压 |
WORKDIR path_dir | 设置工作目录 |
ARG | 设置编译镜像时加入的参数 |
VOLUMN | 设置容器的挂载卷 |
- RUN、CMD、ENTRYPOINT的区别?
- RUN:用于指定 docker build 过程中要运行的命令,即是创建 Docker 镜像(image)的步骤
- CMD:设置容器的启动命令, Dockerfile 中只能有一条 CMD 命令,如果写了多条则 后一条生效,CMD不支持接收docker run的参数。
- ENTRYPOINT:入口程序是容器启动时执行的程序, docker run 中 后的命令将作为参数传递给入口程序 ,ENTRYPOINY类似于 CMD 指令,但可以接收docker run的参数 。
2.编写eureka服务Dockerfile
其他服务和eureka服务的镜像构建步骤是一样的。
2.1 将jar包上传linux
2.2 编写Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10086
ENTRYPOINT ["java", "-jar", "/app.jar"]
- 参数解析:
FROM openjdk:8-jdk-alpine
:拉取openjdk:8-jdk-alpine作为基础镜像ARG JAR_FILE
:定义一个JAR_FILE参数,需要外部传入COPY ${JAR_FILE} app.jar
:拷贝一个文件,命名为app.jarEXPOSE 10086
:暴露10086端口EXTRYPOINT ["java", "-jar", "/app.jar"]
:设置java项目启动命令
2.3 构建镜像
docker build --build-arg JAR_FILE=tensquare_eureka_server-1.0-SNAPSHOT.jar -t eureka:v1 .
2.4 启动容器
docker run -i --name=eureka -p 10086:10086 eureka:v1
2.5 访问容器
- http://192.168.86.128:10086
六、Docker部署Harbor
1.安装
Harbor是基于docker的,所以需要安装docker和docker-compose。
- docker和docker-compose版本要求:
- docker 20.10.10-ce+
- docker-compose 1.18.0+
- 注意事项:
- 数据存放路径应在配置文件中配置到一个容量比较充足的共享存储中
- Harbor是使用docker-compose命令来管理的,如果需要停止Harbor也应用docker-compose stop来停止
- 部署docker教程:https://blog.csdn.net/qq_37344058/article/details/131270071
- 部署docker-compose教程:https://blog.csdn.net/qq_37344058/article/details/136065167
- 下载地址:https://github.com/goharbor/harbor/releases
需要下载offline的压缩包
# 1.下载harbor安装包
wget https://github.com/goharbor/harbor/releases/download/v2.9.3/harbor-offline-installer-v2.9.3.tgz
# 2.解压到/usr/local,并进入到解压目录
tar zxvf harbor-offline-installer-v2.9.3.tgz -C /usr/local/ && cd /usr/local/harbor/
# 3.拷贝一份配置文件
cp harbor.yml.tmpl harbor.yml
# 4.查看当前主机全称
hostname
# 5.修改配置文件
vi harbor.yml
# 5.1 修改hostname
# 5.2 https这行及子行都注释掉,因为没有弄ssl证书加密
下面hostname尽量填IP地址,填hostname有问题
# 6.启动harbor
./install.sh
注意:这是因为在启动docker的时候防火墙做了策略,如果容器在运行中,停止防火墙,在操作容器就会报这个错误,我们可以重启docker解决此问题
重启docker服务:systemctl restart docker.service
启动harbor:docker-compose up -d
- Harbor的命令汇总
- 启动harbor:docker-compose up -d
- 关闭harbor:docker-compose stop
- 重启harbor:docker-compose restart
2.访问
访问地址:harbor的服务器ip地址
账号密码:用户名(admin)、密码(可在harbor.yml配置文件中找到,修改密码的话也在这里面改)
3.创建项目
- Harbor的项目分为公开和私有的
- 公开项目:所有用户都可以访问,通常存放公共的镜像,默认有一个library公开项目。
- 私有项目:只有授权用户才可以访问,通常存放项目本身的镜像。
- 以下为微服务创建一个项目
- 创建了个私有项目
4.创建用户
5.给用户分配项目
- 分配项目的时候,可以选择角色:
- 项目管理员:对当前项目有所有权限
- 维护人员:拥有对 Harbor 系统的维护权限,包括监控系统状态、执行备份和恢复操作、维护存储等。
- 开发人员:对镜像进行上传和下载
- 访客:只能下载,不能上传
6.本地镜像上传
- 上传刚刚创建的eureka镜像
6.1 给镜像打上标签
# 通用格式:docker tag 镜像名称:镜像版本 harbor的IP:85/项目名称/镜像名称:镜像版本
docker tag eureka:v1 192.168.86.128/tensquare/eureka:v1
6.2 将harbor地址添加到Docker白名单
- 默认情况,docker不允许把镜像传入到harbor,因为docker不新人harbor地址
vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"],
"insecure-registries": ["192.168.86.128"]
}
重启docker:systemctl restart docker
启动harbor:cd /usr/local/harbor && docker-compose up -d
6.3 命令行登录harbor
docker login -u 用户名 -p 密码 192.168.86.128
6.4 推送镜像
docker push 192.168.86.128/tensquare/eureka:v1
6.5 从Harbor下载镜像
6.5.1 命令行登录Harbor
docker login -u 用户名 -p 密码 192.168.86.128
6.5.2 拉取镜像
docker pull 192.168.86.128/tensquare/eureka:v1
七、微服务持续集成-案例
1.项目上传到gitlab
1.1 创建git项目
- 需要创建两个项目:
- 前端:tensquare_front
- 后端:tensquare_back
1.2 IDEA上传后端项目
1.2.1 配置git程序
1.2.2 配置GitLab
- 将ssh的链接,填入进去即可。
1.2.3 上传代码
1.3 Git上传前端代码
- 步骤
- 将前端仓库clone
- 将前端代码粘贴进去
- 提交后push
# 1.将前端仓库clone
git clone ssh://git@192.168.86.128:9922/tensquare/tensquare_front.git
cd tensquare_front
# 2.创建分支
git switch --create main
# 3.提交代码
git add . && git commit -m "初始化项目" && git push --set-upstream origin main
2.在Jenkins从GitLab拉取源码
2.1 创建Jenkins微服务项目
- 创建两个微服务项目,并且都是流水线项目
- 前端:tensquare_front
- 后端:tensquare_back
2.1.1 创建后端Jenkins项目
2.1.2 编写Jenkins脚本文件
- 脚本文件放到父工程根根目录:Jenkinsfile
- 下面是脚本式
- 检出git脚本生成
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: '6856b58c-2349-4673-aec6-278f08335aff', url: 'http://192.168.86.128:9980/tensquare/tensquare_back.git']])
- 将一些变量抽取出来
//git凭证ID
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
//git的url地址
def git_url = "http://192.168.86.128:9980/tensquare/tensquare_back.git"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
}
2.1.3 编写每个微服务harbor配置
- 在每一个微服务下面,防止一个harbor代码扫描的配置文件:sonar-project.properties
2.1.3.1 zuul
# must be unique in a given SonarQube instance
sonar.projectKey=tensquare_zuul
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=tensquare_zuul
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.binaries=.
sonar.java.source=1.8
sonar.java.target=1.8
#sonar.java.libraries=**/target/classes/**
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
2.1.3.2 eureka
# must be unique in a given SonarQube instance
sonar.projectKey=tensquare_eureka_server
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=tensquare_eureka_server
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.binaries=.
sonar.java.source=1.8
sonar.java.target=1.8
#sonar.java.libraries=**/target/classes/**
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
2.1.3.3 admin_service
# must be unique in a given SonarQube instance
sonar.projectKey=tensquare_admin_service
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=tensquare_admin_service
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.binaries=.
sonar.java.source=1.8
sonar.java.target=1.8
#sonar.java.libraries=**/target/classes/**
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
2.1.3.3 gathering
# must be unique in a given SonarQube instance
sonar.projectKey=tensquare_gathering
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=tensquare_gathering
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.binaries=.
sonar.java.source=1.8
sonar.java.target=1.8
#sonar.java.libraries=**/target/classes/**
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
2.1.4 流水线添加harbor
- 由于涉及到多个微服务,构建的时候,需要有个下拉框可以选择,构建哪些微服务。以下是添加微服务名称下拉框,可以多选
- 下面是加入了代码扫描的pipeline代码
//git凭证ID
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
//git的url地址
def git_url = "http://192.168.86.128:9980/tensquare/tensquare_back.git"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
stage('代码审查') {
//定义当前Jenkins的SonarQubeScanner工具:下面配置的是 全局配置里面的name
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境:下面配置的是系统配置的name
withSonarQubeEnv('SonarQube-Server') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
3.微服务打包
3.1 Jenkins环境准备
3.1.1 安装项目java环境
3.1.2 安装maven环境
- 安装教程:https://qingsi.blog.csdn.net/article/details/137710489
- maven环境如果安装了,运行jenkins报错
- 因为Jenkins 通过shell脚本调用 mvn 命令的时候,是从/usr/bin 文件夹中找命令的
ln -s /usr/local/maven/apache-maven-3.6.3/bin/mvn /usr/bin/mvn
ln -s /usr/local/maven/apache-maven-3.6.3/bin/mvn /usr/local/bin/mvn
3.1.3 将父工程依赖文件放入maven环境
- 第一种方案:资料包里面有:tensquare_parent.tar.gz
- 放入到:/data/mavenfile/com/tensquare下面
- 第二种方案:打包安装父工程:
mvn -f pom.xml clean install
- pom.xml是父工程的
3.1.4 docker环境
- 需要安装docker环境
3.2 对公共子工程打包
- 由于公共子工程不是Spring服务启动的,而其他的服务依赖于这个包,所以需要提前将公共子工程打包好,并且安装到maven本地仓库
- 在Jenkinsfile加入打包子工程打包安装的步骤
//git凭证ID
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
//git的url地址
def git_url = "http://192.168.86.128:9980/tensquare/tensquare_back.git"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
stage('代码审查') {
//定义当前Jenkins的SonarQubeScanner工具:下面配置的是 全局配置里面的name
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境:下面配置的是系统配置的name
withSonarQubeEnv('SonarQube-Server') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
}
3.3 对微服务打包
- 在Jenkinsfile加入新步骤打包微服务
//git凭证ID
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
//git的url地址
def git_url = "http://192.168.86.128:9980/tensquare/tensquare_back.git"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
stage('代码审查') {
//定义当前Jenkins的SonarQubeScanner工具:下面配置的是 全局配置里面的name
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境:下面配置的是系统配置的name
withSonarQubeEnv('SonarQube-Server') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,打包微服务工程') {
sh "mvn -f ${project_name} clean package"
}
}
4.使用Dockerfile编译、生成镜像
4.1 配置构建docker的插件
- 在每个微服务项目的pom.xml加入dockerfile-maven-plugin插件
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<repository>${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
4.2 配置Dockerfile
- 在每个微服务项目根目录下建立Dockerfile文件
- 注意:每个项目公开的端口不一样
#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 9002
ENTRYPOINT ["java","-jar","/app.jar"]
- 在父工程的Jenkinsfile添加docker build的命令
//git凭证ID
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
//git的url地址
def git_url = "http://192.168.86.128:9980/tensquare/tensquare_back.git"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
stage('代码审查') {
//定义当前Jenkins的SonarQubeScanner工具:下面配置的是 全局配置里面的name
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境:下面配置的是系统配置的name
withSonarQubeEnv('SonarQube-Server') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,打包微服务工程') {
sh "mvn -f ${project_name} clean package dockerfile:build"
}
}
5.上传到Harbor镜像库
- 修改Jenkinsfile脚本
//git凭证ID
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
//git的url地址
def git_url = "http://192.168.86.128:9980/tensquare/tensquare_back.git"
//镜像的版本号
def tag = "latest"
//Harbor的url地址
def harbor_url = "192.168.86.128"
//镜像库项目名称
def harbor_project = "tensquare"
//Harbor的登录凭证ID:这个ID,是在jenkins里面创建的凭证(harbor的账号密码)的ID
def harbor_auth = "bf8ca22e-aee0-4533-bf63-185dac0bef1a"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
stage('代码审查') {
//定义当前Jenkins的SonarQubeScanner工具:下面配置的是 全局配置里面的name
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境:下面配置的是系统配置的name
withSonarQubeEnv('SonarQube-Server') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,打包微服务工程,上传镜像') {
sh "mvn -f ${project_name} clean package dockerfile:build"
//定义镜像名称
def imageName = "${project_name}:${tag}"
//对镜像打上标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
//把镜像推送到Harbor
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
//登录到Harbor
sh "docker login -u ${username} -p ${password} ${harbor_url}"
//镜像上传
sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
sh "echo 镜像上传成功"
}
}
}
- jenkins打包发布成功
- harbor显示有镜像保存
6.拉取镜像和发布应用
- 本次案例,在jenkins的服务器(192.168.86.128)上面,发布到应用服务器(192.168.86.131)上面部署。和部署到其他服务器一样的步骤。
- 部署应用的机器环境:
- 确保安装了docker
6.1 Jenkins安装发布插件
- Publish Over SSH插件
6.2 ssh公钥配置
6.2.1 公钥传输
- 查看jenkins的机器上是否有密钥公钥:
- 查看/root/.ssh 是否有:id_rsa.pub、id_rsa文件
- 查看/root/.ssh 是否有:id_rsa.pub、id_rsa文件
- 如果没有的话,需要生成:
ssh-keygen -t rsa -C 'xxx@xxx.com'
# 下面一路回车即可
- 将jenkins服务器的公钥,传送到应用部署的服务器上
ssh-copy-id 192.168.86.128
6.2.2 jenkins公钥配置
- Passphrase:是填写jenkins服务器生成的ssh key的密码,一般置空,不予理睬
- path to key:jenkins服务器生成的私钥存放目录文件。
- key:直接填写jenkins服务器生成的私钥。
注意:path to key 和 key 二选一即可
6.2.2 jenkins项目构建添加端口参数
- 这个参数用于传入到启动微服务容器的端口
6.2.3 Jenkinsfile添加部署命令
- 可以在流水线代码生成那里生成命令
//git凭证ID
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
//git的url地址
def git_url = "http://192.168.86.128:9980/tensquare/tensquare_back.git"
//镜像的版本号
def tag = "latest"
//Harbor的url地址
def harbor_url = "192.168.86.128"
//镜像库项目名称
def harbor_project = "tensquare"
//Harbor的登录凭证ID:这个ID,是在jenkins里面创建的凭证(harbor的账号密码)的ID
def harbor_auth = "bf8ca22e-aee0-4533-bf63-185dac0bef1a"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
stage('代码审查') {
//定义当前Jenkins的SonarQubeScanner工具:下面配置的是 全局配置里面的name
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境:下面配置的是系统配置的name
withSonarQubeEnv('SonarQube-Server') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,打包微服务工程,上传镜像') {
sh "mvn -f ${project_name} clean package dockerfile:build"
//定义镜像名称
def imageName = "${project_name}:${tag}"
//对镜像打上标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
//把镜像推送到Harbor
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
//登录到Harbor
sh "docker login -u ${username} -p ${password} ${harbor_url}"
//镜像上传
sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
def i = "docker push ${harbor_url}/${harbor_project}/${imageName}"
sh "echo ${i}"
sh "echo 镜像上传成功"
}
// 部署应用
// 1.execCommand的$port,需要作为一个构建参数传入
sh "echo 开始部署"
def execCommand = "/opt/jenkins_shell/deploy.sh ${harbor_url} ${harbor_project} ${project_name} ${tag} ${port}"
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${execCommand}", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
sh "echo 部署完成"
}
}
6.2.3 编写sh部署脚本
- 该放置到部署应用服务器,路径为:/opt/jenkins_shell
- 脚本名称:deploy.sh
- 注意:脚本需要授权:
chmod +x de
#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
echo "$imageName"
#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
#停掉容器
docker stop $containerId
#删除容器
docker rm $containerId
echo "成功删除容器"
fi
#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
#删除镜像
docker rmi -f $imageId
echo "成功删除镜像"
fi
# 登录Harbor
docker login -u admin -p Harbor12345 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName
echo "容器启动成功"
6.3 导入微服务的表和数据
- tensquare_gathering.sql、tensquare_user.sql
6.4 修改所有微服务注册中心配置地址
- 将注册中心的地址,改为实际部署的服务器地址
6.4 按顺序构建docker并自动部署
- 微服务构建顺序:
- tensquare_eureka_server
- tensquare_zuul
- tensquare_admin_service
- tensquare_gathering
6.5 测试接口
- 登录接口
7.部署前端静态web网站
7.1 部署服务器安装nginx
- Docker部署nginx教程:https://blog.csdn.net/qq_37344058/article/details/137742556
7.2 Jenkins配置NodeJS
7.2.1 安装NodeJS插件
- 安装插件NodeJS
7.2.2 安装NodeJS版本
7.3 创建前端流水线
- 项目名称:tensquare_front
// gitlab的凭证
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
node {
stage('拉取代码') {
checkout scmGit(branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: '${git_auth}', url: 'http://192.168.86.128:9980/tensquare/tensquare_front.git']])
}
stage('代码审查') {
// 使用NodeJS的npm进行打包
nodejs("nodejs12"){
sh '''
npm install
npm run build
'''
// 以下为远程调用进行项目部署:使用的是目录拷贝的方式
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/root/docker/nginx/html', remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/**')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
}
7.4 修改前端文件BASE_API地址
- 修改为网关地址
7.5 Jenkins构建
八、微服务持续集成-优化
1.存在的问题
- 上面部署方案存在的问题:
- 一次只能选择一个微服务部署
- 只有一台生产者部署服务器
- 每个微服务只有一个实例,容错率低
- 优化方案:
- 在一个Jenkins工程中可以选择多个微服务同时发布
- 在一个Jenkins工程中可以选择多台生产服务器同时部署
- 每个微服务都是以集群高可用形式部署
2.集群版eureka配置
2.1 eureka微服务配置文件
- 在启动微服务的时候,加入参数: spring.profiles.active 来读取对应的配置
# 集群版
spring:
application:
name: EUREKA-HA
---
server:
port: 10086
spring:
# 指定profile=eureka-server1
profiles: eureka-server1
eureka:
instance:
# 指定当profile=eureka-server1时,主机名是eureka-server1
hostname: 192.168.86.131
client:
service-url:
# 将自己注册到eureka-server1、eureka-server2这个Eureka上面去
defaultZone: http://192.168.86.131:10086/eureka/,http://192.168.86.132:10086/eureka/
---
server:
port: 10086
spring:
profiles: eureka-server2
eureka:
instance:
hostname: 192.168.86.132
client:
service-url:
defaultZone: http://192.168.86.131:10086/eureka/,http://192.168.86.132:10086/eureka/
2.2 其他微服务配置文件
- 将defaultZone改为:http://192.168.86.131:10086/eureka/,http://192.168.86.132:10086/eureka
2.3 Jenkins多选类型参数
2.3.1 安装多选框组件
- Extended Choice Parameter Plugin
2.3.2 创建流水线项目
2.3.3 添加微服务项目多选参数
2.3.4 添加部署服务器多选参数
2.4 Jenkinsfile编写
//git凭证ID
def git_auth = "6856b58c-2349-4673-aec6-278f08335aff"
//git的url地址
def git_url = "http://192.168.86.128:9980/tensquare/tensquare_back.git"
//镜像的版本号
def tag = "latest"
//Harbor的url地址
def harbor_url = "192.168.86.128"
//镜像库项目名称
def harbor_project = "tensquare"
//Harbor的登录凭证ID:这个ID,是在jenkins里面创建的凭证(harbor的账号密码)的ID
def harbor_auth = "bf8ca22e-aee0-4533-bf63-185dac0bef1a"
node {
// 获取当前选择的项目名称
def selectedProjectNames = "${project_name}".split(",")
//获取当前选择的服务器名称
def selectedServers = "${publish_server}".split(",")
stage('拉取代码') {
checkout scmGit(branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]])
}
stage('代码审查') {
// for循环每个项目代码
for(int i=0;i<selectedProjectNames.length;i++){
// tensquare_eureka_server@10086
def projectInfo = selectedProjectNames[i];
// 当前遍历的项目名称
def currentProjectName = "${projectInfo}".split("@")[0]
// 当前遍历的项目端口
def currentProjectPort = "${projectInfo}".split("@")[1]
//定义当前Jenkins的SonarQubeScanner工具:下面配置的是 全局配置里面的name
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境:下面配置的是系统配置的name
withSonarQubeEnv('SonarQube-Server') {
sh """
cd ${currentProjectName}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,打包微服务工程,上传镜像') {
// for循环每个项目代码
for(int i=0;i<selectedProjectNames.length;i++){
// tensquare_eureka_server@10086
def projectInfo = selectedProjectNames[i];
// 当前遍历的项目名称
def currentProjectName = "${projectInfo}".split("@")[0]
// 当前遍历的项目端口
def currentProjectPort = "${projectInfo}".split("@")[1]
sh "mvn -f ${project_name} clean package dockerfile:build"
//定义镜像名称
def imageName = "${currentProjectName}:${tag}"
//对镜像打上标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
//把镜像推送到Harbor
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
//登录到Harbor
sh "docker login -u ${username} -p ${password} ${harbor_url}"
//镜像上传
sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
def i = "docker push ${harbor_url}/${harbor_project}/${imageName}"
sh "echo ${i}"
sh "echo 镜像上传成功"
}
// 遍历所有的服务器,分别部署
for(int j=0;j<selectedServers.length;j++){
//获取当前遍历的服务器名称
def currentServerName = selectedServers[j]
//加上的参数格式:--spring.profiles.active=eureka-server1/eureka-server2
def activeProfile = "--spring.profiles.active="
//根据不同的服务名称来读取不同的Eureka配置信息
if(currentServerName=="master_server"){
activeProfile = activeProfile+"eureka-server1"
}else if(currentServerName=="slave_server"){
activeProfile = activeProfile+"eureka-server2"
}
// 部署应用
def execCommand = "/opt/jenkins_shell/deployCluster.sh ${harbor_url} ${harbor_project} ${currentProjectName} ${tag} ${currentProjectPort} ${activeProfile}"
sshPublisher(publishers: [sshPublisherDesc(configName: "${currentServerName}", transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${execCommand}", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
}
}
2.5 部署sh脚本编写
#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
profile=$6
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
echo "$imageName"
#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
#停掉容器
docker stop $containerId
#删除容器
docker rm $containerId
echo "成功删除容器"
fi
#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
#删除镜像
docker rmi -f $imageId
echo "成功删除镜像"
fi
# 登录Harbor
docker login -u eric -p Eric123456 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName $profile
echo "容器启动成功"
八、Nginx+zuul集群实现高可用网关
- 这里只需要使用nginx的负载均衡功能即可
1.安装nginx
- 之前已经安装过
2.修改nginx配置
vi /etc/nginx/nginx.conf
加入以下内容
upstream zuulServer {
server 192.168.66.103:10020 weight=1;
server 192.168.66.104:10020 weight=1;
}
server {
location / {
proxy_pass http://zuulServer/;
}
}
3.重启nginx
- 由于是docker部署的:docker restart nginx