Sonarqube 배포하기

Sonarqube란 정적 분석을 통해 코드 품질을 높이고, 유지보수를 할 때 도움을 준다. 코드 컨벤션부터 잠재적인 위험 사항까지 체크를 해주어 품질 향상에 도움을 준다.

쿠버네티스 클러스터에 Sonarqube를 배포해보자. Argocd를 설치했으니 GitOps를 통해 Sonarqube를 배포해보자.

ArgoCD로 Sonarqube 배포하기

가장 먼저 GitOps가 될 GitHub 레포지토리를 설정해야한다. 해당 레포지토리는 ArgoCD가 주시하고 있다가 변경이 생기면 레포지토리의 매니페스트 파일에 따라 배포를 진행해준다.

위와 같이 sonarqube 디렉토리를 레포지토리 루트에 생성한다. 다른 디렉토리는 신경쓰지 말자.

쿠버네티스 Secret 생성

Sonarqube와 Sonarqube가 사용할 Postgres의 패스워드를 쿠버네티스 Secret으로 생성하자.

가장 먼저 bas64를 통해 비밀을 인코딩 해야한다.

1
echo '[원하는 패스워드]' | base64

위에서 나온 결과를 복사해둔다. 그리고 posrgres-password-secret.yaml을 다음과 같이 작성한다.

1
2
3
4
5
6
7
apiVersion: v1
kind: Secret
metadata:
  name: sonarqube-postgres
type: Opaque
data:
  password: [base64 인코딩 결과]

다음과 같이 Secret를 적용한다.

1
2
kubectl create ns sonarqube
kubectl apply -f posrgres-password-secret.yaml -n sonarqube

네임스페이스를 만들고 Secret를 생성했다.

쿠버네티스 PV 생성

Sonarqube 매니페스트에서 PVC를 이용해 볼륨을 요청할 것이다. 따라서 바인딩 될 PV가 필요하다. postgres용 pv, sonarqube 데이터 용 pv, sonarqube 익스텐션 용 pv 3개를 생성하자.

sonar-data-pv.yaml을 다음과 같이 작성하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: PersistentVolume
metadata:
  name: sonarqube-data-pv
spec:
  storageClassName: sonarqube-data
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  hostPath:
    path: /sonarqube/data

sonarqube에서 권장하는 용량이 있지만 리소스 문제로 인해 작게 설정하였다. 리소스가 충분한 경우 30기가 이상으로 설정해주자.

sonar-extentions-pv.yaml을 다음과 같이 작성하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: PersistentVolume
metadata:
  name: sonarqube-extentions-pv
spec:
  storageClassName: sonarqube-extentions
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  hostPath:
    path: /sonarqube/extentions

적당히 5기가로 생성했다.

마지막으로 postgres를 위한 pv 매니페스트를 작성해보자.

sonar-postgres-pv.yaml을 다음과 같이 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
kind: PersistentVolume
apiVersion: v1
metadata:
  name: sonarqube-postgres-pv
spec:
  storageClassName: sonarqube-postgres-data
  capacity:
    storage: 8Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  hostPath:
    path: /data/postgresql

다음 명령어로 작성한 매니페스트 파일을 적용하자.

1
kubectl apply -f sonar-postgres-pv.yaml sonar-extentions-pv.yaml sonar-data-pv.yaml

Sonarqube Postgres 매니페스트 작성

Sonarqube를 그냥 띄우면 H2 인메모리 DB를 사용한다. 장기간 사용시 문제가 될 수 있으니 Postgres를 연결해 사용하는 것이 안전하다.

가장 먼저 postgres Deployment를 작성하자. sonar-posrgres-deployment.yaml로 작성했다.

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
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sonarqube-postgres
  namespace: sonarqube
spec:
  replicas: 1
  selector:
    matchLabels:
      name: sonarqube-postgres
  template:
    metadata:
      name: sonarqube-postgres
      labels:
        name: sonarqube-postgres
    spec:
      containers:
        - image: postgres:16.2
          name: sonarqube-postgres
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-password
                  key: password
            - name: POSTGRES_USER
              value: sonar
          ports:
            - containerPort: 5432
              name: postgresport
          volumeMounts:
            # This name must match the volumes.name below.
            - name: data-disk
              mountPath: /var/lib/postgresql/data
      volumes:
        - name: data-disk
          persistentVolumeClaim:
            claimName: postgres-pvc

env의 패스워드 부분은 쿠버네티스 Secret이 사용될 것이다.

다음은 서비스를 작성하자.

sonar-postgres-service.yaml을 다음과 같이 작성하자.

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
  namespace: sonarqube
  labels:
    name: sonarqube-postgres
  name: sonarqube-postgres
spec:
  ports:
    - port: 5432
  selector:
    name: sonarqube-postgres

마지막으로 postgres의 PVC를 작성하자.

sonar-postgres-pvc.yaml를 다음과 같이 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc
  namespace: sonarqube
spec:
  storageClassName: sonarqube-postgres-data
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi

Sonarqube 매니페스트 작성

소나큐브가 PR에 분석 결과를 Comment로 달 수 있게 플러그인을 추가할 것이다. sonarqube-community-branch-plugin이다. 커뮤니티 버전에서도 PR Comment을 사용할 수 있게 해준다. README를 살펴보면 Sonarqube 10.3.0버전은 플러그인 버전 1.18.0을 지원하므로 1.18.0버전으로 설치해보자.

