DevOps全链路实战 | 第 10 天:SonarQube 代码质量检查:SonarQube 部署与 GitLab CI 集成

第 10/19 天

引言

在前面几天的实战中,我们已经搭建了 K8s 集群、Harbor 私有镜像仓库、GitLab CE 代码托管平台以及 GitLab CI 流水线,实现了从代码提交到镜像构建的自动化闭环。然而,一条成熟的 DevOps 管道不仅要保证”能构建、能部署”,更要保证”构建出来的代码质量是达标的”。

代码质量是 DevOps 全链路中不可或缺的一环。如果没有自动化质量门禁,低质量代码会随着 CI/CD 流水线一路流向生产环境,技术债务不断积累,最终引发线上故障。SonarQube 正是解决这一问题的利器——它能够对代码进行静态分析,覆盖代码规范、安全漏洞、重复代码、复杂度、测试覆盖率等多个维度,并可以在 CI 流水线中设置质量门禁(Quality Gate),只有通过检查的代码才允许继续部署。

K8s

今天,我们将在 K8s 集群中部署 SonarQube,配置 PostgreSQL 持久化存储,生成 Sonar 令牌与项目配置,然后将其集成到 GitLab CI 流水线中,实现代码提交后自动触发静态分析、质量门禁校验的完整流程。

核心概念

SonarQube 架构概述

SonarQube 采用经典的 Server + Scanner 架构:

  • SonarQube Server:Web 界面 + 计算引擎 + 搜索服务(ElasticSearch),负责项目管理、规则配置、质量门禁定义和报告展示
  • Sonar Scanner:在 CI 流水线中运行的扫描器,负责读取源代码、执行分析、将结果上报给 Server
  • 数据库:SonarQube 支持 PostgreSQL、Oracle、SQL Server 等,PostgreSQL 是 K8s 环境下的首选

质量门禁(Quality Gate)

质量门禁是 SonarQube 最核心的概念之一。它定义了一组条件,例如:

  • 新增代码的 Bug 数量必须为 0
  • 新增代码的安全漏洞等级不得高于 Critical
  • 新增代码的重复率不得超过 3%
  • 新增代码的测试覆盖率不得低于 80%

只有所有条件都满足,Quality Gate 才会返回 PASSED。在 CI 流水线中,我们可以根据这个结果决定是否放行后续的构建和部署步骤。

SonarScanner 工作原理

SonarScanner 在执行时需要以下关键参数:

  • sonar.host.url:SonarQube Server 地址
  • sonar.projectKey:项目唯一标识
  • sonar.projectName:项目显示名称
  • sonar.sources:源代码目录
  • sonar.login:认证令牌

Scanner 执行后会向 Server 上传分析报告,Server 计算引擎处理后返回 Quality Gate 结果。

实战步骤

一、部署 PostgreSQL 数据库

SonarQube 需要外部数据库存储配置和分析数据。我们先在 devops-tools 命名空间部署 PostgreSQL。

💻 代码示例

# 创建命名空间

kubectl create namespace devops-tools

 

# 添加 Bitnami Helm 仓库

helm repo add bitnami https://charts.bitnami.com/bitnami

helm repo update

 

# 安装 PostgreSQL

helm install postgresql bitnami/postgresql

–namespace devops-tools

–set global.postgresql.auth.postgresPassword=SonarPass123

–set global.postgresql.auth.database=sonar

–set primary.persistence.size=10Gi

–set primary.persistence.storageClass=local-path

安装完成后,验证 PostgreSQL Pod 状态:

💻 代码示例

kubectl get pods -n devops-tools -l app.kubernetes.io/name=postgresql

# 期望输出:postgresql-0 1/1 Running 0 2m

二、部署 SonarQube Server

使用官方 Helm Chart 部署 SonarQube Community Edition:

💻 代码示例

# 添加 SonarQube Helm 仓库

helm repo add sonarqube https://SonarSource.github.io/sonarqube-helm-chart

helm repo update

 

# 创建 values 文件

cat > /tmp/sonar-values.yaml << 'EOF'

edition: "community"

image:

tag: "10.6-community"

 

postgresql:

enabled: false # 使用外部 PostgreSQL

 

jdbcOverwrite:

enabled: true

jdbcUrl: "jdbc:postgresql://postgresql.devops-tools.svc.cluster.local:5432/sonar"

jdbcUsername: "postgres"

jdbcPassword: "SonarPass123"

 

persistence:

enabled: true

storageClass: "local-path"

size: "10Gi"

 

sonarProperties:

sonar.ce.workerCount: "2"

sonar.search.javaOpts: "-Xmx1g"

sonar.web.javaOpts: "-Xmx1g"

 

service:

type: NodePort

port: 9000

nodePort: 30900

EOF

 

# 安装 SonarQube

helm install sonarqube sonarqube/sonarqube

–namespace devops-tools

–values /tmp/sonar-values.yaml

–version 10.6.1

三、验证 SonarQube 启动

SonarQube 首次启动需要初始化 ElasticSearch 和数据库,通常需要 3-5 分钟:

