DockerでSonarQubeを構築してPythonコードを解析する
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 便利な使い方
- cronで定期実行JOBをつくって、定期的に実行・解析させる
- Github等を利用している場合、Webhookを用いて自動で解析させる
Discussion