第 10/19 天
引言
在前面几天的实战中,我们已经搭建了 K8s 集群、Harbor 私有镜像仓库、GitLab CE 代码托管平台以及 GitLab CI 流水线,实现了从代码提交到镜像构建的自动化闭环。然而,一条成熟的 DevOps 管道不仅要保证”能构建、能部署”,更要保证”构建出来的代码质量是达标的”。
代码质量是 DevOps 全链路中不可或缺的一环。如果没有自动化质量门禁,低质量代码会随着 CI/CD 流水线一路流向生产环境,技术债务不断积累,最终引发线上故障。SonarQube 正是解决这一问题的利器——它能够对代码进行静态分析,覆盖代码规范、安全漏洞、重复代码、复杂度、测试覆盖率等多个维度,并可以在 CI 流水线中设置质量门禁(Quality Gate),只有通过检查的代码才允许继续部署。

今天,我们将在 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 界面后,执行以下配置:
- 安装中文语言包:进入 Administration → Marketplace,搜索 “Chinese Pack”,点击安装并重启
- 创建项目令牌:进入 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:9000SONAR_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 流水线中。核心要点回顾:
- PostgreSQL + SonarQube 部署:使用 Helm 在
devops-tools命名空间快速部署,配置 NodePort 方便访问 - 质量门禁机制:自定义 Quality Gate 条件,将代码质量检查从”事后审查”变为”流水线门禁”
- GitLab CI 集成:通过 CI 变量注入 SonarQube 配置,使用
sonar-scanner-cli镜像执行分析,qualitygate.wait=true实现阻塞式门禁校验 - 闭环保障:质量门禁未通过时,流水线在 sonar 阶段中止,有问题的代码无法继续部署
至此,我们的 DevOps 全链路已经补齐了”代码质量”这一关键环节。从代码提交 → Kaniko 构建镜像 → SonarQube 质量检查 → Harbor 推送 → Argo CD 部署,一条带有质量门禁的完整 CI/CD 管道已经成型。
下期预告
明天我们将进入可观测性篇章,发布第 11 天:Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集。届时将在 K8s 集群中部署 Prometheus 全套监控栈,配置 ServiceMonitor 自动发现服务指标,为后续的 Grafana 看板和告警系统奠定数据基础。
系列大纲
- 全链路架构总览:从代码提交到灰度发布的完整管道设计
- K8s 集群与网络基础:kubeadm 离线部署与 Cilium 网络插件
- Harbor 私有镜像仓库部署与验证:Helm 安装与镜像推送
- GitLab CE 自托管部署:代码仓库与项目管理平台
- GitLab Runner 配置:K8s Executor 与 RBAC 权限设置
- GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建
- Harbor 镜像版本管理与 Tag 策略配置
- Argo CD 部署与 GitOps 配置仓库创建
- CI 与 CD 联动:从代码提交到部署的全自动闭环
- SonarQube 代码质量检查:SonarQube 部署与 GitLab CI 集成(今天)
- Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集
- Grafana 看板搭建:K8s 标准面板与自定义业务看板
- 告警规则与 Alertmanager:钉钉/邮件通知渠道配置
- Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义
- 金丝雀发布实战:setWeight 流量分割与 pause 步骤
- AnalysisTemplate 指标分析与自动回滚机制
- 全链路端到端演示:代码提交→构建→代码检查→灰度→监控→告警完整流程
- 生产化加固要点:Harbor/GitLab/Argo CD/SonarQube 高可用方案
- 供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签

















暂无评论内容