💻 代码示例

# 监控启动日志

kubectl logs -f deployment/sonarqube -n devops-tools

 

# 关键日志出现表示启动成功:

# SonarQube is up

# App is ready at /sonarqube

 

# 检查 Pod 状态

kubectl get pods -n devops-tools -l app=sonarqube

启动完成后,通过浏览器访问 http://<节点IP>:30900,使用默认账号 admin / admin 登录,首次登录会要求修改密码。

四、配置 SonarQube 项目与令牌

登录 SonarQube Web 界面后,执行以下配置:

  1. 安装中文语言包:进入 Administration → Marketplace,搜索 “Chinese Pack”,点击安装并重启
  2. 创建项目令牌:进入 My Account → Security → Generate Tokens
💻 代码示例

# 通过 API 创建令牌(假设 SonarQube 已启动)

curl -u admin:YourNewPassword123

-X POST "http://localhost:30900/api/user_tokens/generate"

-d "name=gitlab-ci-token&type=PROJECT_ANALYSIS_TOKEN&projectKey=my-java-app"

 

# 响应示例:

# {"token":"squ_xxxxxxxxxxxxxxxxxxxxxxxxx","type":"PROJECT_ANALYSIS_TOKEN",…}

将返回的 squ_ 开头的令牌保存好,后续 GitLab CI 需要用到。

五、配置质量门禁

SonarQube 默认提供了一个标准 Quality Gate,我们可以自定义更严格的质量门禁:

💻 代码示例

{

"name": "DevOps Production Gate",

"conditions": [

{

"metric": "new_vulnerabilities",

"operator": "GT",

"errorThreshold": "0",

"statusOnError": true

},

{

"metric": "new_bugs",

"operator": "GT",

"errorThreshold": "0",

"statusOnError": true

},

{

"metric": "new_code_smells",

"operator": "GT",

"errorThreshold": "5",

"statusOnError": true

},

{

"metric": "new_duplicated_lines_density",

"operator": "GT",

"errorThreshold": "3",

"statusOnError": true

},

{

"metric": "new_coverage",

"operator": "LT",

"errorThreshold": "80",

"statusOnError": true

}

]

}

通过 API 创建并应用:

💻 代码示例

# 创建自定义质量门禁

curl -u admin:YourNewPassword123

-X POST "http://localhost:30900/api/qualitygates/create"

-d "name=DevOps Production Gate"

 

# 设置为默认质量门禁

curl -u admin:YourNewPassword123

-X POST "http://localhost:30900/api/qualitygates/set_default"

-d "name=DevOps Production Gate"

六、GitLab CI 集成配置

这是全链路集成的关键步骤。我们需要在 GitLab 中配置 CI 变量,并修改 .gitlab-ci.yml 加入 SonarQube 扫描阶段。

首先,在 GitLab 项目中添加 CI/CD 变量(Settings → CI/CD → Variables):

  • SONAR_HOST_URL:值为 http://sonarqube.devops-tools.svc.cluster.local:9000
  • SONAR_TOKEN:值为前面生成的 squ_xxxxx 令牌

然后编写 .gitlab-ci.yml,在构建阶段之后加入 SonarQube 分析:

💻 代码示例

stages:

– build

– test

– sonar

– deploy

 

variables:

IMAGE_NAME: harbor.stellardata.top/devops/my-java-app

IMAGE_TAG: $CI_COMMIT_SHORT_SHA

 

kaniko-build:

stage: build

image:

name: gcr.io/kaniko-project/executor:debug

entrypoint: [""]

script:

– /kaniko/executor

–context="${CI_PROJECT_DIR}"

–dockerfile="${CI_PROJECT_DIR}/Dockerfile"

–destination="${IMAGE_NAME}:${IMAGE_TAG}"

–skip-tls-verify

only:

– main

 

sonarqube-check:

stage: sonar

image:

name: sonarsource/sonar-scanner-cli:latest

entrypoint: [""]

variables:

SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"

GIT_DEPTH: "0"

cache:

key: "${CI_JOB_NAME}"

paths:

– .sonar/cache

script:

– sonar-scanner

-Dsonar.projectKey=my-java-app

-Dsonar.projectName="My Java App"

-Dsonar.sources=src

-Dsonar.host.url=${SONAR_HOST_URL}

-Dsonar.login=${SONAR_TOKEN}

-Dsonar.qualitygate.wait=true

-Dsonar.java.binaries=target/classes

allow_failure: false

only:

– main

关键参数说明:

  • sonar.qualitygate.wait=true:阻塞等待 Quality Gate 结果返回。如果门禁失败,CI Job 将报错退出
  • allow_failure: false:质量门禁未通过时,整个流水线中止,阻止后续 deploy 阶段执行
  • sonar.java.binaries:Java 项目必须指定编译产物路径,否则无法执行部分规则检查
  • GIT_DEPTH: "0":完整克隆 Git 历史,SonarQube 需要计算新增代码的变更差异

七、验证 CI 集成效果

