🎲

DockerでSonarQubeを構築してPythonコードを解析する

2022/02/10に公開約14,300字

DockerでSonarQubeを構築してPythonコードを解析します。

はじめに

先人たちの知恵をお借りするなどして解決できたことを、この場をお借りして感謝するとともに、大変恐縮ですが 自分のメモ として、こちらへまとめておきます。

0 検証環境

  • Windows 10 Pro 21H1
  • Docker 20.10.12

1 SonarQubeとは

コード品質を継続的に検査するためのオープンソースで、ソースコードの静的分析により自動レビューを行うことができます。

機能としては、下記のようなものがあります。

  • バグの検出 bugs
  • 重複コードの検出 duplications
  • 脆弱性のあるコードの検出 vulnerabilities
  • バグを誘発しそうなコードの検出 code smells
  • カバレッジの計測 coverage

また、コード品質の判定するために、自ら設定できる品質が良い状態かの閾値としてQuarityGateがあります。

それでは、構築していきましょう。

2 構築

SonarQubeのコンテナをつくる

docker-hub : sonarqube を使います。

$ docker run -p 9000:9000 --name sonarqube -d --restart always -it sonarqube:lts

docker psコマンドでStatus upになれば成功です。

$ docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS          PORTS                    NAMES
86164ce3bf1a   sonarqube:lts   "bin/run.sh bin/sona…"   28 seconds ago   Up 26 seconds   0.0.0.0:9000->9000/tcp   sonarqube

SonarQubeにログイン

http://localhost:9000 でアクセスできます。

→ ログインid/初期パスワードは、admin/admin です。

※ パスワードを変更しましょう!

さぁログインできましたか?

ログインすると、ダッシュボード画面が表示されます。
まだプロジェクトは何も無いために空の状態ですね。

3 QualityGatesの設定

ヘッダーより "Quality Gates" を押下すると、Quality Gatesの設定画面が表示されます。

初期設定として "SonarWay" というQualityGatesが設定されています。

"Conditions on New Code" とある通り、新しく追加されたソースコードに対してQualityGateの判定を行なう設定となっています。
常に全てのコードにQualityGateの判定をしたい場合は、新たなQualityGateを作成する必要があります。

4 プロジェクトをつくる

ヘッダーより "Projects" を押下します。

画面中央に "Add a project" ボタンが現れますので、それを押下します。

ここでは新規のプロジェクトを作成します。
一番左の "Manually" を押下します。

  • "Project Key"(プロジェクトの名前)を入力します。
  • "Display name" は自動入力されます。
  • "Set Up" ボタンを押下し、次に進みます。

のちほど設定するSonar-scannerが、SonarQubeのアクセスするためのトークンを作成します。
ユーザー名(任意)を入力し、"Generate" ボタンを押下します。

トークンが作成されたら "Continue" ボタンを押下します。

5 Sonar-scannerのインストール

ダウンロードリンクの取得

トークンを作成すると、解析する言語と環境の選択に遷ります。
(Java以外の解析では)Sonar-scannerが必要です。
Pythonを解析したいため、ここでは "Other" を選択します。
OSは "Linux" を選択します。

中央に、"Visit the official documentation of the Scanner to download the latest version, and add the bin directory to the PATH environment variable" とありますので、リンクから、公式のSonar-scannerのDocumentへ遷ります。

Documentの "Linux64-bit" のリンクをコピーします。このリンクが、Sonar-scannerのダウンロード用リンクです。

ダウンロード

SonarQubeのコンテナから、Sonar-scannerをダウンロードします。
sonarqubeコンテナにログインしましょう。
ユーザ指定(-u)しないと、sudo権限のないsonarユーザーになってしまいます。-uオプションは忘れずに!

$ docker exec -it -u root sonarqube bash

必要なパッケージを予めコンテナにインストールしておきましょう。
最低限必要となるのは、wget unzip です。
PATHを通すために .bashrc ファイルを編集したいため、vim もインストールしておきます。
Github等からソースコードを連携したい人は、git もインストールしましょう。

# apk update
# apk upgrade
# apk add wget unzip vim git

