部署需要提前准備的環境:安裝好Jenkins、docker、Maven、Jdk1.8、Git
說明:由於本例只說明如何部署,所以有關項目其他服務如nacos、mysql、redis、seata等默認已經安裝好的;這里只演示如何部署SpringCloud/SpringBoot應用到docker;
一. Jenkins插件安全和全局環境配置
插件安裝 進入Jenkins管理后台首頁面板 系統管理→插件管理→可選插件
需要安裝的插件: Pipeline Utility Steps(用於解析pom文件,因為后續創建的docker容器帶了版本,解析pom去拿版本,如果你的DockerFile生成的容器不帶版本,則不需要安裝)

全局參數配置:進入Jenkins管理后台首頁面板 系統管理→系統配置
在全局屬性里面添加一個環境變量,不然使用mvn命令時可能會報以下錯誤:
........./jenkins5323864766359302328.sh: line 2: mvn: command not found
查看系統PATH變量: echo $PATH
將查詢出的PATA添加到全局環境變量屬性中

全局參數配置:進入Jenkins管理后台首頁面板 系統管理→全局工具配置
編輯maven的setting.xml文件,設置遠程倉庫為阿里雲,設置Docker打包插件白名單
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
<pluginGroups>
<pluginGroup>com.spotify</pluginGroup>
</pluginGroups>
配置maven的setting文件和本地倉庫

設置git

配置Git賬號密碼:進入Jenkins管理后台首頁面板 系統管理→Manage Credentials
點擊添加憑據,范圍為全局,輸入用戶名和密碼點擊確定,ID會自動生成;我的代碼放在gitee,所以這里輸入的是碼雲的賬號密碼

二. 開始新建構建項目
本演示項目來自一個開源的SpringCloudAlibaba項目 源碼地址:https://gitee.com/liuyadu/open-cloud
components: 公用模塊,包含啟動的加載配置,工具類等公用的模塊,其他服務可以引入,完成一些基本的配置;
platform: 基本的服務,包含base服務(用於獲取基本數據),統一網關gateWay,統一用戶認證中心 ,uaa-admin-server
services: 其他服務
這里我只構建 base-server、gateway、uaa-admin-server三個服務

Jenkins新建文件夾
點擊新建任務,選擇文件夾類型;之后在該文件夾下面創建所有的服務,統一管理。這邊我已經創建好了,所以顯示已存在

創建拉取代碼任務項目
創建一個拉取代碼的項目,在open-cloud文件夾里面,新建item,這里選擇構建自由風格的軟件項目,用於拉取我們的項目源碼,這樣就不需要每個服務都單獨拉取一次了;

在源碼管理里面選擇Git,輸入項目Git地址,然后選擇我們之前就已經添加的gitee憑據,指定拉取的分支;

指定拉取的代碼保存地址: 在Additional Behaviors里面新增行為,選擇到指定本地分支;默認情況下拉取代碼到Jenkins工作目錄(默認是/var/lib/jenkins/workspace) 加上在jenkins創建的任務名稱

因為我們有創建一個文件夾,在文件夾下面創建的任務,所以默認是 /var/lib/jenkins/workspace/open-cloud/pull-project,但是我不想顯示pull-project,直接到open-cloud就行,所以我指定Git代碼保存目錄到open-cloud

點擊保存,然后點擊【立即構建】,拉取完之后就能在我們指定的路徑下面找到源碼了;
創建base-gateway服務
打包docker有兩種思路:一種是maven先把打成jar包和Dockerfile,然后使用docker build成一個鏡像,運行;另一種是使用maven的bulid工具,直接在本地打包輸出到指定的docker host主機,需要開啟2375端口給外界訪問/配置ssh秘鑰;
這邊我是直接在服務器上使用maven的docker打包插件,打包到本地容器;源碼pom坐標已經配置了maven docker打包插件,這邊以部署gateway服務為例,其他服務器部署只需要修改一下名稱即可;

在open-cloud文件夾下面,新建一個item,這里我叫base-gateway,選擇流水線;如果不知道Pipeline流水線任務的的可以去看一下文檔
官方文檔:https://www.jenkins.io/zh/doc/book/pipeline/
w3cschool:https://www.w3cschool.cn/jenkins/jenkins-173a28n4.html

