GitLab关联SonarQube实现CI/CD代码扫

1. SonarQube 安装

docker 安装参考文档: www.cnblogs.com/shenh/p/134…

sonar 升级官方文档: docs.sonarqube.org/latest/setu…

sonar 支持 gitlab oauth 官方文档:docs.sonarqube.org/latest/anal…

前言: 因为 SonarQube 社区版不支持多分支, 所以需要安装给 SonarQube 安装一个破解插件: sonarqube-community-branch-plugin 来支持多分支. 直接用官方镜像安装安装该插件后, SonarQube检测到第三方插件会退出启动(原因未知, 没有去研究解决), 所以直接使用了 插件作者提供的 SonarQube 镜像.

  • SonarQube 镜像: sonarqube:8.2-community (该镜像安装 sonarqube-community-branch-plugin时启动失败, 所以最后没有使用)
  • SonarQube + sonarqube-community-branch-plugin 镜像: mc1arke/sonarqube-with-community-branch-plugin:8.5-community (最后使用该版本)
  • PostgreSQL 镜像: postgres:12

sonarqube-community-branch-plugin 信息:

  • sonarqube-community-branch-plugin github地址:

github.com/mc1arke/son…

github.com/mc1arke/son…

SonarQube 7.9以上的版本已不再支持mysql 所以使用 postgresql

前置准备

要直接在 sonarqube container 中通过 服务名称(postgres)访问 PostgresSQL, 默认bridge网络内的容器无法解析对方容器的host,通过新建一个docker网络,可以简单解决此问题.

创建网络

docker network create sonarqube-tier
复制代码

安装 postgresql

# mkdir -p /data/docker-volume/postgres/postgresql
# mkdir -p /data/docker-volume/postgres/data
# docker run --name postgres -d -p 5432:5432 --net sonarqube-tier \
-v /data/docker-volume/postgres/postgresql:/var/lib/postgresql \
-v /data/docker-volume/postgres/data:/var/lib/postgresql/data \
-v /etc/localtime:/etc/localtime:ro \
-e POSTGRES_USER=sonar \
-e POSTGRES_PASSWORD=sonar \
-e POSTGRES_DB=sonar \
-e TZ=Asia/Shanghai \
--restart always \
--privileged=true \
--network-alias postgres \
postgres:12
复制代码
  • **-p 5432:5432:**将容器 5432 映射到宿主机端口 5432
  • -v /data/docker-volume/postgres/postgresql:/var/lib/postgresql: 将容器下的 /var/lib/postgresql 挂载到宿主机 /data/docker-volume/postgres/postgresql
  • -v /etc/localtime:/etc/localtime:ro:设置容器与宿主机时间一致
  • --e POSTGRES_USER=sonar:设置数据库用户名
  • -e POSTGRES_PASSWORD=sonar:设置数据库密码
  • -e POSTGRES_DB=sonar:新建db
  • -e TZ=Asia/Shanghai:设置时区
  • --restart always:容器退出时总是重启
  • --privileged=true:挂载主机目录Docker访问出现Permission denied的解决办法
  • --net sonarqube-tier:容器接入自定义网络
  • --network-alias postgres:给容器起个网络别名

查看启动是否成功,数据库是否创建成功:


> docker exec -it postgres psql -U sonar # 进入 postgres, 用户为 sonar
> \l # 列出所有数据库
> \q # 退出
复制代码

安装 SonarQube

  1. 拉取镜像
docker pull mc1arke/sonarqube-with-community-branch-plugin:8.5-community
复制代码
  1. 创建工作目录
mkdir -p /data/sonarqube
复制代码
  1. 修改系统参数
echo "vm.max_map_count=262144" >> /etc/sysctl.conf
sysctl -p
复制代码
  1. 运行一个test容器
docker run -d --name sonartest mc1arke/sonarqube-with-community-branch-plugin:8.5-community
复制代码

将容器内重要文件复制到宿主机

docker cp sonartest:/opt/sonarqube/conf /data/sonarqube
docker cp sonartest:/opt/sonarqube/data /data/sonarqube
docker cp sonartest:/opt/sonarqube/logs /data/sonarqube
docker cp sonartest:/opt/sonarqube/extensions /data/sonarqube
复制代码

然后删除此容器

docker stop sonartest
docker rm sonartest
复制代码

修改文件夹权限

chmod -R 777 /data/sonarqube/
复制代码

5.创建容器并运行

