Jenkins Docker SpringCloud微服务持续集成(下)
- Jenkins Docker SpringCloud部署方案优化
- Jenkins Docker SpringCloud集群部署流程说明
- 修改所有微服务配置
- 修改注册中心的配置
- 其他微服务配置
- 修改所有微服务配置
- 设计Jenkins集群项目的构建参数
- Jenkins安装Extended Choice Parameter插件
- 创建流水线项目
- 添加参数
- 最后效果
- 把多个项目提交SonarQube进行代码审核
- 多个项目打包及构建镜像、上传私服
- 完成微服务多服务器远程发布
- 在Jenkins项目中增加一个Extended Choice Parameter参数
- 在192.168.18.103和192.168.18.104服务器中创建deployCluster.sh
- 修改Jenkinsfile文件
Jenkins Docker SpringCloud部署方案优化
● 前面部署方案存在的问题:
○ 一次只能选择一个微服务部署。
○ 只有一条生产部署服务器。
○ 每个微服务只有一个实例,容错率低。
● 优化方案:
○ 在一个Jenkins工程中可以选择多个微服务同时发布。
○ 在一个Jenkins工程中可以选择多台生产服务器同时部署。
○ 每个微服务都是以集群高可用的形式部署。
Jenkins Docker SpringCloud集群部署流程说明
修改所有微服务配置
修改注册中心的配置
- application.yaml
# 集群版
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.18.103
client:
service-url:
defaultZone: http://192.168.18.103:10086/eureka,http://192.168.18.104:10086/eureka
---
server:
port: 10086
spring:
profiles: eureka-server2
eureka:
instance:
hostname: 192.168.18.104
client:
service-url:
defaultZone: http://192.168.18.103:10086/eureka,http://192.168.18.104:10086/eureka
- 在启动微服务的时候,加入参数spring.profile.active来读取对应的配置。
其他微服务配置
除了Eureka注册中心以外,其他微服务的配置都需要加入所有Eureka的服务。
商品微服务的配置:
代码语言:javascript复制server:
port: 9001 # 微服务的端口号
spring:
application:
name: service-product # 微服务的名称
# 配置 eureka
eureka:
client:
service-url: # Eureka Server的地址
defaultZone: http://192.168.18.103:10086/eureka,http://192.168.18.104:10086/eureka
instance:
instance-id: service-product
prefer-ip-address: true
订单微服务的配置:
代码语言:javascript复制server:
port: 9002 # 微服务的端口号
spring:
application:
name: service-order # 微服务的名称
# 配置 eureka
eureka:
client:
service-url: # Eureka Server的地址
defaultZone: http://192.168.18.103:10086/eureka,http://192.168.18.104:10086/eureka
instance:
instance-id: service-order
prefer-ip-address: true
设计Jenkins集群项目的构建参数
Jenkins安装Extended Choice Parameter插件
创建流水线项目
添加参数
最后效果
把多个项目提交SonarQube进行代码审核
- 修改Jenkinsfile文件,内容如下:
//定义git凭证ID
def git_auth = "7d5c4945-2533-41e2-bd47-5dd97eb37f38"
//git的url地址
def git_url = "git@192.168.18.100:develop_group/jenkinscloud.git"
//定义tag
def tag = "1.0"
// 定义Harbor的URL地址
def harbor_url = "192.168.18.102:85"
// 镜像库项目名称
def harbor_project = "xudaxian-mall"
// Harbor的登录凭证id
def harbor_auth = "b6cf3cb5-8a33-457d-93da-65c46f0135b2"
node {
// == 修改部分 获取当前选择的项目名称 ==
def selectedProjectNames = "${project_name}".split(",")
// == 修改部分
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
// == 修改部分
for(int i = 0 ; i< selectedProjectNames.length ; i ) {
//jenkinscloud-eureka@10086
def projectInfo = selectedProjectNames[i];
//当前的项目名称 jenkinscloud-eureka
def currentProjectName = "${projectInfo}".split("@")[0]
//当前的项目端口 10086
def currentProjectPort = "${projectInfo}".split("@")[1]
//定义当前Jenkins的SonarQubeScanner工具的环境
def scannerHome = tool 'sonarqube-scanner'
//引用当前Jenkins的SonarQube环境
withSonarQubeEnv('sonarqube-8.6.0') {
sh """
cd ${currentProjectName}
${scannerHome}/bin/sonar-scanner
"""
}
}
// == 修改部分
}
//如果有公共子工程
// stage('编译,安装公共的子工程') {
// sh "mvn -f jenkinscloud-common clean install"
// }
stage('编译,打包微服务工程') {
// dockerfile:build 可以触发插件的执行
sh "mvn -f ${project_name} clean install dockerfile:build "
}
stage('上传镜像') {
//定义镜像的名称
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 '镜像上传到Harbor仓库中成功'"
}
//删除本地镜像
sh "docker rmi -f ${imageName}"
sh "docker rmi -f ${harbor_url}/${harbor_project}/${imageName}"
}
// 定义远程执行命令
def execCommand = "/usr/local/deploy.sh $harbor_url $harbor_project $project_name $tag $port"
stage('拉取镜像和发布应用') {
// 远程部署调用进行项目部署
sshPublisher(publishers: [sshPublisherDesc(configName: '192.168.18.103', 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)])
}
}
多个项目打包及构建镜像、上传私服
- 修改Jenkinsfile文件,内容如下:
//定义git凭证ID
def git_auth = "7d5c4945-2533-41e2-bd47-5dd97eb37f38"
//git的url地址
def git_url = "git@192.168.18.100:develop_group/jenkinscloud.git"
//定义tag
def tag = "1.0"
// 定义Harbor的URL地址
def harbor_url = "192.168.18.102:85"
// 镜像库项目名称
def harbor_project = "xudaxian-mall"
// Harbor的登录凭证id
def harbor_auth = "b6cf3cb5-8a33-457d-93da-65c46f0135b2"
node {
// == 获取当前选择的项目名称 ==
def selectedProjectNames = "${project_name}".split(",")
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
for(int i = 0 ; i< selectedProjectNames.length ; i ) {
//jenkinscloud-eureka@10086
def projectInfo = selectedProjectNames[i];
//当前的项目名称 jenkinscloud-eureka
def currentProjectName = "${projectInfo}".split("@")[0]
//当前的项目端口 10086
def currentProjectPort = "${projectInfo}".split("@")[1]
//定义当前Jenkins的SonarQubeScanner工具的环境
def scannerHome = tool 'sonarqube-scanner'
//引用当前Jenkins的SonarQube环境
withSonarQubeEnv('sonarqube-8.6.0') {
sh """
cd ${currentProjectName}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
//如果有公共子工程
// stage('编译,安装公共的子工程') {
// sh "mvn -f jenkinscloud-common clean install"
// }
stage('编译,打包微服务工程') {
// == 修改部分 ==
for(int i = 0 ; i< selectedProjectNames.length ; i ) {
//jenkinscloud-eureka@10086
def projectInfo = selectedProjectNames[i];
//当前的项目名称 jenkinscloud-eureka
def currentProjectName = "${projectInfo}".split("@")[0]
//当前的项目端口 10086
def currentProjectPort = "${projectInfo}".split("@")[1]
// dockerfile:build 可以触发插件的执行
sh "mvn -f ${currentProjectName} clean install dockerfile:build "
}
// == 修改部分 ==
}
stage('上传镜像') {
// == 修改部分 ==
for(int i = 0 ; i< selectedProjectNames.length ; i ) {
//jenkinscloud-eureka@10086
def projectInfo = selectedProjectNames[i];
//当前的项目名称 jenkinscloud-eureka
def currentProjectName = "${projectInfo}".split("@")[0]
//当前的项目端口 10086
def currentProjectPort = "${projectInfo}".split("@")[1]
//定义镜像的名称
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 '镜像上传到Harbor仓库中成功'"
}
//删除本地镜像
sh "docker rmi -f ${imageName}"
sh "docker rmi -f ${harbor_url}/${harbor_project}/${imageName}"
}
// == 修改部分 ==
}
// 定义远程执行命令
def execCommand = "/usr/local/deploy.sh $harbor_url $harbor_project $project_name $tag $port"
stage('拉取镜像和发布应用') {
// 远程部署调用进行项目部署
// sshPublisher(publishers: [sshPublisherDesc(configName: '192.168.18.103', 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)])
}
}
完成微服务多服务器远程发布
● 远程部署服务器(192.168.18.103和192.168.18.104)已安装Docker,并信任Harbor私有仓库。
● 关闭了防火墙。
● 在Publish over SSH那边增加一台远程部署服务器。
在Jenkins项目中增加一个Extended Choice Parameter参数
- 在Jenkins项目中增加一个Extended Choice Parameter参数的目的是可以选择部署到那个服务器,选择Check
在192.168.18.103和192.168.18.104服务器中创建deployCluster.sh
在远程部署服务器的/usr/local目录下,创建deployCluster.sh文件:
代码语言:javascript复制cd /usr/local
代码语言:javascript复制vim deployCluster.sh
代码语言:javascript复制#! /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 xudaxian -p Xudaxian12345678 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName $profile
echo "容器启动成功"
设置权限:
代码语言:javascript复制chmod x deployCluster.sh
修改Jenkinsfile文件
代码语言:javascript复制//定义git凭证ID
def git_auth = "7d5c4945-2533-41e2-bd47-5dd97eb37f38"
//git的url地址
def git_url = "git@192.168.18.100:develop_group/jenkinscloud.git"
//定义tag
def tag = "1.0"
// 定义Harbor的URL地址
def harbor_url = "192.168.18.102:85"
// 镜像库项目名称
def harbor_project = "xudaxian-mall"
// Harbor的登录凭证id
def harbor_auth = "b6cf3cb5-8a33-457d-93da-65c46f0135b2"
node {
// == 获取当前选择的项目名称 ==
def selectedProjectNames = "${project_name}".split(",")
// 获取当前选择的服务器名称
def selectedServers = "${publish_server}".split(",")
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
for(int i = 0 ; i< selectedProjectNames.length ; i ) {
//jenkinscloud-eureka@10086
def projectInfo = selectedProjectNames[i];
//当前的项目名称 jenkinscloud-eureka
def currentProjectName = "${projectInfo}".split("@")[0]
//当前的项目端口 10086
def currentProjectPort = "${projectInfo}".split("@")[1]
//定义当前Jenkins的SonarQubeScanner工具的环境
def scannerHome = tool 'sonarqube-scanner'
//引用当前Jenkins的SonarQube环境
withSonarQubeEnv('sonarqube-8.6.0') {
sh """
cd ${currentProjectName}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
//如果有公共子工程
// stage('编译,安装公共的子工程') {
// sh "mvn -f jenkinscloud-common clean install"
// }
stage('编译,打包微服务工程') {
for(int i = 0 ; i< selectedProjectNames.length ; i ) {
//jenkinscloud-eureka@10086
def projectInfo = selectedProjectNames[i];
//当前的项目名称 jenkinscloud-eureka
def currentProjectName = "${projectInfo}".split("@")[0]
//当前的项目端口 10086
def currentProjectPort = "${projectInfo}".split("@")[1]
// dockerfile:build 可以触发插件的执行
sh "mvn -f ${currentProjectName} clean install dockerfile:build "
}
}
stage('上传镜像') {
for(int i = 0 ; i< selectedProjectNames.length ; i ) {
//jenkinscloud-eureka@10086
def projectInfo = selectedProjectNames[i];
//当前的项目名称 jenkinscloud-eureka
def currentProjectName = "${projectInfo}".split("@")[0]
//当前的项目端口 10086
def currentProjectPort = "${projectInfo}".split("@")[1]
//定义镜像的名称
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 '镜像上传到Harbor仓库中成功'"
}
//删除本地镜像
sh "docker rmi -f ${imageName}"
sh "docker rmi -f ${harbor_url}/${harbor_project}/${imageName}"
}
}
stage('拉取镜像和发布应用') {
for(int i = 0 ; i< selectedProjectNames.length ; i ) {
//jenkinscloud-eureka@10086
def projectInfo = selectedProjectNames[i];
//当前的项目名称 jenkinscloud-eureka
def currentProjectName = "${projectInfo}".split("@")[0]
//当前的项目端口 10086
def currentProjectPort = "${projectInfo}".split("@")[1]
for(int j =0;j<selectedServers.length;j ){
//获取当前遍历的服务器名称
def currentServerName = selectedServers[j]
//加上参数格式: --spring.profiles.active=eureka-server1/eureka-server2
def activeProfiles = "--spring.profiles.active="
if(currentServerName =="192.168.18.103"){
activeProfiles = activeProfiles "eureka-server1"
}else if(currentServerName == "192.168.18.104"){
activeProfiles = activeProfiles "eureka-server2"
}
// 定义远程执行命令
def execCommand = "/usr/local/deployCluster.sh $harbor_url $harbor_project $currentProjectName $tag $currentProjectPort $activeProfiles"
// 远程部署调用进行项目部署
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)])
}
}
}
}