
SonarQube는 코드 품질과 보안 취약점을 분석하고 지속적으로 관리하는 오픈소스 플랫폼이다.
주로 CI/CD 파이프라인과 연동하여 코드 변경 시 자동으로 분석을 수행하며, 버그, 코드 스멜(Smell), 보안 이슈 등을 탐지한다.
코드 품질과 보안 취약점을 자동으로 검사하는 정적 코드 분석 도구이다.
지속적인 코드 품질 모니터링을 통해 더 안정적이고 유지보수가 용이한 코드를 작성할 수 있다.
간단하게 Kubernetes 위에 Sonarqube를 배포하고 사용하는 방법을 정리해보았다.
추가로, keycloak OpenID Connect 연동도 함께 정리하였다.
Sonarqube는 비교적 배포가 쉬워, 간단하게 deploy를 사용해 배포한다.
oidc를 사용하기 위해 initcontainer로 플러그인 다운로드 및 공유한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: sonarqube
namespace: sonarqube
spec:
replicas: 1
selector:
matchLabels:
app: sonarqube
template:
metadata:
labels:
app: sonarqube
spec:
securityContext:
fsGroup: 1000
runAsUser: 1000
initContainers:
- name: setup-plugins
image: curlimages/curl
command: ['sh', '-c', 'mkdir -p /opt/sonarqube/extensions/plugins && curl -L -o /opt/sonarqube/extensions/plugins/sonar-auth-oidc-plugin-2.1.1.jar https://github.com/vaulttec/sonar-auth-oidc/releases/download/v2.1.1/sonar-auth-oidc-plugin-2.1.1.jar']
volumeMounts:
- name: extensions
mountPath: /opt/sonarqube/extensions
containers:
- name: sonarqube
image: sonarqube:9.9-community
env:
- name: SONAR_JDBC_URL
value: "jdbc:postgresql://sonarqube-postgresql:5432/sonarqube?socketTimeout=60&connectTimeout=30"
- name: SONAR_JDBC_USERNAME
value: sonarqube
- name: SONAR_JDBC_PASSWORD
valueFrom:
secretKeyRef:
name: sonarqube-secrets
key: SONAR_JDBC_PASSWORD
- name: SONAR_ES_BOOTSTRAP_CHECKS_DISABLE
value: "true"
ports:
- containerPort: 9000
startupProbe:
httpGet:
path: /api/system/status
port: 9000
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /api/system/status
port: 9000
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /api/system/status
port: 9000
resources:
limits:
cpu: "8"
memory: "32Gi"
requests:
cpu: "4"
memory: "8Gi"
volumeMounts:
- name: data
mountPath: /opt/sonarqube/data
- name: extensions
mountPath: /opt/sonarqube/extensions
- name: logs
mountPath: /opt/sonarqube/logs
volumes:
- name: data
persistentVolumeClaim:
claimName: sonarqube-data
- name: extensions
persistentVolumeClaim:
claimName: sonarqube-extensions
- name: logs
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: sonarqube
namespace: sonarqube
spec:
type: ClusterIP
ports:
- port: 9000
targetPort: 9000
selector:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sonarqube-ingress
namespace: sonarqube
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
nginx.ingress.kubernetes.io/proxy-busy-buffers-size: "256k"
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
spec:
ingressClassName: nginx
rules:
- host: ex)www.mysonarqube.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: sonarqube
port:
number: 9000
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sonarqube-postgresql
namespace: sonarqube
spec:
serviceName: sonarqube-postgresql
replicas: 1
selector:
matchLabels:
app: sonarqube-postgresql
template:
metadata:
labels:
app: sonarqube-postgresql
spec:
securityContext:
fsGroup: 1001
containers:
- name: postgresql
image: bitnami/postgresql:14
env:
- name: POSTGRESQL_USERNAME
value: sonarqube
- name: POSTGRESQL_PASSWORD
valueFrom:
secretKeyRef:
name: sonarqube-secrets
key: POSTGRESQL_PASSWORD
- name: POSTGRESQL_DATABASE
value: sonarqube
- name: POSTGRESQL_POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: sonarqube-secrets
key: POSTGRESQL_POSTGRES_PASSWORD
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /bitnami/postgresql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: longhorn
resources:
requests:
storage: 30Gi
---
apiVersion: v1
kind: Service
metadata:
name: sonarqube-postgresql
namespace: sonarqube
spec:
type: ClusterIP
ports:
- port: 5432
targetPort: 5432
selector:
app: sonarqube-postgresql
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sonarqube-data
namespace: sonarqube
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 70Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sonarqube-extensions
namespace: sonarqube
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 20Gi
apiVersion: v1
kind: Secret
metadata:
name: sonarqube-secrets
namespace: sonarqube
type: Opaque
stringData:
SONAR_JDBC_PASSWORD: ex)base64
POSTGRESQL_PASSWORD: ex)base64
POSTGRESQL_POSTGRES_PASSWORD: ex)base64

Server URL도 설정해야 한다.
Logo를 설정해 줄 수 있다.





Sonarqube는 CI/CD 파이프라인에서 꼭 사용하는 것이 좋다고 생각한다.
Quality Gate를 사용할 것인지도 중요하지만, 지속적으로 코드 스캔 결과를 직접 확인하는게 운영에 도움이 되는 것 같다. (깨달음)