args에 브랜치 플러그인 관련 설정 정보를 넣어준다.

sonar-deployment-yaml을 다음과 같이 작성한다. Secret에서 DB Password를 가져온다.

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
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sonarqube-deployment
  labels:
    app: sonarqube
  namespace: sonarqube
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sonarqube
  template:
    metadata:
      labels:
        app: sonarqube
    spec:
      containers:
        - name: sonarqube
          image: sonarqube:10.3.0-community
          args:
            - -Dsonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.18.0.jar=web
            - -Dsonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.18.0.jar=ce
          volumeMounts:
            - mountPath: "/opt/sonarqube/data/"
              name: sonarqube-data
            - mountPath: "/opt/sonarqube/extensions/"
              name: sonarqube-extensions
          env:
            - name: SONAR_JDBC_URL
              value: jdbc:postgresql://sonarqube-postgres:5432/sonar
            - name: SONAR_JDBC_USERNAME
              value: sonar
            - name: SONAR_JDBC_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: sonarqube-postgres
                  key: password
          ports:
            - containerPort: 9000
              protocol: TCP
      volumes:
        - name: sonarqube-data
          persistentVolumeClaim:
            claimName: sonarqube-data
        - name: sonarqube-extensions
          persistentVolumeClaim:
            claimName: sonarqube-extensions

다음은 sonarqube가 사용할 data를 위한 pvc를 작성해보자.

sonar-data-pvc.yaml을 다음과 같이 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sonarqube-data
  namespace: sonarqube
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: sonarqube-data
  resources:
    requests:
      storage: 10Gi

sonarqube가 사용할 플러그인 extentions를 위한 pvc를 작성해보자.

sonar-extentions-pvc.yaml을 다음과 같이 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: sonarqube-extensions
  namespace: sonarqube
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: sonarqube-extentions
  resources:
    requests:
      storage: 5Gi

다음은 접속을 위한 서비스 매니페스트를 작성하자.

sonar-service.yaml을 다음과 같이 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Service
metadata:
  namespace: sonarqube
  labels:
    app: sonarqube
  name: sonarqube-service
spec:
  ports:
    - name: sonar
      port: 80
      protocol: TCP
      targetPort: 9000
  selector:
    app: sonarqube

마지막으로 SSL인증을 통해 특정 도메인으로 접속하기 위해 다음과 같이 sonar-ingress.yaml을 작성한다.

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
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sonarqube-ingress
  namespace: sonarqube
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
  ingressClassName: nginx
  rules:
  - host: [원하는 host]
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: sonarqube-service
            port:
             number: 9000
  tls:
    - hosts:
      -  [원하는 host]
      secretName: sonarqube-cert

도메인이 없는 경우에는 ArgoCD 배포하기를 참고해 Ingress를 설정하자.

플러그인 설치

컨트롤 플레인의 /sonarqube/extentions에 Sonarqube 플러그인 볼륨을 매핑했다. 여기에 커뮤니티 브랜치 플러그인을 설치해야한다.

plugins폴더를 생성하고 jar파일을 다운받는다.

1
2
3
4
sudo apt install wget
mkdir -p /sonarqube/extensions/plugin
cd /sonarqube/extensions/plugin
wget https://github.com/mc1arke/sonarqube-community-branch-plugin/releases/download/1.18.0/sonarqube-community-branch-plugin-1.18.0.jar

ArgoCD APP 생성

ArgoCD에 접속해 NEW APP 버튼을 눌러 sonarqube에 대한 GitOps를 적용해보자.

기본적으로 프로젝트 정보를 위와 같이 설정한다.

APP을 생성하면 SYNC를 시작할 것이다. 레포지토리의 매니페스트 파일을 읽어 쿠버네티스 클러스터로 배포시킨다.

위와 같이 잘 배포되면 성공이다.

접속하기

Ingress에서 설정한 URL에 들어가 기본 ID/PW인 admin/admin으로 접속할 수 있다.

패스워드를 변경해준다.

Administration - General - Server Base URL에서 설정한 도메인으로 URL을 변경하면 Sonarqube를 사용하기 위한 준비를 마쳤다.

오류 해결

오류해결 (vm.max_map_count)

Sonarqube는 ElasticSearch를 사용한다. ElasticSearch가 사용하는 최소 max_map_count가 최소 요구사항보다 작아서 오류가 발생해 파드가 작동하지 않을 수도 있다. 따라서 컨트롤플레인에서 vm.max_map_count를 변경해 실행하면 오류를 해결할 수 있다.

1
2
3
4
5
6
7
8
# 값 확인
sudo sysctl -a | grep vm.max_map_count

# 값 변경
sudo systcl -w vm.max_map_count=262144

# 변경된 값 확인
sudo sysctl -a | grep vm.max_map_count

오류해결 (권한 문제)

pv의 권한 문제로 작동이 안될 수 있다. sudo chmod 755 -R [pv 디렉토리 경로] 명령어를 통해 권한을 활성화 해주고 Argocd에서 문제되는 Pod를 삭제해 재생성되도록 해보자.

다음으로

ArgoCD와 Sonarqube를 쿠버네티스 클러스터에 배포했다. 이제 Source Repository에서 GitHub Action을 통해 CI/CD 과정을 진행하면 된다. 다음 포스트에서는 Sonarqube 브랜치 플러그인을 사용하기 위한 준비를 진행해보자.

댓글남기기