1. 程式人生 > >基於GitLab+Jenkins的DevOps賦能實踐

基於GitLab+Jenkins的DevOps賦能實踐

    隨著微服務、中臺架構的興起,DevOps也變得非常關鍵,畢竟是一些基礎設施層面的建設,如果搞好了對後面的研發工作會有很大的效率提升。關於DevOps本身的概念,網上已經非常多了,在園子裡隨便搜尋一些都一堆概念,我就不再重複介紹了。下面直接進入正題,怎麼使用GitLab+Jenkins來完成DevOps的建設。

    在開始實戰演練之前,首先用一張圖來展示一下這次實踐所要完成的功能:

    

    在這個流程中,分為3個環境,分別是預覽環境、預發環境和生產環境,普通開發者接受到任務以後,在GitLab中基於feature分支進行開發,然後把開發好的需求申請合併到dev分支,在申請合併的過程中,會觸發構建流水線進行編譯、單元測試、介面測試、釋出環境等系列校驗,當pipeline完成以後,組長就可以在程式碼審查後,進行合併到dev分支。這個時候又會觸發dev分支的構建流水線,然後再完成一遍上述的流程,把程式碼釋出到預發環境。最後由專案負責人定期把dev合併到master分支,完成生產環境版本釋出。

    首先,在GitLab中建立一個測試專案:

    這個專案是在lizongshenblogs的group下面的applications子group下的一個專案,代表了這是一個原始碼專案。

接下來再為這個專案建立3個流水線配置,主要目的是為了讓程式碼和配置分離:

     在3個配置專案中,分別存放了相應的Jenkinsfile,用於Jenkins流水線的構建配置,接下來開始配置Jenkins。首先進行Jenkins的全域性配置:在Jenkins的Manage Jenkins - Configure System下面配置Gitlab Connection,如圖:

 

在這裡需要注意,這個connection是需要一個gitlab的訪問令牌,可以在gitlab的個人設定 - 訪問令牌裡面生成,生成完成之後,填入到相應的Credentials裡面:

 

 最後測試一下,連線是否成功,只要顯示success,就可以了。

 

 接下來就可以配置具體pipeline了,首先使用Jenkins的New Item分別建立3個流水線型別的專案:

 

 

    在Jenkins中新建3個流水線型別的專案,分別叫feature-pipeline、dev-pipeline、master-pipeline,然後對這3個專案分別進行配置,先來看feature-pipeline的配置:

    首先要配置的項是Build Triggers,在其中勾選Opened Merge Request Events,並且把Rebuild open Merge Requests設定成On push to source branch:

 

 

 然後點選Advanced按鈕,進行高階設定:

 

這裡需要注意的地方是原分支是任何分支,目標分支是dev分支,然後生成一個Secret token,這個token在配置gitlan webhooks的時候會用到。

接下來是配置Pipeline項:

 

 

     這個地方需要配置具體的流水線倉儲的地址,在credentials的地方,使用賬號密碼登入到gitlab即可。

    dev流水線和master流水線配置略有不同,其中dev分支需要配置成accepted merge request events,意思就是當組長接受合併請求的時候觸發:

 

 

     而master分支需要改變的地方是匹配的分支,表示只接受從dev分支到master分支的合併請求:

 

 

     到這裡Jenkins的配置已經配置完成,接下來再回到gitlab進行聯動配置,首先配置專案的webhoos,在專案的Integrations Settings裡面新增一個webhooks:

 

 

    其中URL就填寫Jenkins的Build Triggers專案自動生成的那個URL,secret token是在Build Triggers的高階選項裡面生成的那個token,觸發的選項選擇Merge request events,表示當合並請求的時候進行觸發,點選儲存,gitlab和Jenkins的配置基本上就完成了。

    最後看一下3個專案中的Jenkinsfile:

