iT邦幫忙

2022 iThome 鐵人賽

DAY 9
1
DevOps

不想吃土嗎?就利用開源軟體打造CICD Pipeline吧!系列 第 9

Day 9: SonarQube自動化!讓我默默守護你的代碼!

  • 分享至 

  • xImage
  •  

昨天我們成功使用了SonarQube進行第一次的掃描。今天我們就讓SonarQube跟Jenkins整合到一起,使得每次的程式碼開發都會觸發一次掃描。這個做法可以使得程式碼中的問題盡快反映到SonarQube中,開發者就可以於技術債務還不算多的時候就光速進行處理。

NodeJS在Jenkins的設定

昨天我們利用了一個NodeJS的範例程式進行了掃描,所以這次我們依舊使用同一個範例程式去做教學。

由於SonarQube在掃描的過程中需要運行NodeJS才可以成功進行,所以我們第一步要先讓Jenkins有能力運行NodeJS。為此我們必須先安裝一個Jenkins的插件。

首先,在左方的選單中按下Manage Jenkins,進入設定的主畫面。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012XrCQqhf5Kn.png

然後選擇Manage Plugins
https://ithelp.ithome.com.tw/upload/images/20220921/20152012kUXZVgisvG.png

選擇Available的分頁。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012ZPOdbYz5V1.png

然後在搜尋欄中輸入NodeJS,然後勾選NodeJS的插件後按Install without restart。當然你也可以重啟Jenkins。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012ytoQJZ0Fsw.png

安裝完成後,回到設定的主畫面。然後按下Global Tool Configuration
https://ithelp.ithome.com.tw/upload/images/20220921/20152012Kzpb57XXeF.png

找到NodeJS的部份,然後按下Add NodeJS
https://ithelp.ithome.com.tw/upload/images/20220921/20152012wQGXhQv5py.png

Name中輸入NodeJS,這個名字一會我們會用到。然後選擇你所需要的NodeJS版本。此次我們使用最新的NodeJS版本去運行我們的範例。輸入後以後,在最底的部份按下Save儲存。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012KKcm1saYe1.png

這樣我們就設定好了NodeJS的插件了!

這個設定的目的是讓我們的Jenkins Runner有能力運行如npm install或是node等指令。如果你使用多於一個Jenkins Runner的話,可以在有需要的Runner中安裝此插件。如果你使用的是Java,亦需要作類此的設定,本次系列不詳細說明了。

SonarQube在Jenkins的設定

當準備好NodeJS的設定後,我們可以使用同樣的方法去安裝SonarQube的插件,使Jenkins有掃瞄程式碼的能力。

再次進入到Manage Plugins的頁面中,然後在Available的分頁入輸入SonarQube Scanner,勾選插件然後按下Install without restart
https://ithelp.ithome.com.tw/upload/images/20220921/20152012PaS57fT7M7.png

設定服務器

然後我們需要設定SonarQube的服務器位址,以取得不同語言的掃描規則,以及上載掃描後的報告。

進入Jenkins的設定頁面,然後按下Configure System
https://ithelp.ithome.com.tw/upload/images/20220921/20152012W4hTSLSeKA.png

找到SonarQube servers的部份,然後按下Add SonarQube
https://ithelp.ithome.com.tw/upload/images/20220921/20152012xd9gBfzLvp.png

由於我使用本機架設的SonarQube,所以我在名稱中輸入Local。然後輸入本機SonarQube的位址。如果不知道本機Docker架起的SonarQube的IP,可以用以下指令取得IP。

docker inspect {SonarQube Container Name} | grep "IPAddress"
  • {SonarQube Container Name}: 換成你的SonarQube容器的名稱
    https://ithelp.ithome.com.tw/upload/images/20220921/20152012KfY0PYVHAO.png

然後我們需要加入Jenkins連接到SonarQube時所使用的認證。在Server authentication token的下拉選單下方,找到Add的按鈕,然後按下Jenkins
https://ithelp.ithome.com.tw/upload/images/20220921/20152012XOc2ZEs2NL.png

在彈出的畫面中,Kind的下拉選單中找到Secret text,代表使用Token進行認證。在Secret的欄位中,輸入我們昨天使用過的Token。然後在ID欄位中輸入LocalSonarQube。然後按Add
https://ithelp.ithome.com.tw/upload/images/20220921/201520125FjH1JIV61.png

回到上一個畫面後,在下拉選單中選擇新加的LocalSonarQube,然後按Save儲存。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012dmjXQh1LfU.png

設定掃描器

設定了服務器後,我們需要為Jenkins設定掃描器。進入Jenkins的設定頁面,然後按下Global Tools Configuration。然後找到SonarQube Scanner的部份,按下Add SonarQube Scanner
https://ithelp.ithome.com.tw/upload/images/20220921/20152012uWrjr2ZSn6.png

Name的欄位中輸入CliScanner,以後會用到。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012C909cbNnyV.png

