本文中PostgreSQL使用 Ceph RBD 作为持久卷,SonarQube使用 NFS 作为持久卷。

安装 PostgreSQL

创建 PostgreSQL Secret

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ echo -n sonar | base64
c29uYXI=

$ echo -n Passw0rd | base64
UGFzc3cwcmQ=

$ echo -n sonardb | base64
c29uYXJkYg==

#与 echo -n 作用相同
$ tr --delete '\n' < mysql-root-pwd.txt > .strippedmysql-root-pwd.txt && mv .strippedmysql-root-pwd.txt mysql-root-pwd.txt

OR
$ kubectl create secret generic mysql-secrets --from-literal=root-user=root --from-literal=root-password=Passw0rd --from-literal=mysql-database=sonardb --from-literal=mysql-user=sonar --from-literal=mysql-password=sonar -n sonar

OR
$ kubectl create secret generic mysql-root-pwd --from-file=mysql-root-pwd.txt -n sonar
1
2
3
4
5
6
7
8
9
10
11
12
$ cat pg-secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: postgres-secrets
namespace: sonar
labels:
app: postgres
data:
postgres-db: c29uYXJkYg==
postgres-user: c29uYXI=
postgres-password: c29uYXI=
1
$ kubectl create -f pg-secrets.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ kubectl get secrets -n sonar
NAME TYPE DATA AGE
ceph-secret kubernetes.io/rbd 1 8d
default-token-fzbwt kubernetes.io/service-account-token 3 16d
postgres-secrets Opaque 3 3d

$ kubectl describe secrets/postgres-secrets -n sonar
Name: postgres-secrets
Namespace: sonar
Labels: app=postgres
Annotations: <none>

Type: Opaque

Data
====
postgres-db: 7 bytes
postgres-password: 5 bytes
postgres-user: 5 bytes

部署 PostgreSQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$ cat pg-statefulset.yaml 
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: sonar
labels:
app: postgres
spec:
ports:
- port: 5432
clusterIP: None
selector:
app: postgres
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: postgres
namespace: sonar
labels:
app: postgres
spec:
serviceName: postgres
replicas: 1
template:
metadata:
labels:
app: postgres
spec:
terminationGracePeriodSeconds: 10
containers:
- name: postgresql
image: 10.0.77.16/library/postgres:10.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5432
name: postgresql
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secrets
key: postgres-user
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: postgres-secrets
key: postgres-db
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secrets
key: postgres-password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-volume
mountPath: /var/lib/postgresql/data
imagePullSecrets:
- name: registrykey
volumeClaimTemplates:
- metadata:
name: postgres-volume
spec:
accessModes:
- ReadWriteOnce
storageClassName: ceph-postgres
resources:
requests:
storage: 10Gi
1
$ kubectl create -f pg-statefulset.yaml

volumeClaimTemplates中定义了PVC,并指定了storageClassName: "ceph-postgres",会根据PVC动态创建Pod所需的PV。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ kubectl get pvc -n sonar
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
postgres-volume-postgres-0 Bound pvc-df69da97-2e7a-11e8-b7b9-0050568879ea 10Gi RWO ceph-postgres 5m

$ kubectl get pv -n sonar
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-df69da97-2e7a-11e8-b7b9-0050568879ea 10Gi RWO Delete Bound sonar/postgres-volume-postgres-0 ceph-postgres 7m