pipeline {
    agent {
        label 'slave-pipeline'
    }
    options {
        gitLabConnection('gitlab')
    }
    stages {
        stage('Prepare'){
            steps{
                script{
                        git branch: '${gitlabSourceBranch}', changelog: false, credentialsId: 'gitlab', poll: false, url: 'https://gitlab.com/lizongshenblogs/applications/devopsdemo.git'
                                
                        script {
                            GIT_COMMIT_ID = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
                            IMAGE_TAG = "${GIT_COMMIT_ID}-snapshot"
                            INGRESS_HOST = "preview-${gitlabSourceRepoName}-${gitlabMergeRequestIid}"
                            MR_URL = "${gitlabSourceRepoHomepage}/merge_requests/${gitlabMergeRequestIid}"
    
                            build_tag = "feature-${gitlabSourceRepoName}-${gitlabSourceBranch}-${GIT_COMMIT_ID}"
                            currentBuild.displayName = "#" + BUILD_NUMBER + "_" + gitlabMergeRequestIid + "_" + build_tag
                        }
                }
            }
        
        }
    
        stage('Build') {
        
            when {
                expression {
                    "${gitlabTargetBranch}" == 'dev'
                }
            }
            
            steps {
                script {
                    updateGitlabCommitStatus name: 'Build', state: 'running'
    
                    try {
                    
                        echo "開始編譯..."
                        
                    } catch(Exception ex){
                        updateGitlabCommitStatus name: 'Build', state: 'failed'
                        throw ex;
                    } finally {
    
                    }
    
                    updateGitlabCommitStatus name: 'Build', state: 'success'
    
                }
            }
        }
        stage('Test') {
            steps {
                script {
                    updateGitlabCommitStatus name: 'Test', state: 'running'
    
                    try {
                        echo "開始進行單元測試..."
                    } catch(Exception ex){
                        updateGitlabCommitStatus name: 'Test', state: 'failed'
                        throw ex;
                    } finally {
    
                    }
                    
                    updateGitlabCommitStatus name: 'Test', state: 'success'
                     
                }
            }
        }
        stage('Deploy') {
            steps {
                script {
                    updateGitlabCommitStatus name: 'Deploy', state: 'running'
    
                    try {
                        echo "開始進行釋出..."

                    } catch(Exception ex){
                        updateGitlabCommitStatus name: 'Deploy', state: 'failed'
                        throw ex;
                    } finally {
    
                    }
                    
                    updateGitlabCommitStatus name: 'Deploy', state: 'success'
                    addGitLabMRComment comment: "App ${gitlabSourceRepoName} preview link: <a href='http://localhost'>${gitlabSourceRepoName}</a>"
                }
            }
        }
    }
    
    post {
        failure {
            updateGitlabCommitStatus name: 'Complete', state: 'failed'
        }
        success {
            updateGitlabCommitStatus name: 'Complete', state: 'success'
        }
    }
}

    其中updateGitlabCommitStatus就可以實時地把Jenkins的構建狀態發回到gitlab中去:

 

    點選這些構建狀態,就可以實時地檢視到構建日誌。在這裡gitlab和Jenkins的配置基本上就全部完成了,接下來再看一下gitlab中關於程式碼管理配置,一般情況下,dev分支和master分支是不允許直接push程式碼的,只允許從需求分支中合併程式碼,這就需要在gitlab的       Settings - Repository - Protected Branches中把dev和master保護起來:

 

     另外還可以設定只有當流水線成功了以後,才可以進行合併:

 

    通過這樣一些保護措施,就可以讓dev和master分支變得相對穩定。由於篇幅有限,再加上Jenkinsfile中包含了太多的定製化敏感內容,只能進行一些刪減,如果有不明白的地方,可以私下找我相互交流。

    寫在最後:DevOps是一個很廣泛的話題,今天講的GitLab+Jenkins這套流程只是DevOps中的一部分,完全實現DevOps還需要更多的流程配合,以後有機會再為大家分享。

&n