Jenkins+Docker+SpringCloud微服務持續集成(集群版)


Jenkins+Docker+SpringCloud微服務持續集成(集群版)

作者:運維人在路上

個人博客https://www.cnblogs.com/hujinzhong

微信公眾號:運維人在路上

Bilibili賬號https://space.bilibili.com/409609392

個人簡介:本人是一枚大型電商平台的運維工程師,對開發及運維有一定了解,現分享技術干貨,歡迎大家交流!

一、單機版存在的問題及優化

1.1、存在的問題

單機版部署文章:https://www.cnblogs.com/hujinzhong/p/14571041.html

image-20210324094618391

上訴部署方案存在的問題:

  • 1)一次只能選擇一個微服務部署,還要手動修改端口,比較麻煩
  • 2)只有一台生產部署服務器
  • 3)每個微服務只有一個實例,容錯率低

1.2、優化

1)在一個Jenkins工程中可以選擇多個微服務同時發布

2)在一個Jenkins工程中可以選擇多台生產服務器同時部署

3)每個微服務都是以集群高可用形式部署

二、集群高可用部署

2.1、部署流程說明

2.2、詳細部署步驟

2.2.1、修改所有微服務配置

1)注冊中心配置修改

# 集群版
spring:
  application:
    name: EUREKA-HA

---
server:
  port: 10086
spring:
  # 指定profile=eureka-server1
  profiles: eureka-server1
eureka:
  instance:
    # 指定當profile=eureka-server1時,主機名是eureka-server1
    hostname: 10.0.0.103
  client:
    service-url:
      # 將自己注冊到eureka-server1、eureka-server2這個Eureka上面去
      defaultZone: http://10.0.0.103:10086/eureka/,http://10.0.0.104:10086/eureka/

---
server:
  port: 10086
spring:
  profiles: eureka-server2
eureka:
  instance:
    hostname: 10.0.0.104
  client:
    service-url:
      defaultZone: http://10.0.0.103:10086/eureka/,http://10.0.0.104:10086/eureka/

注意:在啟動微服務的時候,加入參數spring.profiles.active來讀取對應的配置

2)其他微服務配置

除了Eureka注冊中心以外,其他微服務配置都需要加入所有Eureka服務

server:
  port: 9001
spring:
  application:
    name: tensquare-admin-service #指定服務名
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://10.0.0.102:3306/tensquare_user?characterEncoding=UTF8
    username: root
    password: Root@123
  jpa:
    database: mysql
    show-sql: true

#Eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://10.0.0.103:10086/eureka,http://10.0.0.104:10086/eureka
  instance:
    lease-renewal-interval-in-seconds: 5 # 每隔5秒發送一次心跳
    lease-expiration-duration-in-seconds: 10 # 10秒不發送就過期
    prefer-ip-address: true


 # jwt參數
jwt:
  config:
    key: itcast
    ttl: 1800000

2.2.2、設計Jenkins集群項目的構建參數

1)安裝Extended Choice Parameter插件,支持多選框

image-20210324101513335

2)創建流水線項目

image-20210324101733770

3)配置流水線,添加參數

image-20210324101858301

添加字符串參數:分支名稱

image-20210324102009404

添加多選框參數:項目名稱

image-20210324102423225

image-20210324104010424

最后效果:

image-20210324104038559

2.2.3、微服務構建鏡像上傳Harbor

修改Jenkinsfile

//gitlab的憑證
def git_auth = "cf17ff40-5824-4b2d-bdd5-784560255001"
//gitlab倉庫地址
def git_url = "git@10.0.0.101:dianchou_group/tensqure_back.git"
//鏡像的版本號
def tag = "latest"
//Harbor的url地址
def harbor_url = "10.0.0.101:85"
//鏡像庫項目名稱
def harbor_project = "dianchou"
//Harbor的登錄憑證ID
def harbor_auth = "86beb97d-7de6-4dc2-ab10-bc199d9eda97"