(2022年2月11日 一部修正)
apk upgradeを行なわないほうが良い というご指摘をいただきました。
 "sonarqubeのDockerfileを見ると、glibc等ライブラリをバージョン指定でインストールしていまため、ライブラリのバージョンが上がった時に動作しない可能性がある" とのことです。

インストールが終わったら、Sonar-scannerのzipファイルを wget でダウンロードします。

# wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-linux.zip
# ls -l
total 42192
-rw-r--r--    1 sonarqub sonarqub      7651 Feb  4 08:23 COPYING
drwxr-xr-x    1 sonarqub sonarqub      4096 Feb  5 05:35 bin
drwxr-xr-x    2 sonarqub sonarqub      4096 Feb  4 08:23 conf
drwx------    1 sonarqub sonarqub      4096 Feb  9 12:20 data
-rw-r--r--    1 sonarqub sonarqub     40615 Feb  4 08:26 dependency-license.json
drwxr-xr-x    7 sonarqub sonarqub      4096 Feb  4 08:41 elasticsearch
drwx------    1 sonarqub sonarqub      4096 Feb  9 12:21 extensions
drwxr-xr-x    6 sonarqub sonarqub      4096 Feb  4 08:41 lib
drwx------    1 sonarqub sonarqub      4096 Feb 10 00:11 logs
-rw-r--r--    1 root     root      43099390 Feb  9 14:01 sonar-scanner-cli-4.6.2.2472-linux.zip
drwx------    1 sonarqub sonarqub      4096 Feb 10 00:12 temp
drwxr-xr-x    6 sonarqub sonarqub      4096 Feb  4 08:41 web

ダウンロードできたら、unzip コマンドで展開します。

# unzip sonar-scanner-cli-4.6.2.2472-linux.zip

展開すると、sonar-scannerのディレクトリが出来ます。
このディレクトリ配下にbinがあり、その中にsonar-scannerコマンドが入っています。

# ls -l
total 42196
-rw-r--r--    1 sonarqub sonarqub      7651 Feb  4 08:23 COPYING
drwxr-xr-x    1 sonarqub sonarqub      4096 Feb  5 05:35 bin
drwxr-xr-x    2 sonarqub sonarqub      4096 Feb  4 08:23 conf
drwx------    1 sonarqub sonarqub      4096 Feb  9 12:20 data
-rw-r--r--    1 sonarqub sonarqub     40615 Feb  4 08:26 dependency-license.json
drwxr-xr-x    7 sonarqub sonarqub      4096 Feb  4 08:41 elasticsearch
drwx------    1 sonarqub sonarqub      4096 Feb  9 12:21 extensions
drwxr-xr-x    6 sonarqub sonarqub      4096 Feb  4 08:41 lib
drwx------    1 sonarqub sonarqub      4096 Feb 10 00:11 logs
drwxr-xr-x    6 root     root          4096 May  7  2021 sonar-scanner-4.6.2.2472-linux
-rw-r--r--    1 root     root      43099390 Feb  9 14:01 sonar-scanner-cli-4.6.2.2472-linux.zip
drwx------    1 sonarqub sonarqub      4096 Feb 10 00:12 temp
drwxr-xr-x    6 sonarqub sonarqub      4096 Feb  4 08:41 web

sonar-scannerコマンドが使えるように .bashrcファイルにPATHの設定をします。

# vim ~/.bashrc

「i」キーを押下してinsertモードにしてから、以下を入力します。

export PARH="$PATH:/opt/sonarqube/sonar-scanner-4.6.2.2472-linux/bin"

「esc」キーを押下してinsertモードから抜けたら、:wqと入力して、保存してvimから抜けて、dockerへ戻ります。

設定し終えたら、.bashrcファイルを再読み込みします。

# source ~/.bashrc

6 コード解析

sonarqubeコンテナに、解析したいソースコードを置きます。
/opt/sonarqube/python 配下のソースコードを解析します。

