1.k8s部署Sonarqube
1.1部署pgsql作为Sonarqube的数据库
pgsql-sts.yaml
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: sonarqube
spec:
selector:
matchLabels:
app: postgres
serviceName: "postgres-service"
template:
metadata:
labels:
app: postgres
spec:
terminationGracePeriodSeconds: 10
#nodeSelector:
# public: ops
containers:
- name: postgres
image: postgres
imagePullPolicy: IfNotPresent
env:
# put the data into a sub directory to avoid the permission issue in k8s with restricted psp enabled
# more detail refer to https://github.com/goharbor/harbor-helm/issues/756
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
- name: ALLOW_IP_RANGE
value: "0.0.0.0/0"
- name: POSTGRES_DB
value: "sonarDB"
- name: POSTGRES_USER
value: "sonarUser"
- name: POSTGRES_PASSWORD
value: "123456"
ports:
- name: pgport
protocol: TCP
containerPort: 5432
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: database-data
- mountPath: /dev/shm
name: shm-volume
initContainers:
- name: data-migrator
image: postgres #goharbor/harbor-db:v2.7.0
imagePullPolicy: IfNotPresent
command:
- /bin/sh
args:
- -c
- '[ -e /var/lib/postgresql/data/postgresql.conf ] && [ ! -d /var/lib/postgresql/data/pgdata
] && mkdir -m 0700 /var/lib/postgresql/data/pgdata && mv /var/lib/postgresql/data/*
/var/lib/postgresql/data/pgdata/ || true'
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: database-data
- name: data-permissions-ensurer
image: postgres
command:
- /bin/sh
args:
- -c
- chmod -R 700 /var/lib/postgresql/data/pgdata || true
imagePullPolicy: IfNotPresent
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: database-data
securityContext:
runAsUser: 999
fsGroup: 999
volumes:
- emptyDir:
medium: Memory
sizeLimit: 512Mi
name: shm-volume
volumeClaimTemplates:
- metadata:
name: database-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "manage-167nfs"
resources:
requests:
storage: 20Gi
pgsql-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres-service
namespace: sonarqube
labels:
app: postgres
spec:
selector:
app: postgres
ports:
- name: pgport
port: 5432
clusterIP: None
1.2创建pvc作为sonarqube的持久化存储
sonarqube-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sonarqube-data
namespace: sonarqube
spec:
accessModes:
- ReadWriteMany
# 修改为自己的sc
storageClassName: "managed-nfs-storage"
resources:
requests:
storage: 20Gi
sonarqube.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sonarqube
namespace: sonarqube
labels:
app: sonarqube
spec:
replicas: 1
selector:
matchLabels:
app: sonarqube
template:
metadata:
labels:
app: sonarqube
spec:
initContainers:
- name: init-sysctl
image: busybox
imagePullPolicy: IfNotPresent
command: ["sysctl", "-w", "vm.max_map_count=262144"]
securityContext:
privileged: true
containers:
- name: sonarqube
image: sonarqube:lts
ports:
- containerPort: 9000
env:
- name: SONARQUBE_JDBC_USERNAME
value: "sonarUser"
- name: SONARQUBE_JDBC_PASSWORD
value: "123456"
- name: SONARQUBE_JDBC_URL
value: "jdbc:postgresql://postgres-service:5432/sonarDB"
livenessProbe:
httpGet:
path: /sessions/new
port: 9000
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /sessions/new
port: 9000
initialDelaySeconds: 60
periodSeconds: 30
failureThreshold: 6
resources:
limits:
cpu: 2000m
memory: 4096Mi
requests:
cpu: 1000m
memory: 1024Mi
volumeMounts:
- mountPath: /opt/sonarqube/conf
name: data
subPath: conf
- mountPath: /opt/sonarqube/data
name: data
subPath: data
- mountPath: /opt/sonarqube/extensions
name: data
subPath: extensions
volumes:
- name: data
persistentVolumeClaim:
claimName: sonarqube-data
sonarqube-svc.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: sonarqube
name: sonarqube
namespace: sonarqube
spec:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: sonarqube
port: 9000
protocol: TCP
targetPort: 9000
selector:
app: sonarqube
sessionAffinity: None
type: ClusterIP
sonarqube-ingress.ymal
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
# 启用了TLS,则控制器会将 (308) 重定向到 HTTPS
nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
nginx.ingress.kubernetes.io/service-weight: ''
name: sonarqube-ingress
namespace: sonarqube
spec:
ingressClassName: nginx
rules:
- host: sonarqube.XXX.com
http:
paths:
- backend:
service:
name: sonarqube
port:
number: 9000
path: /
pathType: ImplementationSpecific
全部执行
![](https://img-blog.csdnimg.cn/img_convert/5260ed5a1ff97f8cbbc0dfa9585c56ab.png)
通过ingress配置的域名访问默认账号密码admin/admin
登录后因为是全英文的,需要安装中文插件
![](https://img-blog.csdnimg.cn/img_convert/bf41e96bf26947357431f525b0dea26d.png)
1.3SonaQube关闭审查结果上传到SCM功能
![](https://img-blog.csdnimg.cn/img_convert/6f7cd05a40cb8a90a4d6ce3bc55addb9.png)
2.将Sonarqube加入到Jenkins Pipeline中
Jenkins需要添加sonarqube的客户端命令和服务的的信息,所以要先安装sonarqube插件
1. Sonar Quality Gates Plugin
2.SonarQube Scanner for Jenkins
![](https://img-blog.csdnimg.cn/img_convert/f7a714ea4505b3fa4dd4c29b4f2e6ff7.png)
2.1添加sonarqube的客户端命令工具
![](https://img-blog.csdnimg.cn/img_convert/ba6c51f93ff00e3337fd892ba363e958.png)
这里我是用的是sonar-scanner-cli-4.7.0.2747-linux.zip,把文件存放在公司内网的nginx中,构建时下载解压然后使用该命令
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.7.0.2747-linux.zip
2.2添加sonarqube服务端信息
![](https://img-blog.csdnimg.cn/img_convert/7317034e88f7dfc33b9ad63b258b276c.png)
Name:自定义
URL:可以用k8s的SVC或是域名可以访问到的信息,如果用svc则不能通过jenkins的扫描结果直接跳转到sonarqube
Token:这个时非常重要的,要去sonarqube中生成
2.3Sonarqube生成token
![](https://img-blog.csdnimg.cn/img_convert/bee0a7bb9d3395fe293a5b7f608f42dd.png)
配置 》 配置 》 webhook,信息填写完成后会生成token
![](https://img-blog.csdnimg.cn/img_convert/5eda35459ec8faebdc3ae43692b171ca.png)
jenkins上添加对应的凭据
![](https://img-blog.csdnimg.cn/img_convert/0b875b8759d0c08d395134eb58af65ca.png)
配置完成后添加到pipeline中
2.4Pipeline添加Sonarqube扫描
stage('SonarQube代码审查') {
when {
expression {
return (CHKDEPL == 'deploy')
}
}
steps{
script {
env.scannerHome = tool 'sonarqube-scanner'
}
withSonarQubeEnv('sonarqube') {
sh '''
echo ${scannerHome}
ls -l ${scannerHome}/sonar-scanner-4.7.0.2747-linux/bin
pwd
ls -l
${scannerHome}/sonar-scanner-4.7.0.2747-linux/bin/sonar-scanner -Dsonar.projectKey=${PROJECT_NAME} -Dsonar.projectName=${PROJECT_NAME} -Dsonar.projectVersion=${BUILD_NUMBER} -Dsonar.sources=. -Dsonar.java.binaries=. -Dsonar.language=java -Dsonar.sourceEncoding=UTF-8
#需要配置默认的java项,否则运行会报错:
#org.sonar.java.AnalysisException: Your project contains .java files, please provide compiled classes with sonar.java.binaries property, or exclude them from the analysis with sonar.exclusions property
#sonar.java.binaries=.
'''
}
}
}
}
网上很多同学直接使用sonarqube配置文件配置sonarqube的服务端信息,配置文件是sonar-project.properties如下:
# 项目名,如果项目名不存在会自动创建该项目
sonar.projectKey=my_project
# 源码路径,设置为当前目录
sonar.sources=.
# SonarQube 访问地址,根据实际情况填写
sonar.host.url=http://JenkinsIP:9000
# token,在 SonarQube 中创建的 token,只有 SonarQube 开起了强制用户认证,才需要 token,默认情况下,强制用户认证是关闭的。
sonar.login=c4765957e5ada82ebe21a7c2e1f56afbff4059d3
# 语言类型
sonar.language=java
# 二进制文件目录,就是 .class 文件的目录,只有部分项目需要该配置
sonar.java.binaries=collector/target/classes,jmx_prometheus_httpserver/target/classes,jmx_prometheus_javaagent/target/classes
# 源代码编码格式
sonar.sourceEncoding=UTF-8
这里我们不采用这种方式,因为客户端是在k8s的pod中的,每构建一次下载一次,构建完摧毁pod
Pipeline中扫描Java代码使用的命令
${scannerHome}/sonar-scanner-4.7.0.2747-linux/bin/sonar-scanner \
# 配置该Java项目的项目Key
-Dsonar.projectKey=${PROJECT_NAME} \
# 配置该Java项目的项目名称
-Dsonar.projectName=${PROJECT_NAME} \
# 配置该Java项目的版本信息,自定义
-Dsonar.projectVersion=${BUILD_NUMBER} \
# 扫描所在代码目录
-Dsonar.sources=. \
# 这里要配置,否则运行会报错:
#org.sonar.java.AnalysisException: Your project contains .java files, please provide compiled classes with sonar.java.binaries property, or exclude them from the analysis with sonar.exclusions property
-Dsonar.java.binaries=. \
# java html
-Dsonar.language=java \
-Dsonar.sourceEncoding=UTF-8
扫描后可以看到相关信息
![](https://img-blog.csdnimg.cn/img_convert/fb980c03fa23602b606f7e3aa3e9065b.png)
添加对Vue项目的扫描
stage('SonarQube代码审查') {
steps{
script {
env.scannerHome = tool 'sonarqube-scanner'
env.ndjs = tool "nodejs16142"
}
withSonarQubeEnv('sonarqube') {
sh '''
echo ${scannerHome}
echo ${ndjs}
PATH=${PATH}:${ndjs}/bin
ls -l ${scannerHome}/sonar-scanner-4.7.0.2747-linux/bin
pwd
ls -l
${scannerHome}/sonar-scanner-4.7.0.2747-linux/bin/sonar-scanner -Dsonar.projectKey=${PROJECT_NAME} -Dsonar.projectName=${PROJECT_NAME} -Dsonar.projectVersion=${BUILD_NUMBER} -Dsonar.sources=. -Dsonar.java.binaries=. -Dsonar.sourceEncoding=UTF-8
'''
}
}
}
${scannerHome}/sonar-scanner-4.7.0.2747-linux/bin/sonar-scanner \
-Dsonar.projectKey=${PROJECT_NAME} \
-Dsonar.projectName=${PROJECT_NAME} \
-Dsonar.projectVersion=${BUILD_NUMBER} \
-Dsonar.sources=. \
-Dsonar.java.binaries=. \
-Dsonar.sourceEncoding=UTF-8
注意:这里扫描会检查node版本所以要先安装nodejs