node {
    //獲取當前選擇的項目名稱
    def selectedProjectNames = "${project_name}".split(",")

    stage('拉取代碼') {
        checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
    }

    stage('代碼審查') {
         sh "echo ${selectedProjectNames}"
        //定義當前Jenkins的SonarQubeScanner工具
        def scannerHome = tool 'sonarqube-scanner'
        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]

            //引用當前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')]) {
                //登錄
                sh "docker login -u ${username} -p ${password} ${harbor_url}"
                //上傳鏡像
                sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
                sh "echo 上傳鏡像成功"
            }
            //刪除本地鏡像
            sh "docker rmi -f ${imageName}"
            sh "docker rmi -f ${harbor_url}/${harbor_project}/${imageName}"
       }
    }

    stage('部署應用') {

    }
}

2.2.4、遠程部署多服務器

1)jenkins配置遠程服務器

拷貝公鑰到遠程服務器

[root@jenkins ~]# ssh-copy-id 10.0.0.103
[root@jenkins ~]# ssh-copy-id 10.0.0.104

系統配置->添加遠程服務器

image-20210324172829964

2)安裝docker並配置

[root@hadoop104 ~]# cat /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://t09ww3n9.mirror.aliyuncs.com"],
  "insecure-registries": ["10.0.0.101:85"]
}

3)添加參數

添加多選框:部署服務器

image-20210324173306948

image-20210324173331632

最終效果:

image-20210324173418743

4)修改Jenkinfile

//gitlab的憑證
def git_auth = "cf17ff40-5824-4b2d-bdd5-784560255001"
//gitlab倉庫地址
def git_url = "git@10.0.0.101:dianchou_group/tensqure_back.git"
//鏡像的版本號
def tag = "latest"
//Harbor的url地址
def harbor_url = "10.0.0.101:85"
//鏡像庫項目名稱
def harbor_project = "dianchou"
//Harbor的登錄憑證ID
def harbor_auth = "86beb97d-7de6-4dc2-ab10-bc199d9eda97"

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('代碼審查') {
         sh "echo ${selectedProjectNames}"
        //定義當前Jenkins的SonarQubeScanner工具
        def scannerHome = tool 'sonarqube-scanner'
        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]

            //引用當前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')]) {
                //登錄
                sh "docker login -u ${username} -p ${password} ${harbor_url}"
                //上傳鏡像
                sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
                sh "echo 上傳鏡像成功"
            }
            //刪除本地鏡像
            sh "docker rmi -f ${imageName}"
            sh "docker rmi -f ${harbor_url}/${harbor_project}/${imageName}"

            //遍歷所有服務器,分別部署
            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"
                   }

                   //部署應用
                   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 "部署成功"
            }
       }
    }

}

5)編寫deployCluster.sh部署腳本

[root@hadoop104 jenkins_shell]# pwd
/opt/jenkins_shell
[root@hadoop104 jenkins_shell]# cat deployCluster.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 dianchou -p Dianchou123 $harbor_url
# 下載鏡像
docker pull $imageName

# 啟動容器
docker run -di -p $port:$port $imageName $profile

echo "容器啟動成功"

6)最終結果

image-20210324175909697

2.2.5、Nginx+Zuul集群實現高可用網關

image-20210326154920821

1)安裝nginx並配置

[root@tomcat ~]# cat /etc/nginx/conf.d/tensquare_font.conf 
upstream zuulServer {
    server 10.0.0.103:10020 weight=1;
    server 10.0.0.104:10020 weight=1;
}
server {
    listen       85;
    server_name  _;
    root   /usr/share/nginx/html;

    location / {
	proxy_pass http://zuulServer/;
    }

}

[root@tomcat ~]# nginx -t
[root@tomcat ~]# nginx -s reload

2)修改前端代碼訪問后台的訪問地址,設置為nginx的負載均衡地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM