Jenkins(七) Jenkins+Docker+SpringCloud微服務持續集成(上)

大致流程說明:
1.開發人員每天把代碼提交到Gitlab代碼倉庫
2.Jenkins從Gitlab中拉取項目源碼,編譯并打成jar包,然后構建成Docker鏡像,將鏡像上傳到Harbor私有倉庫。
3.Jenkins發送SSH遠程命令,讓生產部署服務器到Harbor私有倉庫拉取鏡像到本地,然后創建容器。
4.最后,用戶可以訪問到容器

這里不講述Docker的安裝及基礎命令的使用,學dockers可以看 Docker 概念、命令、DockerFile等看這篇就夠了 這篇文章

Harbor 鏡像倉庫安裝及使用

Harbor(港口,港灣)是一個用于存儲和分發Docker鏡像的企業級Registry服務器。除了Harbor這個私有鏡像倉庫之外,還有Docker官方提供的Registry。相對Registry,Harbor具有很多優勢:

  1. 提供分層傳輸機制,優化網絡傳輸 Docker鏡像是是分層的,而如果每次傳輸都使用全量文件(所以
    用FTP的方式并不適合),顯然不經濟。必須提供識別分層傳輸的機制,以層的UUID為標識,確定
    傳輸的對象。
  2. 提供WEB界面,優化用戶體驗 只用鏡像的名字來進行上傳下載顯然很不方便,需要有一個用戶界
    面可以支持登陸、搜索功能,包括區分公有、私有鏡像。
  3. 支持水平擴展集群 當有用戶對鏡像的上傳下載操作集中在某服務器,需要對相應的訪問壓力作分
    解。
  4. 良好的安全機制 企業中的開發團隊有很多不同的職位,對于不同的職位人員,分配不同的權限,
    具有更好的安全性。

Harbor 安裝

  1. 除了docker以外,還要安裝dockers-compose,Docker Compose 命令及使用 你可以看這篇博客
  2. 下載Harbor的壓縮包,地址,需要科式上網,下載完成開始解壓
tar -xzf harbor-offline-installer-v1.9.2.tgz
mv harbor /opt/software/
# 修改配置文件內容
vim /opt/software/harbor/harbor.yml 
# 修改hostname
hostname: 你自己機器的IP
# 修改端口
port: 85
  1. 安裝Harbor
cd /opt/software/harbor
./prepare
./install.sh
  1. 啟動Harbor
docker-compose up -d 啟動
docker-compose stop 停止
docker-compose restart 重新啟動
  1. 訪問Harbor http://IP:85,默認賬戶密碼:admin/Harbor12345

Harbor 使用

1.創建項目
Harbor的項目分為公開和私有的:

  • 公開項目:所有用戶都可以訪問,通常存放公共的鏡像,默認有一個library公開項目。
  • 私有項目:只有授權用戶才可以訪問,通常存放項目本身的鏡像。

我們可以為微服務項目創建一個新的項目:

2.用戶創建

3.為用戶分配項目

推送到鏡像倉庫

# 打標簽,命令 docker tag nginx:1.17.1 Harbor的IP:端口/Harbor項目的名稱/鏡像名字
docker tag nginx:1.17.1 192.168.81.102:85/test/nginx:1.17.1
# 查看
docker images
# 會多一條鏡像數據
192.168.81.102:85/test/nginx         1.17.1                          98ebf73aba75        2 years ago         109MB

把Harbor地址加入到Docker信任列表

# 編輯docker文件
vim /etc/docker/daemon.json
# 加入這句話
"insecure-registries":["192.168.81.102:85"],
# 重啟配置和docker
systemctl restart docker
# Harbor  的 test 項目是私有的,需要登錄
docker login -u admin -p Harbor12345 192.168.81.102:85
# 推送到Harbor倉庫里
docker push 192.168.81.102:85/test/nginx

其他服務下載鏡像也需要把地址添加到docker的配置文件中,并且也需要使用 docker login 進行登錄。復制以下的命令,到其他服務器下執行即可。

微服務構建到docker鏡像

1.把微服務提交到 SVN
2.在jenkins上創建一個 Pipelin 類型的 item(項目)
3.配置Pipelin item的構建時參數

這里講一點,項目中很多的 jar 是有依賴關系的,如果單獨打某個服務可能會包找不到依賴,所以建議第一次對根目錄進行打包,會把依賴全部加載到maven庫中,后期單個服務打包即可。

4.在每個服務的pom文件中添加 plugin

<!-- 幫助讀取項目中的dockerfile文件,幫我們構建docker鏡像 -->
<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>
    <version>1.3.6</version>
    <configuration>
        <repository>${project.artifactId}</repository>
        <!-- 定義dockerfile 文件的參數 -->
        <buildArgs>
            <!-- 定義一個 JAVA_FILE 參數,指為我們項目的名稱 -->
            <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
        </buildArgs>
    </configuration>
</plugin>

5.在每個服務的根目錄下編寫 Dockerfile 文件

FROM openjdk:8-jdk-alpine
# 這個會讀取在pom中聲明的變量
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
# 對外端口
EXPOSE 10086
ENTRYPOINT ["java","-jar","/app.jar"]

6.設置構建后鏡像推至鏡像倉庫

7.在項目的根目錄中編寫 Jenkinsfile

node {
    // 版本
    def tag = "1.0"
    // 鏡像倉庫的地址
    def harbor_url = "192.168.81.102:85"
    // 鏡像倉庫的項目,這里建議項目名稱和jenkins的item項目名稱、以及harbor的項目名稱保持一致,否則用一下腳本會出問題
    def harbor_project = "demo"

    // 拉取代碼
    stage('pull code') {
        checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: '80dfe5c5-1684-47b1-a410-6f53ceb3c543', url: 'http://192.168.81.15:3000/biguncle/test.git']]])
    }
    // 編譯并推送鏡像倉庫
    stage('build project') {
        if  ("${project_name}" ==  'demo' ) {
            echo '打包根目錄'
            sh 'mvn clean package dockerfile:build'
        } else {
            echo  "打包子目錄 ${project_name}"
            sh "mvn -f ${project_name} clean package dockerfile:build"
        }
        echo "把jar上傳鏡像倉庫"
        def oldImageName = "${project_name}:latest"
        def newImageName = "${harbor_url}/${harbor_project}/${project_name}:${tag}"
        // 改名稱 做規范
        sh "docker tag ${oldImageName} ${newImageName}"
        // 刪除之前的 鏡像
        sh "docker rmi ${oldImageName}"
        // 推送到 dockers倉庫
        withCredentials([usernamePassword(credentialsId: '8a3d7ab1-4cd6-482c-86c9-a12aa6404d98', passwordVariable: 'harbor_password', usernameVariable: 'harbor_account')]) {
            // 登錄
            sh "docker login -u ${harbor_account} -p ${harbor_password} ${harbor_url}"
            // 上傳
            sh "docker push ${newImageName}"
            echo "鏡像推送成功"
        }
    }
    // 發送郵件
    stage('send email') {
        emailext body: '''<!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次構建日志</title>
        </head>
        <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
        <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sansserif">
            <tr>
                <td>(本郵件是程序自動下發的,請勿回復!)</td>
            </tr>
            <tr>
                <td><h2>
                    <font color="#0000FF">構建結果 - ${BUILD_STATUS}</font>
                </h2></td>
            </tr>
            <tr>
                <td><br/>
                    <b><font color="#0B610B">構建信息</font></b>
                    <hr size="2" width="100%" align="center"/>
                </td>
            </tr>
            <tr>
                <td>
                    <ul>
                        <li>項目名稱&nbsp;:&nbsp;${PROJECT_NAME}</li>
                        <li>構建編號&nbsp;:&nbsp;第${BUILD_NUMBER}次構建</li>
                        <li>觸發原因:&nbsp;${CAUSE}</li>
                        <li>構建日志:&nbsp;
                            <a href="${BUILD_URL}console">${BUILD_URL}console</a>
                        </li>
                        <li>構建&nbsp;&nbsp;Url&nbsp;:&nbsp;
                            <a href="${BUILD_URL}">${BUILD_URL}</a>
                        </li>
                        <li>工作目錄&nbsp;:&nbsp;
                            <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a>
                        </li>
                        <li>項目&nbsp;&nbsp;Url&nbsp;:&nbsp;
                            <a href="${PROJECT_URL}">${PROJECT_URL}</a>
                        </li>
                    </ul>
                </td>
            </tr>
            <tr>
                <td><b><font color="#0B610B">Changes Since Last Successful Build:</font></b>
                    <hr size="2" width="100%" align="center"/>
                </td>
            </tr>
            <tr>
                <td>
                    <ul>
                        <li>歷史變更記錄 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
                    </ul>
                    ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br/>%c<br/>",showPaths=true,changesFormat="<pre>[%a]<br/>%m</pre>",pathFormat="&nbsp;&nbsp;&nbsp;&nbsp;%p"}
                </td>
            </tr>
            <tr>
                <td><b>Failed Test Results</b>
                    <hr size="2" width="100%" align="center"/>
                </td>
            </tr>
            <tr>
                <td>
                    <pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica,sans-serif">
                        $FAILED_TESTS
                    </pre>
                    <br/>
                </td>
            </tr>
            <tr>
                <td><b><font color="#0B610B">構建日志 (最后 100行):</font></b>
                    <hr size="2" width="100%" align="center"/>
                </td>
            </tr>
            <tr>
                <td>
                    <textarea cols="80" rows="30" readonly="readonly"
                              style="font-family: Courier New">
                        ${BUILD_LOG,maxLines=100}
                    </textarea>
                </td>
            </tr>
        </table>
        </body>
        </html>''', mimeType: 'text/html', subject: '43243214321', to: '875730567@qq.com'
    }
}

jenkins自動化服務拉取鏡像并啟動

這部操作需要安裝一個 Publish Over SSH 插件,安裝好后在Manager Jenkins -> Configure System 進行配置

更改 Jenkinsfile 腳本,添加遠程機器拉取鏡像并啟動容器,具體語法怎么使用,可以到 流水線語法中查看

node {
    // 版本
    def tag = "1.0"
    // 鏡像倉庫的地址
    def harbor_url = "192.168.81.102:85"
    // 鏡像倉庫的項目,這里建議項目名稱和jenkins的item項目名稱、以及harbor的項目名稱保持一致,否則用一下腳本會出問題
    def harbor_project = "demo"

    // 拉取代碼
    stage('pull code') {
        checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: '80dfe5c5-1684-47b1-a410-6f53ceb3c543', url: 'http://192.168.81.15:3000/biguncle/test.git']]])
    }
    // 編譯并推送鏡像倉庫
    stage('build project') {
        if  ("${project_name}" ==  'demo' ) {
            echo '打包根目錄'
            sh 'mvn clean package dockerfile:build'
        } else {
            echo  "打包子目錄 ${project_name}"
            sh "mvn -f ${project_name} clean package dockerfile:build"
        }
        echo "把jar上傳鏡像倉庫"
        def oldImageName = "${project_name}:latest"
        def newImageName = "${harbor_url}/${harbor_project}/${project_name}:${tag}"
        // 改名稱 做規范
        sh "docker tag ${oldImageName} ${newImageName}"
        // 刪除之前的 鏡像
        sh "docker rmi ${oldImageName}"
        // 推送到 dockers倉庫
        withCredentials([usernamePassword(credentialsId: '8a3d7ab1-4cd6-482c-86c9-a12aa6404d98', passwordVariable: 'harbor_password', usernameVariable: 'harbor_account')]) {
            // 登錄
            sh "docker login -u ${harbor_account} -p ${harbor_password} ${harbor_url}"
            // 上傳
            sh "docker push ${newImageName}"
            echo "鏡像推送成功"
        }

        // 遠程調用腳本,port 最好也添加 jenkins項目配置里的參數配置,作為參數傳進來
        echo "執行遠程命令 /home/server/deploy.sh ${harbor_url} ${harbor_project} ${project_name} ${tag} ${port}"
        sshPublisher(publishers: [sshPublisherDesc(configName: 'test_103', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/home/server/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)])

    }
    // 發送郵件
    stage('send email') {
        emailext body: '''<!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次構建日志</title>
        </head>
        <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
        <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sansserif">
            <tr>
                <td>(本郵件是程序自動下發的,請勿回復!)</td>
            </tr>
            <tr>
                <td><h2>
                    <font color="#0000FF">構建結果 - ${BUILD_STATUS}</font>
                </h2></td>
            </tr>
            <tr>
                <td><br/>
                    <b><font color="#0B610B">構建信息</font></b>
                    <hr size="2" width="100%" align="center"/>
                </td>
            </tr>
            <tr>
                <td>
                    <ul>
                        <li>項目名稱&nbsp;:&nbsp;${PROJECT_NAME}</li>
                        <li>構建編號&nbsp;:&nbsp;第${BUILD_NUMBER}次構建</li>
                        <li>觸發原因:&nbsp;${CAUSE}</li>
                        <li>構建日志:&nbsp;
                            <a href="${BUILD_URL}console">${BUILD_URL}console</a>
                        </li>
                        <li>構建&nbsp;&nbsp;Url&nbsp;:&nbsp;
                            <a href="${BUILD_URL}">${BUILD_URL}</a>
                        </li>
                        <li>工作目錄&nbsp;:&nbsp;
                            <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a>
                        </li>
                        <li>項目&nbsp;&nbsp;Url&nbsp;:&nbsp;
                            <a href="${PROJECT_URL}">${PROJECT_URL}</a>
                        </li>
                    </ul>
                </td>
            </tr>
            <tr>
                <td><b><font color="#0B610B">Changes Since Last Successful Build:</font></b>
                    <hr size="2" width="100%" align="center"/>
                </td>
            </tr>
            <tr>
                <td>
                    <ul>
                        <li>歷史變更記錄 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
                    </ul>
                    ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br/>%c<br/>",showPaths=true,changesFormat="<pre>[%a]<br/>%m</pre>",pathFormat="&nbsp;&nbsp;&nbsp;&nbsp;%p"}
                </td>
            </tr>
            <tr>
                <td><b>Failed Test Results</b>
                    <hr size="2" width="100%" align="center"/>
                </td>
            </tr>
            <tr>
                <td>
                    <pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica,sans-serif">
                        $FAILED_TESTS
                    </pre>
                    <br/>
                </td>
            </tr>
            <tr>
                <td><b><font color="#0B610B">構建日志 (最后 100行):</font></b>
                    <hr size="2" width="100%" align="center"/>
                </td>
            </tr>
            <tr>
                <td>
                    <textarea cols="80" rows="30" readonly="readonly"
                              style="font-family: Courier New">
                        ${BUILD_LOG,maxLines=100}
                    </textarea>
                </td>
            </tr>
        </table>
        </body>
        </html>''', mimeType: 'text/html', subject: '43243214321', to: '875730567@qq.com'
    }
}

重新構建,其他服務器就會自動拉取了。

其他服務器一定要有 jenkins 服務器的公鑰,構建過程 SSH 不會輸出任何信息只會告訴你 EXEC 執行了多久,需要自己去測一下。

vue 前端使用Jenkins部署

1.首先需要安裝 NodeJS 插件
2.到Manager Jenkins->Global Tool Configuration->NodeJS

3.創建一個流水線的前端項目,根據腳本把配置補全

node {
    stage('拉取代碼') {
        checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: '80dfe5c5-1684-47b1-a410-6f53ceb3c543', url: 'http://192.168.81.15:3000/biguncle/test_vue.git']]])
    }
    stage('打包,部署網站') {
        //使用NodeJS的npm進行打包,這個和 以上的 name 保持一致
        nodejs('nodejs12'){
            sh '''
                npm install
                npm 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)])
    }
}

從腳本中可以看出,我們需要一個 branch 參數,還要配置 前端項目的 遠程 server 地址

這里沒有使用execCommand的命令,而是通過 sourceFiles、removePrefix、remoteDirectory,sourceFiles 代表我們copy哪個文件,remoteDirectory 遠程目錄,特就是copy到nginx所在目錄
57-62

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容