在流水線里面,編寫自己的Pipeline腳本,Jenkins的Pipeline腳本支持直接編寫Script和從SCM加載腳本文件。如果選擇從SCM獲取,則可以直接把腳本放到項目的源碼里面,指定文件即可,為了方便我直接選擇編寫腳本。

腳本文件如下:
node {
// 指定工作目錄,必須指定,否則路徑默認會是/var/lib/jenkins/workspace/open-cloud/base-gateway/
dir('/var/lib/jenkins/workspace/open-cloud/') {
def workspace = pwd()
echo "workspace:${workspace}"
def image_name = 'open.cloud/open-cloud-base-gateway'
def container_name='open-cloud-base-gateway'
def project_home = 'open-cloud/open-cloud-base-gateway'
// docker 掛載目錄,自行創建前面的目錄路徑
def root_path = "/data/docker/work/${project_home}"
//刪除舊容器和鏡像
stage('RM 刪除舊容器和鏡像') {
echo '================刪除已經存在的容器和鏡像=================='
sh "/data/docker/work/docker-rm.sh ${container_name}"
}
//編譯代碼和依賴
stage('Build 編譯代碼和依賴') {
// Run the maven build
echo "bulid components模塊......."
sh "mvn -f components/pom.xml -Dmaven.test.skip=true clean install package -P test"
echo "bulid open-cloud-base-client......."
sh "mvn -f platform/open-cloud-base-client/pom.xml -Dmaven.test.skip=true clean install package -P test"
echo "bulid open-cloud-base-server......."
sh "mvn -f platform/${container_name}/pom.xml -Dmaven.test.skip=true clean install package -P test dockerfile:build"
}
//讀取pom文件獲取 version 和 port
def pom = readMavenPom file: 'pom.xml'
def port = "${pom.properties.appPort}"
//運行容器
stage('Run 運行容器') {
echo '================運行容器=================='
sh "docker run -p ${port}:${port} -d --name ${container_name} --restart=on-failure -v ${root_path}:${root_path} -v ${root_path}/log:/logs ${image_name}:${pom.version}"
}
}
}
這里我把port統一在每個服務的pom中配置,bootstrap.yml啟動配置讀取pom中的即可,這樣就可以保證我們在本地測試和docker部署的端口一致;


上面有一個sh文件用於判斷docker中是否已經存在此容器和鏡像,如果存在則刪除; sh文件內容如下,需要注意的是如果sh文件你是在Windows上創建的,格式可能無法直接運行,需要編輯文件 set ff=unix
#!/usr/bin/env bash
IMAGE_NAME=$1
echo "$IMAGE_NAME"
if [ ! -n "$IMAGE_NAME" ]; then
echo 參數不能為空
exit 4
fi
echo '================獲取鏡像id=================='
IID=$(docker images | grep "$IMAGE_NAME" | awk '{print $3}')
echo 鏡像id=$IID
if [ -n "$IID" ]; then
echo 存在$IMAGE_NAME鏡像
docker rmi $IID
else
echo 不存在$IMAGE_NAME鏡像
fi
echo '================獲取容器id=================='
CID=$(docker ps -aqf "name=$IMAGE_NAME")
echo 容器id=$CID
if [ -n "$CID" ]; then
echo 存在$IMAGE_NAME容器,停止容器並刪除
docker rm -f $IMAGE_NAME
else
echo 不存在$IMAGE_NAME容器
fi
最后保存,點擊立即構建;等待構建完成....

注意:構建中如果出現 org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use method java.util.Dictionary get java.lang.Object...錯誤,是因為讀取pom文件時需要Jenkins安全簽名認證,點擊系統管理選擇In-process Script Approval ,點擊approval ,對攔截到的命令允許通過,重啟Jenkins即可

- 相同步驟,創建base-serve、uaa-admin-serve

docker ps -a 查看容器運行情況,三個服務正常運行。

如果需要指定服務的啟動順序,可以使用構建觸發器,讓項目在其他項目構建完成之后觸發