由於我們使用NodeJS,所以我們不能直接使用Maven提供的Scanner。所以我們要使用CLI版本的Sonar Scanner。按下Add Installer去新增一個新的Scanner。然後選擇Extract *.zip/*.tar.gz,在URL一欄中,輸入SonarQube提供的CLI版Sonar Scanner下載連結(https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.7.0.2747-linux.zip)。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012sDcfqRyvn6.png

然後按下Save儲存。

成功設定好SonarQube Scanner!

在Pipeline中運行SonarQube Scanning

打開我們在Day 6的第一條Pipeline,然後我們開始設置意義上的第一個自動化流程。

打開我們在Day 6設置好的Jenkinsfile,把Hello的Stage移除。然後在Stages中加入Code Scanning的 Stage。

pipeline {
    agent any

    stages {
        stage('Code Scanning') {

        }
	}
}

由於我們使用CLI的Sonar Scanner,我們需要引用到Sonar Scanner的解壓縮工作位置。在Stage中加入以下的Environment(環境變數)。

pipeline {
    agent any

    stages {
        stage('Code Scanning') {
            environment {
                scannerHome = tool 'CliScanner'
            }
        }
	}
}

這裡其實是一個變數,讓scannerHome這個變數取得CliScanner在Jenkins的工作位置。而CliScanner就是上一個部份我們設定的Scanner插件時所填入的名稱。

然後再加入SonarQube Scanning的Step。

pipeline {
    agent any

    stages {
        stage('Code Scanning') {
            environment {
                scannerHome = tool 'CliScanner'
            }
            steps {
                withSonarQubeEnv('Local'){

                }
            }
        }
	}
}

這裡withSonarQubeEnv是一個由SonarQube插件提供的block,後面的Local是最初我們設定的服務器名稱。如果填入不同的名稱,可以讓我們選擇使用不同的SonarQube服務器。

然後中間的部份,我們先輸出Start Scanning…,代表我們成功進入了這個block開始進行檢測的步驟。然後用sh去執行SonarQube的Scanning。

pipeline {
    agent any

    stages {
        stage('Code Scanning') {
            environment {
                scannerHome = tool 'CliScanner'
            }
            steps {
                withSonarQubeEnv('Local'){
                    echo "Start Scanning..."
                    sh "${scannerHome}/bin/sonar-scanner"
                }
            }
        }
	}
}

這裡可以看到sh所執行的指令,就是引用scannerHome這個變數的位置,然後取得當中的bin/sonar-scanner並執行。

完成後我們把源碼commit到專案並上傳到remote的Git專案中,然後先執行一次Pipeline。我們先回到Jenkins中,按下Build Now
https://ithelp.ithome.com.tw/upload/images/20220921/20152012h2VaXH3cf3.png

成功了!我們回到SonarQube看一下結果。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012WtyF5YVnUD.png

噫!跟想像中不太一樣。我們測試專案中應該有一些Bug存在的,但為甚麼這次檢測不到呢?

讓我們回到Jenkins中查看一下檢測過程。

在左方的Build History中找到最後的Pipeline執行結果。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012k4P5aHBRpC.png

然後在左方按下Console Output
https://ithelp.ithome.com.tw/upload/images/20220921/20152012hoaSiok92x.png

仔細查看後,發現原來SonarQube執行檢測的過程中,由於缺少了NodeJS的功能,因此未能成功掃描專案。這個問題很容易解決,還記得最初我們已經設定了NodeJS的執行環境嗎?是時候派上用場了!
https://ithelp.ithome.com.tw/upload/images/20220921/20152012SfWyO2dtSW.png

讓我們回到Jenkinsfile中,然後在withSonarQubeEnv的block中加入NodeJS的block。

pipeline {
    agent any

    stages {
        stage('Code Scanning') {
            environment {
                scannerHome = tool 'CliScanner'
            }
            steps {
                withSonarQubeEnv('Local'){
                    nodejs(nodeJSInstallationName: 'NodeJS') {
                        echo "Start Scanning..."
                        sh "${scannerHome}/bin/sonar-scanner"
                    }
                }
            }
        }
    }
}
  • nodeJSInstallationName: 最初設定的NodeJS環境的名稱

然後再commit、上傳、執行。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012IhuNUG4Mvl.png

跑完Pipeline後回到SonarQube。
https://ithelp.ithome.com.tw/upload/images/20220921/20152012a41al0rSgs.png

耶!錯誤都回來了!(明明有Bug不知道是在興奮甚麼…)

小結

就是這樣,我們成功使用了第一個靜態測試軟體,並且整合到了我們的Pipeline中。其實這裡我們可以再加入Quality Gates的概念到Pipeline中,使得當我們掃描結果不理想的時候中斷後續的步驟。但由於篇幅的關係,這裡就留待大家自己按需要去發掘Jenkins的更多功能了。

其他軟體的整合方式其實都是大同小異,當加入更多的Stage在Pipeline以後,每次自動化就會報行更多的自動化的操作。接下來就讓我們一起為這條Pipeline加入更多的功能吧!

題外話

SonarQube真的挺好的一套軟體,免費版本除了支援不少語言外,近來還加入了CloudFormation跟Terraform的掃描。基本上我之前參與的項目中,每一條Pipeline都一定有這個軟體的存在,所以這幾天多講了一點相關的內容。希望這幾天的介紹對大家有所幫助啦!


上一篇
Day 8: 快快樂樂地用SonarQube進行檢測吧!
下一篇
Day 10: 軟體供應鏈的守護者!Dependency Track!
系列文
不想吃土嗎?就利用開源軟體打造CICD Pipeline吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言