大致流程說明:
1)開發人員每天把代碼提交到Gitlab代碼倉庫
2)Jenkins從Gitlab中拉取項目源碼,編譯並打成jar包,然后構建成Docker鏡像,將鏡像上傳到Harbor私有倉庫。
3)Jenkins發送SSH遠程命令,讓生產部署服務器到Harbor私有倉庫拉取鏡像到本地,然后創建容器。
4)最后,用戶可以訪問到容器
服務列表
名稱 | IP地址 | 安裝軟件 |
---|---|---|
持續基礎服務器 | 192.168.5.3 | jenkins,JDK,Maven,Git,SonarQube,Docker,MySQL |
代碼托管服務器 | 192.168.5.4 | gitlab-ce |
Docker倉庫服務器 | 192.168.5.5 | Docker,Harbor |
生產部署服務器 | 192.168.5.6 | Docker |
4.2 SpringCloud微服務源碼概述
# 測試代碼下載地址
wget https://cunqi0105-1300757323.cos.ap-shanghai.myqcloud.com/configuration-file/tensquareAdmin.zip
wget https://cunqi0105-1300757323.cos.ap-shanghai.myqcloud.com/configuration-file/tensquare_parent.zip
# 數據庫文件下載
wget https://cunqi0105-1300757323.cos.ap-shanghai.myqcloud.com/configuration-file/mysql-sql.zip
項目架構:前后端分離
后端技術棧:SpringBoot+SpringCloud+SpringDataJpa(Spring全家桶)
微服務項目結構:
-
tensquare_parent:父工程,存放基礎配置
-
tensquare_common:通用工程,存放工具類
-
tensquare_eureka_server:SpringCloud的Eureka注冊中心
-
tensquare_zuul:SpringCloud的網關服務
-
tensquare_admin_service:基礎權限認證中心,負責用戶認證(使用JWT認證)
-
tensquare_gathering:一個簡單的業務模塊,活動微服務相關邏輯
數據庫結構:
-
tensquare_user:用戶認證數據庫,存放用戶賬戶數據。對應tensquare_admin_service微服務
-
tensquare_gathering:活動微服務數據庫。對應tensquare_gathering微服務
微服務配置分析:
-
tensquare_eureka
-
tensquare_zuul
-
tensquare_admin_service
-
tensquare_gathering
4.3 環境准備(1)-Docker安裝
詳細請參考文檔:
4.5 環境准備(2)-Harbor鏡像倉庫安裝及使用
詳細請參考文檔:
4.6 微服務持續集成(1)-項目代碼上傳到Gitlab
在IDEA操作即可,參考之前的步驟。包括后台微服務和前端web網站代碼
4.7 微服務持續集成(2)-從Gitlab拉取項目源碼
1)Jenkins上創建 tenquare_back任務
2) 創建參數化構建函數
3)生成流水線腳本
4)創建Jenkinsfile文件
//gitlab的憑證
def git_auth = "14ae86e8-c3b4-4d7d-afe1-8c23d9fed317"
//gitlab的地址
def git_url = "git@192.168.5.4:root/tensquare_bak.git"
node {
stage('拉取代碼') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
}
5)上傳代碼
6)項目測試
4.8 微服務持續集成(3)-提交到SonarQube代碼審查
1) 創建參數化構建函數
2)在每個微服務項目的根目錄下添加sonar-project.properties
# must be unique in a given SonarQube instance
sonar.projectKey=項目名稱
# this is the name and version displayed in the SonarQube UI. Was mandatory
prior to SonarQube 6.1.
sonar.projectName=項目名稱
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
3)修改Jenkinsfile構建腳本
//gitlab的憑證
def git_auth = "14ae86e8-c3b4-4d7d-afe1-8c23d9fed317"
//gitlab的地址
def git_url = "git@192.168.5.4:root/tensquare_bak.git"
// 構建版本的名稱
def tag = "latest"
node {
stage('拉取代碼') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代碼審查') {
//定義當前Jenkins的SonarQubeScanner工具
def scannerHome = tool 'sonarqube-scanner'
//引用當前Jenkins SonarQube環境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
4)項目測試
4.9 微服務持續集成(4)-使用Dockerfile編譯、生成鏡像
利用dockerfile-maven-plugin插件構建Docker鏡像 1)在每個微服務項目的pom.xml加入dockerfile-maven-plugin插件(依賴父工程tensquare_common,不需要添加)
<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>
2)在每個微服務項目根目錄下建立Dockerfile文件(依賴父工程tensquare_common,不需要添加)
#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10086
ENTRYPOINT ["java","-jar","/app.jar"]
注意:每個項目公開的端口不一樣
3)修改Jenkinsfile構建腳本
//gitlab的憑證
def git_auth = "14ae86e8-c3b4-4d7d-afe1-8c23d9fed317"
//gitlab的地址
def git_url = "git@192.168.5.4:root/tensquare_bak.git"
// 構建版本的名稱
def tag = "latest"
node {
stage('拉取代碼') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代碼審查') {
//定義當前Jenkins的SonarQubeScanner工具
def scannerHome = tool 'sonarqube-scanner'
//引用當前Jenkins SonarQube環境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('編譯,構建鏡像') {
//定義鏡像名稱
def imageName = "${project_name}:${tag}"
//編譯,安裝公共工程
sh "mvn -f tensquare_common clean install"
//編譯,構建本地鏡像
sh "mvn -f ${project_name} clean package dockerfile:build"
}
}
4)項目測試
5)編譯失敗
出現這種問題,是因為微服務具有相關的依賴,需要將tensquare_parent
項目手動上傳到maven本地倉庫中
4.10 微服務持續集成(5)-上傳到Harbor鏡像倉庫
1)使用憑證管理Harbor私服賬戶和密碼
2)生成憑證腳本代碼
3)修改Jenkinsfile構建腳本
//gitlab的憑證
def git_auth = "14ae86e8-c3b4-4d7d-afe1-8c23d9fed317"
//gitlab的地址
def git_url = "git@192.168.5.4:root/tensquare_bak.git"
// 構建版本的名稱
def tag = "latest"
//Harbor私服地址
def harbor_url = "192.168.5.5:8080"
//Harbor的項目名稱
def harbor_project_name = "tensquare"
//Harbor的憑證
def harbor_auth = "cd0b948d-e82b-4c0c-8a7c-8c6b8fb5454b"
node {
stage('拉取代碼') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代碼審查') {
//定義當前Jenkins的SonarQubeScanner工具
def scannerHome = tool 'sonarqube-scanner'
//引用當前Jenkins SonarQube環境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('編譯,構建鏡像') {
//定義鏡像名稱
def imageName = "${project_name}:${tag}"
//編譯,安裝公共工程
sh "mvn -f tensquare_common clean install"
//編譯,構建本地鏡像
sh "mvn -f ${project_name} clean package dockerfile:build"
//給鏡像打標簽
sh "docker tag ${imageName} ${harbor_url}/${harbor_project_name}/${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_name}/${imageName}"
}
//刪除本地鏡像
sh "docker rmi -f ${imageName}"
sh "docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}"
}
}
3)項目測試
4.11 微服務持續集成(6)-拉取鏡像和發布應用
1)安裝 Publish Over SSH 插件
Publish Over SSH
2)拷貝jenkins公鑰到生產服務器
ssh-copy-id 192.168.5.6
3)添加遠程服務器
4)添加一個port參數
5)生成遠程調用模板代碼
6)修改Jenkinsfile構建腳本
//gitlab的憑證
def git_auth = "14ae86e8-c3b4-4d7d-afe1-8c23d9fed317"
//gitlab的地址
def git_url = "git@192.168.5.4:root/tensquare_bak.git"
// 構建版本的名稱
def tag = "latest"
//Harbor私服地址
def harbor_url = "192.168.5.5:8080"
//Harbor的項目名稱
def harbor_project_name = "tensquare"
//Harbor的憑證
def harbor_auth = "cd0b948d-e82b-4c0c-8a7c-8c6b8fb5454b"
node {
stage('拉取代碼') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代碼審查') {
//定義當前Jenkins的SonarQubeScanner工具
def scannerHome = tool 'sonarqube-scanner'
//引用當前Jenkins SonarQube環境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('編譯,構建鏡像') {
//定義鏡像名稱
def imageName = "${project_name}:${tag}"
//編譯,安裝公共工程
sh "mvn -f tensquare_common clean install"
//編譯,構建本地鏡像
sh "mvn -f ${project_name} clean package dockerfile:build"
//給鏡像打標簽
sh "docker tag ${imageName} ${harbor_url}/${harbor_project_name}/${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_name}/${imageName}"
}
//刪除本地鏡像
sh "docker rmi -f ${imageName}"
sh "docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}"
//=====以下為遠程調用進行項目部署========
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deploy.sh $harbor_url $harbor_project_name $project_name $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
7)編寫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 admin -p Harbor12345 $harbor_url
# 下載鏡像
docker pull $imageName
# 啟動容器
docker run -di -p $port:$port $imageName
echo "容器啟動成功"
chmod +x /opt/jenkins_shell/deploy.sh
8)項目測試
4.12 微服務持續集成(7)-部署前端靜態web網站
1)安裝NodeJS插件
NodeJS
2)配置NodeJS環境
3)添加branch,project_name,port參數
4)編寫dockerfile腳本
FROM nginx
COPY ./dist /usr/share/nginx/html
EXPOSE 80
5)編寫Jenkinsfile構建腳本
//gitlab的憑證
def git_auth = "14ae86e8-c3b4-4d7d-afe1-8c23d9fed317"
//gitlab的地址
def git_url = "git@192.168.5.4:root/tensquare_front.git"
// 構建版本的名稱
def tag = "latest"
//Harbor私服地址
def harbor_url = "192.168.5.5:8080"
//Harbor的項目名稱
def harbor_project_name = "tensquare"
//Harbor的憑證
def harbor_auth = "cd0b948d-e82b-4c0c-8a7c-8c6b8fb5454b"
node {
stage('拉取代碼') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('編譯,構建鏡像') {
//定義鏡像名稱
def imageName = "${project_name}:${tag}"
//使用NodeJS 進行打包
nodejs('nodejs'){
sh'''
npm install
npm run build
'''
}
//生成鏡像
sh "docker build -t ${project_name}:${tag} ."
//給鏡像打標簽
sh "docker tag ${imageName} ${harbor_url}/${harbor_project_name}/${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_name}/${imageName}"
}
//刪除本地鏡像
sh "docker rmi -f ${imageName}"
sh "docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}"
//=====以下為遠程調用進行項目部署========
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deploy.sh $harbor_url $harbor_project_name $project_name $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
6)編寫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 admin -p Harbor12345 $harbor_url
# 下載鏡像
docker pull $imageName
# 啟動容器
docker run -di -p $port:$port $imageName
echo "容器啟動成功"
7)修改代碼連接后端微服務服務
8)項目測試