Jenkins—— Jenkins+Docker+SpringCloud微服务持续集成项目优化和集群
Posted stan Z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jenkins—— Jenkins+Docker+SpringCloud微服务持续集成项目优化和集群相关的知识,希望对你有一定的参考价值。
Jenkins+Docker+SpringCloud微服务持续集成项目的优化
前言
这篇笔记是作为上一章项目进行的优化
优化方案:
- 在一个Jenkins工程中可以选择多个微服务同时发布
- 在一个Jenkins工程中可以选择多台生产服务器同时部署
- 每个微服务都是以集群高可用形式部署
Jenkins+Docker+SpringCloud集群部署流程优化
- 部署服务的时候不再手动一个一个去构建,通过循环一次构建
- 通过集群的方式实现负载均衡
修改所有微服务的配置
修改eruka的配置
需要实现一个相互注册的功能
修改eureka_server的配置
spring:
application:
name: EUREKA-HA
---
server:
port: 10086
spring:
# 指定profile=eureka-server1
profiles: eureka-server1
eureka:
instance:
# 指定当profile=eureka-server1时,主机名是eureka-server1
hostname: 47.108.189.123
client:
service-url:
# 将自己注册到eureka-server1、eureka-server2这个Eureka上面去
defaultZone: http://47.108.189.123:10086/eureka/,http://47.108.190.228:10086/eureka/
---
server:
port: 10086
spring:
profiles: eureka-server2
eureka:
instance:
hostname: 47.108.190.228
client:
service-url:
defaultZone: http://47.108.189.123:10086/eureka/,http://47.108.190.228:10086/eureka/
在启动微服务的时候,加入参数: spring.profiles.active
来读取对应的配置
然后其他服务只需更改注册地址
修改zuul、admin_service、gathering的配置
就是在配置里由原先一台增加到两台服务器的地址
http://47.108.189.123:10086/eureka/,http://47.108.190.228:10086/eureka/
将修改的文件上传仓库
设计Jenkins集群项目的构建参数
创建流水线项目(集群版)
选择SCM
因为要进行多项选择,所以需要插件Extended Choice Parameter
安装Extended Choice Parameter
插件
进入流水线项目
先添加一个普通的字符串参数
再添加多选参数
点击保存之后去构建项目
这里出现了可以多选择的效果
编写多选项遍历Jenkins脚本
多选项进行代码审查
// git凭证ID
def git_auth = "41580d48-d4c3-4116-9a71-4d4d777c5753"
// git的url地址
def git_url = "git@192.168.188.110:maomao_group/tensquare_back.git"
// 镜像的版本号
def tag = "latest"
// Harbor的url地址
def harbor_url = "192.168.188.115:85"
// 镜像库项目名称
def harbor_project = "tensquare"
// Harbor的登录凭据ID
def harbor_auth = "c0e6642d-bab9-4978-be45-955e5130fae2"
node {
// 获取当前选择的项目名称
def selectedProjectNames = "${project_name}".split(",")
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
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工具环境 在全局工具配置里查看
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境 在系统配置里查看
withSonarQubeEnv('sonarqube') {
sh """
cd ${currentProjectName}
${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 镜像上传成功啦"
}
// 部署项目
sshPublisher(publishers: [sshPublisherDesc(configName: 'tomcat_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deploy.sh $harbor_url $harbor_project $project_name $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
其实改变的地方就是
- 使用
split(“,”)
分隔项目名称(因为是以,号分隔的) - 代码审查里面,需要使用遍历循环去检测每个服务的代码
- for循环遍历多选的服务,
lenght
获取长度 - 因为项目名称@端口,所以需要分别获取名称和端口,用于sonarqube进入相应的空间
上传jenkinsfile到仓库之后通过多选构建项目
先进行两个项目的测试
进行eruka的审查
进行了zuul的审查
因为只是为了测试遍历选项是否成功,后面会构建失败,所以不用担心
完成多选项微服务构建、上传镜像
这一步进行镜像的构建和上传,因为可以先把部署应用的代码注释
// git凭证ID
def git_auth = "41580d48-d4c3-4116-9a71-4d4d777c5753"
// git的url地址
def git_url = "git@192.168.188.110:maomao_group/tensquare_back.git"
// 镜像的版本号
def tag = "latest"
// Harbor的url地址
def harbor_url = "192.168.188.115:85"
// 镜像库项目名称
def harbor_project = "tensquare"
// Harbor的登录凭据ID
def harbor_auth = "c0e6642d-bab9-4978-be45-955e5130fae2"
node {
// 获取当前选择的项目名称
def selectedProjectNames = "${project_name}".split(",")
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
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工具环境 在全局工具配置里查看
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境 在系统配置里查看
withSonarQubeEnv('sonarqube') {
sh """
cd ${currentProjectName}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,安装公共子工程,上传镜像') {
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 ${currentProjectName} 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}"
sh "echo 镜像上传成功啦"
}
// 部署项目
// sshPublisher(publishers: [sshPublisherDesc(configName: 'tomcat_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deploy.sh $harbor_url $harbor_project $project_name $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
}
- 可以将代码审查的循环直接拿到构建镜像那里使用
- 修改项目名称为变量就行了
进行测试
成功了,说明循环遍历没问题
完成微服务多服务器远程部署
这时候,我们需要添加第二台远程tomcat服务器
进入jenkins系统配置,找到Publish over SSH,新增一台SSH Server
拷贝公钥到远程服务器
ssh-copy-id 192.168.188.114
点击测试连接,显示Success表示远程连接成功
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://zydiol88.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.188.115:85"]
}
systemctl restart docker
在流水线项目里添加多选参数
和之前一样,因此不在多做描述
保存之后,进行Jenkinsfile的编写
// git凭证ID
def git_auth = "41580d48-d4c3-4116-9a71-4d4d777c5753"
// git的url地址
def git_url = "git@192.168.188.110:maomao_group/tensquare_back.git"
// 镜像的版本号
def tag = "latest"
// Harbor的url地址
def harbor_url = "192.168.188.115:85"
// 镜像库项目名称
def harbor_project = "tensquare"
// Harbor的登录凭据ID
def harbor_auth = "c0e6642d-bab9-4978-be45-955e5130fae2"
node {
// 获取当前选择的项目名称
def selectedProjectNames = "${project_name}".split(",")
// 获取当前选择的服务器名称
def selectedServers = "${publish_server}".split(",")
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
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工具环境 在全局工具配置里查看
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境 在系统配置里查看
withSonarQubeEnv('sonarqube') {
sh """
cd ${currentProjectName}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,安装公共子工程,上传镜像') {
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 ${currentProjectName} 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}"
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=="tomcat_server") {
activeProfile = activeProfile+"eureka-server1"
}else if(currentServerName=="tompig_server"){
activeProfile = activeProfile+"eureka-server2"
}
// 部署项目
sshPublisher(publishers: [sshPublisherDesc(configName: "${currentServerName}", transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deployCluster.sh $harbor_url $harbor_project $currentProjectName $tag $currentProjectPort $activeProfile", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
echo "${currentProjectName}完成编译,构建镜像"
}
}
}
在之前deploy.sh的基础上再写一个deployCluster.sh脚本
#! /bin/bash
#接收外部参数
harbor_url=$1
harbor_project=$2
project_name=$3
tag=$4
port=$5
profile=$6
imageName=$harbor_url/$harbor_project/$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 maomao -p Xiaotian123 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName $profile
echo "容器启动成功"
- 只需要再增加一个变量profile 用来存储新增的位置变量activeProfile
- 在启动容器的时候选择不同的eruka配置
写完之后将脚本传到另一台服务器上
scp deployCluster.sh root@192.168.188.114:/opt/jenkins_shell/
chown +x deployCluster.sh
进行项目的部署,看看能否将两个eruka部署到两台服务器上
构建成功,分别在tomcat和tompig服务器上部署了eruka集群
打开浏览器查看集群,分别有两个实例
总结错误
- 引用变量必须使用" " 我有个变量外边加的’ ’ 导致错误
- 花括号一定是有开有关,如果少了关也会错
- jenkins里流水线配置的变量名和脚本里变量名一定要统一
我把流水线变量名改成publish_server了,结果脚本里没改,导致错误
将剩下三个微服务同时部署到两个服务器上
这里就简单了,因为前面已经将所有错都排除了
只需要构建除eruka之外的其他三个微服务
所有微服务都部署在两台服务器上了,形成了微服务集群
怎么在docker中部署jenkins
jenkins学习1-docker快速搭建jenkins环境
docker jenkins 构建 springboot 项目、vue 项目