08 . Jenkins之SpringCloud微服務+Vue+Docker持續整合

men發表於2020-10-04

簡介

大致流程
/*
		1.開發人員每天把程式碼提交到Gitlab程式碼倉庫
		2.jenkins從gitlab中拉取專案原始碼,編譯並打包成war包,然後構建Docker映象,將映象上傳到Harbor私有倉庫
		3.jenkins傳送ssh遠端命令,讓生產部署服務到Harbor私有倉庫拉取映象到本地,然後建立容器
		4.最後,使用者就可以訪問到容器
*/

SpringCloud微服務原始碼概述

/*
	專案架構: 前後端分離
	後端技術棧: SpringBoot+SpringCloud+SpringDatajpa(Spring全家桶)
*/



/*
	微服務專案結構
		tensquare_parent:   父工程,存放基礎配置
		tensquare_common:   通用工程
		tensquare_eureka_server:  SpringCloud的Eureka註冊中心
		tensquare_zull:  SpringCloud的閘道器服務
		tensquare:  基礎許可權認證中心,負責使用者認證(使用jwt認證)
		tenquare_guathering:  一個簡單的業務模組,活動微服務相關邏輯
*/


/*
	資料庫結構
		tensquare_user:  使用者認證資料庫,存放使用者賬號資料,對應tensquare_admin_service微服務
		tensquare_gathering:  活動微服務資料庫,對應tensquare_gathering微服務
*/


/*
	微服務配置分析
		tensquare_eureka
		tensquare_zuul
		tensquare_admin_service
		tensquare_gathering
*/

部署Docker

安裝必要系統工具和軟體源
# 安裝一些必要的系統工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 新增軟體源資訊
# docker 官方源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 阿里雲源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安裝並啟動Docker-ce
# 安裝前可以先更新 yum 快取:
sudo yum makecache fast

# CentOS7安裝 Docker-ce
yum -y install docker-ce        # CentOS 中安裝
apt-get install docker-ce       # Ubuntu 中安裝
pacman -S docker                # Arch 中安裝
emerge --ask docker             # Gentoo 中安裝

# 如果想安裝特定版本的Docker-ce版本,先列出repo中可用版本,然後選擇安裝
yum list docker-ce --showduplicates |sort -r
Loading mirror speeds from cached hostfile
Loaded plugins: fastestmirror
Installed Packages
docker-ce.x86_64            3:19.03.4-3.el7                    docker-ce-stable
docker-ce.x86_64            3:19.03.4-3.el7                    @docker-ce-stable
docker-ce.x86_64            3:19.03.3-3.el7                    docker-ce-stable
docker-ce.x86_64            3:19.03.2-3.el7                    docker-ce-stable
docker-ce.x86_64            3:19.03.1-3.el7                    docker-ce-stable

yum install docker-ce-<VERSION STRING>
# 選擇安裝 docker-ce-18.06.1.ce
yum install docker-ce-18.06.1.ce -y

# Docker映象加速
# 沒有啟動/etc/docker目錄不存在,需要自己建立,docker啟動也會自己建立
# 為了期望我們的映象下載快一點,應該定義一個映象加速器,加速器在國內
mkdir /etc/docker
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}

# 或者使用阿里雲的
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://yj9iu9ne.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

# 啟動Docker後臺服務
systemctl start docker && systemctl enable docker
systemctl daemon-reload                 # 守護程式重啟

# 通過執行hello-world映象,驗證是否正確安裝了docker,或者通過檢視版本
docker run hello-world
docker version
Client: Docker Engine - Community
Version:           19.03.4
API version:       1.40
Go version:        go1.12.10
Git commit:        9013bf583a
Built:            Fri Oct 18 15:52:22 2019
OS/Arch:           linux/amd64
Experimental:      false
docker使用

docker使用請看我前面寫的docker blog

https://www.cnblogs.com/you-men/category/1789332.html

使用dockerfile製作微服務映象

1.上傳Eureka的微服務jar包到linux

2.編寫Dockerfile

FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10086
ENTRYPOINT ["java","-jar","/app.jar"]

3.構建映象

docker build --build-arg JAR_FILE=tensquare_eureka_server-1.0-SNAPSHOT.jar -t eureka:v1 .

4.檢視映象是否建立成功

docker images

5.建立容器

docker run -i --name=eureka -p 10086:10086 eureka:v1

部署配置Harbor