docker run -d --name sonar -p 9000:9000 \
 -e ALLOW_EMPTY_PASSWORD=yes \
 -e SONARQUBE_DATABASE_USER=sonar \
 -e SONARQUBE_DATABASE_NAME=sonar \
 -e SONARQUBE_DATABASE_PASSWORD=sonar \
 -e SONARQUBE_JDBC_URL="jdbc:postgresql://postgres:5432/sonar" \
 --net sonarqube-tier \
 --privileged=true \
 --restart always \
 -v /data/sonarqube/logs:/opt/sonarqube/logs \
 -v /data/sonarqube/conf:/opt/sonarqube/conf \
 -v /data/sonarqube/data:/opt/sonarqube/data \
 -v /data/sonarqube/extensions:/opt/sonarqube/extensions\
 mc1arke/sonarqube-with-community-branch-plugin:8.5-community
复制代码

若这种方式出现连不上数据库 postgres 的问题,可参照下面的方法

找到 /data/sonarqube/conf/ 路径下的文件 sonar.properties,修改如下并保存

# 找到如下配置去掉注释。并赋值 username,password
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar

# 去掉 sonar.jdbc.url 注释,配置url
#----- PostgreSQL 9.3 or greater
# By default the schema named "public" is used. It can be overridden with the parameter "currentSchema".
sonar.jdbc.url=jdbc:postgresql://postgres:5432/sonar
复制代码

使用docker命令创建容器

docker run -d --name sonar -p 9000:9000 \
 --net sonarqube-tier \
 --privileged=true \
 --restart always \
 -v /data/sonarqube/logs:/opt/sonarqube/logs \
 -v /data/sonarqube/conf:/opt/sonarqube/conf \
 -v /data/sonarqube/data:/opt/sonarqube/data \
 -v /data/sonarqube/extensions:/opt/sonarqube/extensions\
 mc1arke/sonarqube-with-community-branch-plugin:8.5-community
复制代码

验证

浏览器输入 http://ip:9000 开始初始化数据库,这个时间过程比较长,大概几分钟。初始化成功后进入登录界面,
账号:admin 
密码:admin

image.png

2. 配置 SonarQube

2.1 安装 SonarQube 中文插件

image.png

如果通过应用市场下载失败, 可以手动下载, 中文语言包下载地址:github.com/SonarQubeCo… 。找到自己版本对应的中文包。将 jar 包放入 /data/sonarqube/extensions/plugins ,重启 sonarqube。

docker restart sonar

2.2 配置 SonarQube 使用 gitlab 账号登录(gitlab OAuth)

SonarQube 官方文档: docs.sonarqube.org/latest/anal…

  1. 在 gitlab 创建 Application
Admin Area -> Applications -> New Application
Name:字面意思
Redirect URI:回调地址。HTTP://SONAR_ADDRES + /oauth2/callback/gitlab;如果版本不同或许可能存在差异,具体可以看官方文档。
Scopes:仅启用委托认证勾选read_user,需要组同步则同时勾选api。
复制代码

image.png

image.png

  • Redirect URI:回调地址。HTTP://SONAR_ADDRES + /oauth2/callback/gitlab;如果版本不同或许可能存在差异,具体可以看官方文档。

  • Scopes:仅启用委托认证勾选read_user,需要组同步则同时勾选api。

提交后保存Application IDSecret

  1. 配置Sonarqube

先配置 Sonar 的服务地址:

配置 -> 通用配置 -> 通用

Server base URL:sonarqube的公共访问地址。
复制代码

image.png

再配置 Sonar Gitlab Oauth

配置 -> 通用配置 -> ALM Integrations -> Gitlab
Enabled:启用。
GitLab URL:Gitlab地址。
Application ID:在Gitlab applications中创建的application id。
Secret:在Gitlab applications中创建的application Secret。
其他选项根据需求勾选。
复制代码

image.png

image.png

确认无误后退出账号,点击登录后则会看到使用gitlab登录。

image.png

3. GitLab 关联 SonarQube 实现代码扫描

3.1 安装 sonar scanner

sonar scanner 下载地址: docs.sonarqube.org/latest/anal…

  • 如果 gitlab runner 执行器为 shell, 在 runner 所在服务器安装
  • 如果 gitlab runner 之行为为 docker, 基于 maven 镜像安装
  1. 安装(linux):
> wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.2.0.1873-linux.zip # 下载 sonar scanner
> unzip sonar-scanner-cli-4.2.0.1873-linux.zip
> mv sonar-scanner-cli-4.2.0.1873-linux /user/local
复制代码
  1. 修改 /etc/profile, 增加下面配置
export SONAR_HOME=/usr/local/sonar-scanner-4.6.2.2472-linux
export PATH=$PATH:$SONAR_HOME/bin
复制代码

然后让配置生效

source /etc/profile
复制代码
  1. 生成 sonar tonken
