SonarQube 实例部署
本文档介绍 SonarQube Operator 的订阅以及部署 SonarQube 实例的功能。
Namespace Security Policy 限制
由于以下原因,SonarQube 不支持在 SPA(Security Policy Admission)策略设置为 Restricted 或 Baseline 的命名空间中部署:
- Init Container 需要 Root 权限:SonarQube 使用 init container 初始化 PVC 目录权限,而
Restricted 策略不允许 root 权限。
- InitSysctl 需要特权权限:默认情况下,SonarQube 使用 initSysctl container 配置 Elasticsearch 所需的 sysctl 参数(例如
vm.max_map_count 和 fs.file-max)。这需要 privileged 权限才能修改系统级内核参数。
建议:为 SonarQube 部署创建专用命名空间,并确保其安全策略设置为 privileged。
前提条件
部署规划
SonarQube 支持多种资源配置,以适配不同客户场景。在不同场景下,所需的资源、配置等会有显著差异。因此,本节介绍在部署 SonarQube 实例之前,需要在部署规划中考虑哪些方面,以及各个决策点会产生什么影响,以便用户基于这些信息进行后续具体的实例部署。
基本信息
- 平台提供的 SonarQube Operator 基于社区官方 SonarQube Chart,并增强了 IPv6 支持和安全漏洞修复等企业能力。其功能上与社区版本完全兼容,在用户体验上则通过可选、可定制模板等方式提升了 SonarQube 部署的便利性。
部署前资源规划
部署前资源规划是指在部署之前做出决策,并在部署过程中生效。
有关环境资源的更多建议,请参考官方文档: https://docs.sonarsource.com/sonarqube-community-build/server-installation/server-host-requirements
不要使用网络存储作为存储后端
在生产环境中,不要将基于网络存储的 StorageClass、PVC 或其他远程挂载存储用于 SonarQube 持久化。SonarQube 内部使用 Elasticsearch,官方 SonarSource 主机要求说明中指出,不应为 SonarQube 的 data 目录使用 NFS、SMB/CIFS 或 NAS 等远程挂载存储,因为这类存储通常更慢、延迟波动更大,并且会成为单点故障。官方文档还将受影响路径描述为 <sonarqubeHome>/data,该路径用于存放 Elasticsearch 索引,需要较高的 I/O 性能。
在规划 SonarQube 存储时,应使用本地节点存储或具有良好读写性能的块存储,而不是基于网络存储的存储类。如果在部署模板中选择了 StorageClass,请与存储提供商确认其后端不是远程挂载文件存储。
相关参考:
实例部署
从 Quickstart Template 模板部署
该模板用于快速创建轻量级 SonarQube 实例,适用于开发和测试场景,不建议用于生产环境。
- 计算资源:800m CPU,4 Gi 内存
- 存储:使用节点本地存储,配置存储节点 IP 和路径
- 网络访问:使用 NodePort 访问服务,与存储共享节点 IP,并指定端口
从 Production Template 模板部署
该模板用于快速创建生产级 SonarQube 实例,适用于生产场景,推荐用于生产环境。
- 计算资源:8 CPU 核,16 Gi 内存
- 存储:使用 PVC 存储,配置 StorageClass
- 网络访问:使用 Domain 访问服务。
通过 YAML 部署
资源配置
SonarQube 只需配置整体资源即可,例如:
spec:
helmValues:
resources:
limits:
cpu: 800m
memory: 4Gi
requests:
cpu: 400m
memory: 2Gi
更多信息请参考 SonarQube Chart 中的资源说明
网络配置
网络配置分为两类:
- 基于 ingress 的网络配置
- 基于 NodePort 的网络配置
基于 ingress 的网络配置同时支持 https 和 http 协议。需要提前在集群中部署 ingress controller。
spec:
helmValues:
ingress:
enabled: true
hosts:
- name: test-ingress-https.example.com
tls:
- secretName: test-tls-cert
hosts:
- test-ingress-http.example.com
基于 NodePort 的网络配置:
spec:
helmValues:
service:
name: sonarqube
type: NodePort
nodePort: <nodeport.http>
存储配置
存储配置主要分为三类:
- 基于 StorageClass 的存储配置
- 基于 PVC 的存储配置
- 基于 HostPath 的存储配置
基于 StorageClass 的存储配置:
Warning
不要为 SonarQube 持久化选择基于网络存储的 StorageClass。请使用低延迟、读写性能良好的存储后端。
spec:
helmValues:
persistence:
enabled: true
storageClass: <storage-class.rwm> ## StorageClass needs to be created in advance
size: 10Gi
基于 PVC 的存储配置:
spec:
helmValues:
persistence:
enabled: true
existingClaim: sonarqube-pvc ## PVC needs to be created in advance
基于 HostPath 的存储配置:
spec:
helmValues:
nodeSelector:
kubernetes.io/hostname: <node.random> ## Select the deployment node
persistence:
enabled: false
host:
nodeName: <node.random> ## Name of the node
path: /tmp/sonarqube-<template.{{randAlphaNum 10}}> ## Select the deployment node and specify the storage path
PostgreSQL 访问凭据配置
需要先在平台上创建一个 PostgreSQL 实例,并在 PostgreSQL 中创建一个数据库供使用。
SonarQube 25.1.0 支持的 PostgreSQL 版本为 13 到 17。
通过配置具有特定格式内容的 secret 资源来实现 PostgreSQL 访问。详细信息请参见 配置 PostgreSQL 和账户访问凭据。
在 SonarQube YAML 中使用 secret 作为访问 PG 的凭据:
spec:
helmValues:
postgresql:
enabled: false ## Disable the default PostgreSQL instance
jdbcOverwrite:
enable: true
jdbcSecretName: postgres-password ## Credentials for connecting to PG
jdbcUrl: jdbc:postgresql://<pg.host>:<pg.port>/<pg.database>?socketTimeout=1500 ## Address for connecting to PG
jdbcUsername: postgres ## PG access user
管理员账户配置
初始化 SonarQube 实例时,需要配置管理员账户及其密码。这通过配置 secret 资源完成。详细信息请参见 配置 PostgreSQL 和账户访问凭据。
通过 YAML 将其指定给 SonarQube:
spec:
helmValues:
account:
adminPasswordSecretName: sonarqube-root-password
完整 YAML 示例
NodePort、PVC、PostgreSQL、管理员账户
apiVersion: operator.alaudadevops.io/v1alpha1
kind: Sonarqube
metadata:
name: sonarqube-demo
spec:
helmValues:
prometheusExporter: # Disable the default prometheus monitoring, jar packages need to be added in advance when starting
enabled: false
resources: # Set resource limits
limits:
cpu: 800m
memory: 4Gi
requests:
cpu: 400m
memory: 2Gi
postgresql: # Disable the default PostgreSQL instance
enabled: false
jdbcOverwrite: # Use a pre-created PostgreSQL instance
enable: true
jdbcSecretName: postgres-password
jdbcUrl: jdbc:postgresql://<pg.host>:<pg.port>/<pg.database>?socketTimeout=1500
jdbcUsername: <pg.username>
service: # Use NodePort to expose the SonarQube instance
name: sonarqube
type: NodePort
nodePort: <nodeport.http>
account: # Set Root password
adminPasswordSecretName: sonarqube-root-password
persistence: # Use PVC for storage mounting
enabled: true
existingClaim: sonarqube-pvc
SSO 配置
配置 SSO 包括以下步骤:
在 global 集群中注册一个 SSO 身份验证客户端
- 在 global 集群中创建以下 OAuth2Client 资源以注册 SSO 身份验证客户端。
- 配置 SonarQube 实例使用 SSO 身份验证
apiVersion: dex.coreos.com/v1
kind: OAuth2Client
name: OIDC
metadata:
name: onxw4ylsof2wezjnmrsxrs7sttsiiirdeu # This value is calculated based on the hash of the id field, online calculator: https://go.dev/play/p/QsoqUohsKok
namespace: cpaas-system
id: sonarqube-dex # Client id
public: false
redirectURIs:
- <sonarqube-host>/* # SonarQube authentication callback address, where <sonarqube-host> is replaced with the access address of the SonarQube instance
secret: Z2l0bGFiLW9mZmljaWFsLTAK # Client secret
spec: {}
将 SSO 配置添加到 SonarQube 实例:
spec:
helmValues:
sonarProperties:
sonar.core.serverBaseURL: <sonarqube url>
sonar.forceAuthentication: false
sonar.auth.oidc.enabled: true
sonar.auth.oidc.issuerUri: <platform-url>/dex
sonar.auth.oidc.clientId.secured: sonarqube-dex # Client id
sonar.auth.oidc.clientSecret.secured: Z2l0bGFiLW9mZmljaWFsLTAK # Client secret
sonar.auth.oidc.loginStrategy: Preferred username
sonar.auth.oidc.providerConfiguration: '{"issuer":"<platform-url>/dex","authorization_endpoint":"<platform-url>/dex/auth","token_endpoint":"<platform-url>/dex/token","jwks_uri":"<platform-url>/dex/keys","response_types_supported":["code","id_token","token"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"],"scopes_supported":["openid","email","groups","profile","offline_access"],"token_endpoint_auth_methods_supported":["client_secret_basic"],"claims_supported":["aud","email","email_verified","exp","iat","iss","locale","name","sub"]}'
为使用自签名证书的平台启用 SSO
如果平台通过 https 访问并使用自签名证书,则需要将该自签名证书的 CA 挂载到 SonarQube 实例。方法如下:
在 global 集群的 cpaas-system 命名空间中,找到名为 dex.tls 的 secret,从该 secret 中获取 ca.crt 和 tls.crt 内容,保存为新的 secret,并将其创建到 SonarQube 实例所在的命名空间中。
apiVersion: v1
data:
ca.crt: <base64 encode data>
tls.crt: <base64 encode data>
kind: Secret
metadata:
name: dex-tls
namespace: cpaas-system
编辑 SonarQube 实例以使用此 CA:
spec:
helmValues:
caCerts:
enabled: true
secret: dex-tls
在纯 IPv6 集群中使用
在纯 IPv6 集群环境中部署时,由于 Java 默认支持双栈,因此需要显式配置 IPv6 协议设置。添加以下配置以确保连通性:
spec:
helmValues:
env:
- name: JAVA_TOOL_OPTIONS
value: '-Djava.net.preferIPv6Addresses=true'
sonarProperties:
sonar.cluster.node.search.host: '[::1]'
sonar.cluster.node.es.host: '[::1]'
sonar.web.javaAdditionalOpts: '-javaagent:/opt/sonarqube/extensions/plugins/sonarqube-community-branch-plugin-26.1.0.jar=web -Djava.net.preferIPv6Addresses=true'