安裝docker-compose
curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 對二進位制檔案應用可執行許可權:
sudo chmod +x /usr/local/bin/docker-compose
# 測試是否安裝成功
docker-compose --version
解壓安裝配置harbor
# 解壓
tar xf harbor-offline-installer-v1.9.2.tgz 
mkdir /opt/harbor
mv harbor/*  /opt/harbor
cd /opt/harbor

# 配置
vim harbor.yml
hostname: 192.168.1.8
port: 88
  
# 安裝
./install
啟動訪問harbor
# 啟動
docker-compose up -d 

# 停止
docker-compose stop 

# 重新啟動
docker-compose restart


# 訪問harbor
# IP:88
# 預設賬戶密碼: admin/Harbor12345

建立專案
# Harbor的專案分為公有和私有的:
# 公有專案:  所有使用者都可以訪問,通常你存放公共映象,預設有一個library公開專案
# 私有專案:  所有授權使用者才可以訪問,通常存放專案本身的映象

建立使用者

給專案分配使用者

角色 許可權說明
訪客 對於指定專案擁有隻讀許可權
開發人員 對於指定專案擁有讀寫許可權
維護人員 對於指定專案擁有讀寫許可權,建立Webhooks
專案管理員 除了讀寫許可權,同時擁有使用者管理/映象掃描管理許可權
以新使用者登入Harbor

映象上傳Harbor

1. 給映象打標籤

docker tag nginx:latest 192.168.1.8/tensquare/nginx:v1

2. 將Harbor地址加入到Docker信任列表

vim /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://yj9iu9ne.mirror.aliyuncs.com"],
  "insecure-registries": ["192.168.1.8:88"]
}

3. 登入harbor推送映象

 docker login -u wunai -p xxxxx 192.168.1.8:88
    
 docker push 192.168.1.8:88/tensquare/nginx:v1

從Harbor下載映象

1.修改docker配置

vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["192.168.1.8:88"]
}

2.先登入,再從Harbor下載映象

 docker login -u wunai -p xxxxx 192.168.1.8:88
 docker pull 192.168.1.8:88/tensquare/nginx:v1

從GitHub拉取程式碼

建立GitLab後端專案

建立前端專案

上傳程式碼就不演示了

配置Jenkins後端拉取專案

jenkinsfile2

//git憑證ID
def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
//git的url地址
def git_url = "git@192.168.1.4:youmen/tensquare_back.git"


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

提交到SonarQube程式碼審查

jenkinsfile2

//git憑證ID
def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
//git的url地址
def git_url = "git@192.168.1.4:youmen/tensquare_back.git"


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

   stage('程式碼審查') {
        //定義當前Jenkins的SonarQubeScanner工具
        def scannerHome = tool 'sonar-scanner'
        //引用當前JenkinsSonarQube環境
        withSonarQubeEnv('sonarqube') {
            sh """
                cd ${project_name}
         	    ${scannerHome}/bin/sonar-scanner
            """
        }
   	}
}

編譯打包微服務工程

//git憑證ID
def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
//git的url地址
def git_url = "git@192.168.1.4:youmen/tensquare_back.git"


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

   stage('程式碼審查') {
        //定義當前Jenkins的SonarQubeScanner工具
        def scannerHome = tool 'sonar-scanner'
        //引用當前JenkinsSonarQube環境
        withSonarQubeEnv('sonarqube') {
            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生成映象

在每個微服務專案pom.xml加入dockerfile-maven-plugin外掛
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </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>
        </plugins>
    </build>
每個微服務專案根目錄建立dockerfile檔案
#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10086
ENTRYPOINT ["java","-jar","/app.jar"]
配置jenkinsfile
//git憑證ID
def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
//git的url地址
def git_url = "git@192.168.1.4:youmen/tensquare_back.git"


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

   stage('程式碼審查') {
        //定義當前Jenkins的SonarQubeScanner工具
        def scannerHome = tool 'sonar-scanner'
        //引用當前JenkinsSonarQube環境
        withSonarQubeEnv('sonarqube') {
            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"
   	}
}

上傳Harbor映象倉庫並拉取釋出應用

建立harbor憑證

# 建立完成後再點進去將裡面ID複製出來,然後放到Jenkinsfile裡面
1d961bbc-82a1-41a2-b146-52bcaffe44f7

將harbor使用者名稱和密碼通過憑證和pipline轉換達到隱藏使用者名稱和密碼的功能

上傳Harbor映象
//git憑證ID
def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"

//git的url地址
def git_url = "git@192.168.1.4:youmen/tensquare_back.git"

// 映象版本號
def tag = "latest"

// Harbor的url地址
def harbor_url="192.168.1.8:88"

// 映象庫專案名稱
def harbor_project = "tensquare"

// Harbor的登陸憑證
def harbor_auth = "1d961bbc-82a1-41a2-b146-52bcaffe44f7"

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

   stage('程式碼審查') {
        //定義當前Jenkins的SonarQubeScanner工具
        def scannerHome = tool 'sonar-scanner'
        //引用當前JenkinsSonarQube環境
        withSonarQubeEnv('sonarqube') {
            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 映象上傳成功"
        }
   	}
}

拉取映象和釋出應用

安裝Publish Over SSH外掛

做jenkins與生產部署伺服器免密
# [root@jenkins-2 ~]# ssh-copy-id 192.168.1.6

配置微服務啟動埠

配置jenkinsfile
//git憑證ID
def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"

//git的url地址
def git_url = "git@192.168.1.4:youmen/tensquare_back.git"

// 映象版本號
def tag = "latest"

// Harbor的url地址
def harbor_url="192.168.1.8:88"

// 映象庫專案名稱
def harbor_project = "tensquare"

// Harbor的登陸憑證
def harbor_auth = "1d961bbc-82a1-41a2-b146-52bcaffe44f7"

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

   stage('程式碼審查') {
        //定義當前Jenkins的SonarQubeScanner工具
        def scannerHome = tool 'sonar-scanner'
        //引用當前JenkinsSonarQube環境
        withSonarQubeEnv('sonarqube') {
            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 映象上傳成功"
        }

        // 部署應用
       	sshPublisher(publishers: [sshPublisherDesc(configName: 'master_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)])
   	}
}
配置部署指令碼
[root@tomcat-6 ~]# cat /opt/jenkins_shell/deploy.sh 
#! /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 eric -p Eric123456 $harbor_url

# 下載映象
docker pull $imageName

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

echo "容器啟動成功"


# 記得加+x許可權

訪問檢視

部署測試所有微服務

# src/main/resourcesapplication.yml 修改資料庫地址

[root@tomcat-6 ~]# docker ps
CONTAINER ID        IMAGE                                                     COMMAND                CREATED             STATUS              PORTS                               NAMES
120baa66789c        192.168.1.8:88/tensquare/tensquare_gathering:latest       "java -jar /app.jar"   3 minutes ago       Up 3 minutes        0.0.0.0:9002->9002/tcp              friendly_jones
29bb1c3156c3        192.168.1.8:88/tensquare/tensquare_zuul:latest            "java -jar /app.jar"   8 minutes ago       Up 8 minutes        0.0.0.0:10020->10020/tcp            xenodochial_knuth
76113fb1c859        192.168.1.8:88/tensquare/tensquare_eureka_server:latest   "java -jar /app.jar"   13 minutes ago      Up 13 minutes       0.0.0.0:8080->8080/tcp, 10086/tcp   peaceful_euler
7a84a0f6e3eb        192.168.1.8:88/tensquare/tensquare_admin_service:latest   "java -jar /app.jar"   20 minutes ago      Up 20 minutes       0.0.0.0:9001->9001/tcp              sad_beaver

部署前端靜態網站

安裝配置nginx
yum -y install nginx
systemctl start nginx && systemctl enable nginx
# 檢視nginx軟體版本
nginx -v

# 修改nginx埠

    server {
        listen       9090 default_server;
        listen       [::]:9090 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

# 重啟服務使配置生效        
systemctl restart nginx 

# 驗證服務狀態
[root@tomcat-6 ~]# curl -I localhost:9090
HTTP/1.1 200 OK
Server: nginx/1.16.1
安裝NodeJS外掛

配置全域性工具Nodejs

Jenkins配置Nginx伺服器

注意修改前端程式碼的裡面地址為閘道器地址

'use strict'
module.exports = {
  NODE_ENV: '"production"',
  // BASE_API: '"http://192.168.207.131:7300/mock/5c0b42c85b4c7508d4dc568c/1024"'
  BASE_API: '"http://192.168.1.6:10020"' // 管理員閘道器
}

// gitlab憑證
def git_auth = "181829c8-c8cd-4e85-aa93-89ad280a5e69"

def git_url = "git@192.168.1.4:youmen/tensquare_front.git"



node {
   stage('拉取程式碼') {
        checkout([$class: 'GitSCM', branch
es: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
   }


	stage('打包,部署網站') {
	// 使用NodeJS的npm進行打包
		sh '''
			npm install 
			nmp run build
		'''
	}

	// 專案部署
   	sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/usr/share/nginx/html', remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/**')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}

相關文章