右上角账号 -> 我的账号 -> 安全 -> 生成令牌
复制代码

image.png

为避免权限问题, 使用管理员账号生产令牌
记住令牌, 只会显示这一次.

  1. 配置 sonar scanner: /usr/local/sonar-scanner-4.6.2.2472-linux/conf/sonar-scanner.properties
# sonar server 服务地址
sonar.host.url=http://172.16.10.52:9000/
# 上一步生产的 sonar tonken
sonar.login=10c0839a8286ab71fdda56f19c9a0bd79e336074

复制代码

3.2 配置 gitlab pipeline

variables:
  # sonner scanner 安装目录
  SCANNER_HOME : "/usr/local/sonar-scanner-4.6.2.2472-linux"
  # 扫描代码路径
  SCAN_DIR : "src"
  # 制品目录
  ARTIFACT_PATH : 'target/*.jar'  
  # maven 仓库地址
  MAVEN_REPO: /data/.m2/repository

stages:
  - compile
  
编译:
  stage: compile
  tags:
    - test
  # interruptible 当新管道在同一分支上启动时,可以取消正在运行的作业。
  interruptible: true
  # 是否允许失败,允许的话如果当前阶段运行失败还会继续执行下一个阶段
  allow_failure: false
  # 运行脚本
  script:
    - java -version
    - mvn -version
    # maven 编译
    - mvn -Dmaven.repo.local=$MAVEN_REPO clean -U package -Dfile.encoding=UTF-8 -DskipTests=true
    # 代码扫描
    - "$SCANNER_HOME/bin/sonar-scanner -Dsonar.projectKey=${CI_PROJECT_NAME} \
                                      -Dsonar.projectName=${CI_PROJECT_NAME} \
                                      -Dsonar.projectVersion=${CI_COMMIT_REF_NAME} \
                                      -Dsonar.ws.timeout=30 \
                                      -Dsonar.projectDescription=${CI_PROJECT_TITLE} \
                                      -Dsonar.links.homepage=${CI_PROJECT_URL} \
                                      -Dsonar.sources=${SCAN_DIR} \
                                      -Dsonar.sourceEncoding=UTF-8 \
                                      -Dsonar.java.binaries=target/classes \
                                      -Dsonar.java.test.binaries=target/test-classes \
                                      -Dsonar.java.surefire.report=target/surefire-reports \
                                      -Dsonar.branch.name=${CI_COMMIT_REF_NAME}"
    - ls -lh target/
  # Maven编译,所以会有Jar包产物,这里定义产物的过期时间
  artifacts:
    name: $PROJECT
    expire_in: 1 days
    paths:
      - target/*.jar
  
复制代码

3.3 查看扫描结果

等待 pipeline 执行完成

image.png

查看代码扫描结果

image.png

4. 问题解决

4.1 Java 项目有多个 module 扫描

参考: www.jianshu.com/p/1a4b8bdf1…

image.png

scanner 扫描配置修改支持多个module:

"$SCANNER_HOME/bin/sonar-scanner -Dsonar.projectKey=${CI_PROJECT_NAME} \
                                      -Dsonar.projectName=${CI_PROJECT_NAME} \
                                      -Dsonar.projectVersion=${CI_COMMIT_REF_NAME} \
                                      -Dsonar.ws.timeout=30 \
                                      -Dsonar.projectDescription=${CI_PROJECT_TITLE} \
                                      -Dsonar.links.homepage=${CI_PROJECT_URL} \
                                      -Dsonar.sources=src/main/java \
                                      -Dsonar.language=java \
                                      -Dsonar.sourceEncoding=UTF-8 \
                                      -Dsonar.java.binaries=target/classes \
                                      -Dsonar.java.test.binaries=target/test-classes \
                                      -Dsonar.java.surefire.report=target/surefire-reports \
                                      -Dsonar.branch.name=${CI_COMMIT_REF_NAME} \
                                      -Dsonar.modules=beta_service-dao,beta_service-manager-api,beta_service-manager,beta_service-service-api,beta_service-service,beta_service-share,beta_service-web,start \
                                      -Dbeta_service-dao.sonar.projectName=beta_service-dao \
                                      -Dbeta_service-manager-api.sonar.projectName=beta_service-manager-api \
                                      -Dbeta_service-manager.sonar.projectName=beta_service-manager \
                                      -Dbeta_service-service-api.sonar.projectName=beta_service-service-api \
                                      -Dbeta_service-service.sonar.projectName=beta_service-service \
                                      -Dbeta_service-web.sonar.projectName=beta_service-web \
                                      -Dstart.sonar.projectName=start"
复制代码

修改点:

image.png