# pwd
/opt/sonarqube
# ls -l
total 42200
-rw-r--r--    1 sonarqub sonarqub      7651 Feb  4 08:23 COPYING
drwxr-xr-x    1 sonarqub sonarqub      4096 Feb  5 05:35 bin
drwxr-xr-x    2 sonarqub sonarqub      4096 Feb  4 08:23 conf
drwx------    1 sonarqub sonarqub      4096 Feb  9 12:20 data
-rw-r--r--    1 sonarqub sonarqub     40615 Feb  4 08:26 dependency-license.json
drwxr-xr-x    7 sonarqub sonarqub      4096 Feb  4 08:41 elasticsearch
drwx------    1 sonarqub sonarqub      4096 Feb  9 12:21 extensions
drwxr-xr-x    6 sonarqub sonarqub      4096 Feb  4 08:41 lib
drwx------    1 sonarqub sonarqub      4096 Feb 10 00:11 logs
drwxr-xr-x    2 root     root          4096 Feb 10 12:24 python
drwxr-xr-x    6 root     root          4096 May  7  2021 sonar-scanner-4.6.2.2472-linux
-rw-r--r--    1 root     root      43099390 Feb  9 14:01 sonar-scanner-cli-4.6.2.2472-linux.zip
drwx------    1 sonarqub sonarqub      4096 Feb 10 00:12 temp
drwxr-xr-x    6 sonarqub sonarqub      4096 Feb  4 08:41 web

解析したいソースコードのあるディレクトリに入ります。

# cd /opt/sonarqube/python/

※ 予め、/opt/sonarqube/配下に /python/ディレクトリを作成して、ここにソースコードを置きました。

$ docker cp ./sample.py 86164ce3bf1a:/opt/sonarqube/python/
# cd /opt/sonarqube/python/
# ls -l
total 16
-rwxr-xr-x    1 root     root         14547 Nov 23 23:20 sample.py

SonarQubeの画面に表示されていたSonar-scannerコマンドをCopy&Pasteして、実行します。

コマンドを実行したら、have a break! ☕🍫

ソースコードのstep数によって解析にかかる時間は変わります。
EXEXUTION SUCCESS と表示されたら、解析は完了です。