提交代码触发流水线后,观察 GitLab CI 的执行结果:

💻 代码示例

# 在 SonarQube 中查看项目分析结果

curl -u admin:YourNewPassword123

"http://localhost:30900/api/components/show?component=my-java-app"

 

# 查询质量门禁状态

curl -u admin:YourNewPassword123

"http://localhost:30900/api/qualitygates/project_status?projectKey=my-java-app"

 

# 响应示例:

# {

# "projectStatus": {

# "status": "OK",

# "conditions": [

# {"status": "OK", "metricKey": "new_bugs", …},

# {"status": "OK", "metricKey": "new_vulnerabilities", …}

# ]

# }

# }

当 status 为 OK 时,Quality Gate 通过,CI 流水线继续执行 deploy 阶段;当 status 为 ERROR 时,流水线在 sonar 阶段中止,阻止有问题的代码进入生产环境。

常见问题

1. SonarQube Pod 启动失败,日志报 vm.max_map_count 不足

SonarQube 内置的 ElasticSearch 要求宿主机 vm.max_map_count 至少为 262144。在所有 K8s 节点上执行:

💻 代码示例

sysctl -w vm.max_map_count=262144

echo "vm.max_map_count=262144" >> /etc/sysctl.conf

也可以通过安装 initContainer 的 sysctl 修改来处理,但生产环境推荐直接在节点层面永久设置。

2. SonarScanner 报错 “Insufficient privileges”

确认 CI 变量中 SONAR_TOKEN 使用的是 PROJECT_ANALYSIS_TOKEN 类型,且该令牌对应的用户对目标项目有 “Execute Analysis” 权限。建议在 SonarQube 中创建专用的 CI 账号,避免使用 admin 账号。

3. Quality Gate 状态一直显示 PENDING

这是因为 sonar.qualitygate.wait=true 未配置,Scanner 不会等待分析结果。另外也可能是 SonarQube Server 的 Compute Engine 负载过高。如果项目较大,可以适当增加 sonar.ce.workerCount 来加速分析。

4. Java 项目扫描报 “Class not found”

SonarQube 的部分 Java 规则需要读取编译后的 .class 文件。确保 sonar.java.binaries 参数指向正确的编译产物目录,且在 sonar 阶段之前已经执行了 mvn compile 或 gradle build。

总结

今天我们完成了 SonarQube 在 K8s 中的完整部署,并将其深度集成到 GitLab CI 流水线中。核心要点回顾:

  1. PostgreSQL + SonarQube 部署:使用 Helm 在 devops-tools 命名空间快速部署,配置 NodePort 方便访问
  2. 质量门禁机制:自定义 Quality Gate 条件,将代码质量检查从”事后审查”变为”流水线门禁”
  3. GitLab CI 集成:通过 CI 变量注入 SonarQube 配置,使用 sonar-scanner-cli 镜像执行分析,qualitygate.wait=true 实现阻塞式门禁校验
  4. 闭环保障:质量门禁未通过时,流水线在 sonar 阶段中止,有问题的代码无法继续部署

至此,我们的 DevOps 全链路已经补齐了”代码质量”这一关键环节。从代码提交 → Kaniko 构建镜像 → SonarQube 质量检查 → Harbor 推送 → Argo CD 部署,一条带有质量门禁的完整 CI/CD 管道已经成型。

下期预告

明天我们将进入可观测性篇章,发布第 11 天:Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集。届时将在 K8s 集群中部署 Prometheus 全套监控栈,配置 ServiceMonitor 自动发现服务指标,为后续的 Grafana 看板和告警系统奠定数据基础。

系列大纲

  1. 全链路架构总览:从代码提交到灰度发布的完整管道设计
  2. K8s 集群与网络基础:kubeadm 离线部署与 Cilium 网络插件
  3. Harbor 私有镜像仓库部署与验证:Helm 安装与镜像推送
  4. GitLab CE 自托管部署:代码仓库与项目管理平台
  5. GitLab Runner 配置:K8s Executor 与 RBAC 权限设置
  6. GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建
  7. Harbor 镜像版本管理与 Tag 策略配置
  8. Argo CD 部署与 GitOps 配置仓库创建
  9. CI 与 CD 联动:从代码提交到部署的全自动闭环
  10. SonarQube 代码质量检查:SonarQube 部署与 GitLab CI 集成(今天)
  11. Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集
  12. Grafana 看板搭建:K8s 标准面板与自定义业务看板
  13. 告警规则与 Alertmanager:钉钉/邮件通知渠道配置
  14. Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义
  15. 金丝雀发布实战:setWeight 流量分割与 pause 步骤
  16. AnalysisTemplate 指标分析与自动回滚机制
  17. 全链路端到端演示:代码提交→构建→代码检查→灰度→监控→告警完整流程
  18. 生产化加固要点:Harbor/GitLab/Argo CD/SonarQube 高可用方案
  19. 供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签
微信二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像 - 恒星
欢迎您留下宝贵的见解!
提交
头像 - 恒星

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容