$ kubectl describe persistentvolume pvc-df69da97-2e7a-11e8-b7b9-0050568879ea
Name: pvc-df69da97-2e7a-11e8-b7b9-0050568879ea
Labels: <none>
Annotations: kubernetes.io/createdby=rbd-dynamic-provisioner
pv.kubernetes.io/bound-by-controller=yes
pv.kubernetes.io/provisioned-by=kubernetes.io/rbd
StorageClass: ceph-postgres
Status: Bound
Claim: sonar/postgres-volume-postgres-0
Reclaim Policy: Delete
Access Modes: RWO
Capacity: 10Gi
Message:
Source:
Type: RBD (a Rados Block Device mount on the host that shares a pod's lifetime)
CephMonitors: [10.0.77.17:6789]
RBDImage: kubernetes-dynamic-pvc-df734e53-2e7a-11e8-93af-00505688047e
FSType: xfs
RBDPool: rbd
RadosUser: admin
Keyring: /etc/ceph/keyring
SecretRef: &{ceph-secret }
ReadOnly: false
Events: <none>

部署 Sonarqube

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
$ cat sonar-rc.yaml
apiVersion: v1
kind: Service
metadata:
name: sonar
namespace: sonar
spec:
type: NodePort
ports:
- port: 9000
protocol: TCP
nodePort: 30001
selector:
name: sonar
---
apiVersion: v1
kind: ReplicationController
metadata:
name: sonar
namespace: sonar
labels:
name: sonar
spec:
replicas: 1
selector:
name: sonar
template:
metadata:
labels:
name: sonar
spec:
containers:
- name: sonar
image: 10.0.77.16/library/sonarqube:6.7
env:
- name: SONARQUBE_JDBC_USERNAME
valueFrom:
secretKeyRef:
name: postgres-secrets
key: postgres-user
- name: SONARQUBE_JDBC_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secrets
key: postgres-password
- name: SONARQUBE_JDBC_URL
value: jdbc:postgresql://postgres:5432/sonardb
ports:
- containerPort: 9000
volumeMounts:
- mountPath: "/opt/sonarqube/conf"
name: sonar-conf
- mountPath: "/opt/sonarqube/data"
name: sonar-data
- mountPath: "/opt/sonarqube/extensions"
name: sonar-extensions
- mountPath: "/opt/sonarqube/logs"
name: sonar-logs
volumes:
- name: sonar-conf
nfs:
server: 10.0.77.16
path: "/nfs/sonar/conf"
- name: sonar-data
nfs:
server: 10.0.77.16
path: "/nfs/sonar/data"
- name: sonar-extensions
nfs:
server: 10.0.77.16
path: "/nfs/sonar/extensions"
- name: sonar-logs
nfs:
server: 10.0.77.16
path: "/nfs/sonar/logs"
1
$ kubectl create -f sonar-rc.yaml

使用默认用户、密码 admin/admin 访问SonarQube http://k8s-node-ip:30001

SonarQube Plugins

Plugin Library

SonarQube v6.7预装好的Plugins如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ kubectl get pods -n sonar
NAME READY STATUS RESTARTS AGE
postgres-0 1/1 Running 0 15h
sonar-wmvnf 1/1 Running 0 15h

$ kubectl exec -n sonar sonar-wmvnf -it -- bash
root@sonar-wmvnf:/opt/sonarqube/extensions/plugins# ls -l
total 40464
-rw-r--r-- 1 sonarqube sonarqube 2703958 Nov 6 08:12 sonar-csharp-plugin-6.5.0.3766.jar
-rw-r--r-- 1 sonarqube sonarqube 1618672 Nov 6 08:12 sonar-flex-plugin-2.3.jar
-rw-r--r-- 1 sonarqube sonarqube 6759535 Nov 6 15:31 sonar-java-plugin-4.15.0.12310.jar
-rw-r--r-- 1 sonarqube sonarqube 3355702 Nov 6 08:12 sonar-javascript-plugin-3.2.0.5506.jar
-rw-r--r-- 1 sonarqube sonarqube 3022870 Nov 6 16:50 sonar-php-plugin-2.11.0.2485.jar
-rw-r--r-- 1 sonarqube sonarqube 4024311 Nov 6 08:12 sonar-python-plugin-1.8.0.1496.jar
-rw-r--r-- 1 sonarqube sonarqube 3625962 Nov 6 08:12 sonar-scm-git-plugin-1.3.0.869.jar
-rw-r--r-- 1 sonarqube sonarqube 6680471 Nov 6 08:12 sonar-scm-svn-plugin-1.6.0.860.jar
-rw-r--r-- 1 sonarqube sonarqube 2250667 Nov 6 08:12 sonar-typescript-plugin-1.1.0.1079.jar
-rw-r--r-- 1 sonarqube sonarqube 7368250 Nov 6 08:12 sonar-xml-plugin-1.4.3.1027.jar

SonarQube Scanner

Analyzing with SonarQube Scanner

1
2
3
4
5
root@sonar-wmvnf:~# cd /opt/sonarqube/extensions/downloads
root@sonar-wmvnf:/opt/sonarqube/extensions/downloads# wget https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.1.0.1141-linux.zip
root@sonar-wmvnf:/opt/sonarqube/extensions/downloads# unzip sonar-scanner-cli-3.1.0.1141-linux.zip -d /opt/sonarqube
root@sonar-wmvnf:/opt/sonarqube# mv sonar-scanner-3.1.0.1141-linux sonar-scanner
root@sonar-wmvnf:/opt/sonarqube# chown -R sonarqube:sonarqube sonar-scanner/

增加 SonarQube Scanner 的环境变量

1
2
3
4
5
6
7
$ kubectl cp sonar/sonar-wmvnf:/etc/profile ./
tar: Removing leading `/' from member names

$ vi profile
......
/opt/sonarqube/sonar-scanner/bin
......
1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl cp ./profile sonar/sonar-wmvnf:/etc/

root@sonar-wmvnf:/opt/sonarqube# source /etc/profile
root@sonar-wmvnf:/opt/sonarqube# sonar-scanner -h
INFO:
INFO: usage: sonar-scanner [options]
INFO:
INFO: Options:
INFO: -D,--define <arg> Define property
INFO: -h,--help Display help information
INFO: -v,--version Display version information
INFO: -X,--debug Produce execution debug output

配置 SonarQube Scanner 属性

1
2
3
4
$ cat sonar-scanner.properties

sonar.host.url=http://localhost:9000
sonar.sourceEncoding=UTF-8
1
$ kubectl cp ./sonar-scanner.properties sonar/sonar-wmvnf:/opt/sonarqube/sonar-scanner/conf/sonar-scanner.properties

配置 Python 代码分析

1
2
3
4
5
6
7
8
9
10
11
$ cat sonar-project.properties
sonar.projectKey=my:python
sonar.projectName=python
sonar.projectVersion=1.0
sonar.sources=.
sonar.sourceEncoding=UTF-8

sonar.language=py
#sonar.python.pylint=/usr/bin/pylint
#sonar.python.pylint_config=.pylintrc
#sonar.python.pylint.reportPath=./pylint-report.txt
1
2
3
4
5
root@sonar-wmvnf:/opt/sonarqube/conf# mkdir python

$ kubectl cp ./sonar-project.properties sonar/sonar-wmvnf:/opt/sonarqube/conf/python/sonar-project.properties

root@sonar-wmvnf:/opt/sonarqube/conf# chown -R sonarqube:sonarqube python

执行分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
root@sonar-wmvnf:/opt/sonarqube/conf/python# sonar-scanner -Dsonar.projectKey=my:python -Dsonar.sources=.

INFO: Scanner configuration file: /opt/sonarqube/sonar-scanner/conf/sonar-scanner.properties
INFO: Project root configuration file: /opt/sonarqube/conf/python/sonar-project.properties
INFO: SonarQube Scanner 3.1.0.1141
......
......
INFO: ANALYSIS SUCCESSFUL, you can browse http://localhost:9000/dashboard/index/my:python
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://localhost:9000/api/ce/task?id=AWJW_N6U1qxTjZHyQmBu
INFO: Task total time: 4.424 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 6.144s
INFO: Final Memory: 11M/335M
INFO: ------------------------------------------------------------------------

Jenkins集成Sonarqube

  • [Analyzing with SonarQube Scanner for Jenkins](Analyzing with SonarQube Scanner for Jenkins)

Reference