# sonar-scanner \
>   -Dsonar.projectKey=python-code \
>   -Dsonar.sources=. \
>   -Dsonar.host.url=http://localhost:9000 \
>   -Dsonar.login=<token>
INFO: Scanner configuration file: /opt/sonarqube/sonar-scanner-4.6.2.2472-linux/conf/sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: SonarScanner 4.6.2.2472
INFO: Java 11.0.11 AdoptOpenJDK (64-bit)
INFO: Linux 5.10.60.1-microsoft-standard-WSL2 amd64
INFO: User cache: /root/.sonar/cache
INFO: Scanner configuration file: /opt/sonarqube/sonar-scanner-4.6.2.2472-linux/conf/sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: Analyzing on SonarQube server 8.9.7
INFO: Default locale: "en_US", source code encoding: "UTF-8" (analysis is platform dependent)
INFO: Load global settings
INFO: Load global settings (done) | time=128ms
INFO: Server id: BF41A1F2-AX7ebf1_NZ1ate27xPpT
INFO: User cache: /root/.sonar/cache
INFO: Load/download plugins
INFO: Load plugins index
INFO: Load plugins index (done) | time=73ms
INFO: Load/download plugins (done) | time=2122ms
INFO: Process project properties
INFO: Process project properties (done) | time=19ms
INFO: Execute project builders
INFO: Execute project builders (done) | time=6ms
INFO: Project key: python-code
INFO: Base dir: /opt/sonarqube/python
INFO: Working dir: /opt/sonarqube/python/.scannerwork
INFO: Load project settings for component key: 'python-code'
INFO: Load project settings for component key: 'python-code' (done) | time=47ms
INFO: Load quality profiles
INFO: Load quality profiles (done) | time=147ms
INFO: Load active rules
INFO: Load active rules (done) | time=2884ms
WARN: SCM provider autodetection failed. Please use "sonar.scm.provider" to define SCM of your project, or disable the SCM Sensor in the project settings.
INFO: Indexing files...
INFO: Project configuration:
INFO: 1 file indexed
INFO: Quality profile for py: Sonar way
INFO: ------------- Run sensors on module python-code
INFO: Load metrics repository
INFO: Load metrics repository (done) | time=35ms
INFO: Sensor Python Sensor [python]
INFO: Starting global symbols computation
INFO: 1 source file to be analyzed
INFO: Load project repositories
INFO: Load project repositories (done) | time=29ms
INFO: 0/1 files analyzed, current file: sample.py
INFO: 1/1 source file has been analyzed
INFO: Starting rules execution
INFO: 1 source file to be analyzed
INFO: 1/1 source file has been analyzed
INFO: Sensor Python Sensor [python] (done) | time=11673ms
INFO: Sensor Cobertura Sensor for Python coverage [python]
INFO: Sensor Cobertura Sensor for Python coverage [python] (done) | time=19ms
INFO: Sensor PythonXUnitSensor [python]
INFO: Sensor PythonXUnitSensor [python] (done) | time=1ms
INFO: Sensor CSS Rules [cssfamily]
INFO: No CSS, PHP, HTML or VueJS files are found in the project. CSS analysis is skipped.
INFO: Sensor CSS Rules [cssfamily] (done) | time=1ms
INFO: Sensor JaCoCo XML Report Importer [jacoco]
INFO: 'sonar.coverage.jacoco.xmlReportPaths' is not defined. Using default locations: target/site/jacoco/jacoco.xml,target/site/jacoco-it/jacoco.xml,build/reports/jacoco/test/jacocoTestReport.xml
INFO: No report imported, no coverage information will be imported by JaCoCo XML Report Importer
INFO: Sensor JaCoCo XML Report Importer [jacoco] (done) | time=5ms
INFO: Sensor C# Project Type Information [csharp]
INFO: Sensor C# Project Type Information [csharp] (done) | time=1ms
INFO: Sensor C# Properties [csharp]
INFO: Sensor C# Properties [csharp] (done) | time=2ms
INFO: Sensor JavaXmlSensor [java]
INFO: Sensor JavaXmlSensor [java] (done) | time=1ms
INFO: Sensor HTML [web]
INFO: Sensor HTML [web] (done) | time=7ms
INFO: Sensor VB.NET Project Type Information [vbnet]
INFO: Sensor VB.NET Project Type Information [vbnet] (done) | time=2ms
INFO: Sensor VB.NET Properties [vbnet]
INFO: Sensor VB.NET Properties [vbnet] (done) | time=1ms
INFO: ------------- Run sensors on project
INFO: Sensor Zero Coverage Sensor
INFO: Sensor Zero Coverage Sensor (done) | time=18ms
INFO: SCM Publisher No SCM system was detected. You can use the 'sonar.scm.provider' property to explicitly specify it.
INFO: CPD Executor Calculating CPD for 1 file
INFO: CPD Executor CPD calculation finished (done) | time=39ms
INFO: Analysis report generated in 131ms, dir size=121 KB
INFO: Analysis report compressed in 25ms, zip size=22 KB
INFO: Analysis report uploaded in 95ms
INFO: ANALYSIS SUCCESSFUL, you can browse http://localhost:9000/dashboard?id=python-code
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://localhost:9000/api/ce/task?id=AX7jqzDj-zas7f9hy7O4
INFO: Analysis total time: 17.497 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 21.573s
INFO: Final Memory: 95M/334M
INFO: ------------------------------------------------------------------------

7 解析結果を確認する

SonarQubeに戻ります。

自動的に画面がリロードされて、sonar-scannerで解析した結果が表示されています。
コードに問題がある場合はIssues欄に表示されます。詳細を確認してIssueを解消しましょう。
(今回は、問題が無いソースコードだったため、Issues欄には何も表示されていません。)

Security Hotspots

Code Smells

まとめ

SonarQubeを使用することで、ソースコードの品質を定量的に示してくれるため、コードの改善点が分かります。🙌


付録1 SonarQubeを日本語化する

Japanese Packプラグインのインストールにより、画面を日本語化できます。
しかし、最新バージョンに対応していないためか、日本語化されても中途半端な感じが否めません。

日本語と英語が混在して見づらいと感じる人は、日本語化せずにお使いになったほうが良いかもしれません。

Japanese Packプラグインのインストール:

図中、①→②→③→④の順でplug-inをインストールします。

付録2 便利な使い方

  1. cronで定期実行JOBをつくって、定期的に実行・解析させる
  2. Github等を利用している場合、Webhookを用いて自動で解析させる

参考

Discussion

ログインするとコメントできます