SonarQube 설치
사전준비
nfs dynamic provisioning
happycloud-lee.tistory.com/178?category=832243
Jenkins 설치
1. 설치하기
CPU가 최소 4core 이상 되어야 합니다.
ㅇ helm repository를 추가합니다.
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm repo update
ㅇ 작업 디렉토리 생성 및 이동
$ mkdir ~/install && cd ~/install
ㅇ sonarqube.yaml 작성
$ vi sonarqube.yaml
- storageClass는 kubectl get sc로 알 수 있습니다.
- ingress의 hostname은 접근을 위해 PC의 hosts에 등록해야 함
sonarqubeUsername: admin
sonarqubePassword: "P@ssw0rd$"
service:
type: ClusterIP
ports:
http: 80
elastic: 9001
nodePorts:
http: ""
elastic: ""
ingress:
enabled: true
ingressClassName: "nginx"
hostname: mysonar.io
persistence:
enabled: true
storageClass: "nfs-retain"
accessModes:
- ReadWriteOnce
size: 2Gi
ㅇ namespace 생성 및 이동
$ kubectl create ns sonarqube
$ kubens sonarqube
ㅇ 설치테스트
$ helm install sonar -f sonarqube.yaml bitnami/sonarqube --dry-run
ㅇ 설치
$ helm install sonar -f sonarqube.yaml bitnami/sonarqube
ㅇ 확인
ingress 주소로 웹브라우저에서 접근하고, id는 admin, 암호 admin으로 로그인합니다.
2. 환경설정
1) sonarqube의 MyAccount > Security에서 User Token발급
2) jenkins에 SonarQube Scanner 플러그인 설치하고 셋업
Jenkins에 Credential을 위에서 만든 Token으로 만듭니다.
System설정에서 SonarQube 서버 설정을 합니다.
Jenkins에 플러그인 'SonaqQube Scanner'를 먼저 설치 해야 합니다.
- Name: CI/CD파이프라인에서 참조할 이름입니다. 보통 SonarQube라고 합니다.
- Server URL: Jenkins Pod에서 접근할 SonarQube 서비스의 주소. kubectl get svc -n sonarqube로 확인하고 다른 네임스페이스에 있으므로 전체 주소를 입력합니다.
- Authentication Token: 위에서 만든 credential을 선택
3) 각 프로젝트의 SonarQube 사용 설정
SonarQube와 연계할 각 서비스별로 프로젝트를 생성합니다.
- project 만들기: Projects 누르고 [Create local project] 클릭하여 생성
4) Jenkins로 통보할 webhook 만들기
SonarQube 품질 검사 결과를 Jenkins로 보내기 위해 Webhook을 만듭니다.
- name: 적절히 지정. 예) jenkins_webhook
- url: Jenkins 서버의 주소
Jenkins를 k8s에 설치한 경우 http://{service name}/sonarqube-webhook/ 으로 하고, 그냥 설치한 경우는 http://{IP 또는 host}/sonarqube-webhook으로 함
5) Quality Gate 만들기
SonarQube의 Quality Gate 복사하여 Custom만들고 New code의 code coverage를 조정함
이름은 적절히 지정하세요.
Coverage를 0으로 조정합니다.
아래는 Job workload controller를 이용하여 테스트 사용자를 등록하고 삭제하는 yaml입니다.
ADMIN TOKEN은 위에서 만든 'MyAccount > Security의 User Token'을 사용하면 됩니다.
테스트 사용자 등록
apiVersion: batch/v1
kind: Job
metadata:
name: sonarqube-test-user-creation
spec:
template:
spec:
containers:
- name: sonarqube-test-user-creation
image: alpine
command: ["/bin/sh", "-c"]
args:
- |
# curl 설치
apk update && apk add curl
# SonarQube 서버 URL과 관리자 토큰
SONARQUBE_URL="http://sonar-sonarqube"
ADMIN_TOKEN="squ_b03e0441620c5b33d5b48749dd90b1c9f77c86ee"
# 생성할 사용자 수
USER_COUNT=30
# 사용자 생성 함수
create_user() {
username=$1
password=$2
name=$3
email=$4
curl -s -u "${ADMIN_TOKEN}:" -X POST "${SONARQUBE_URL}/api/users/create" \
-d "login=${username}" \
-d "password=${password}" \
-d "name=${name}" \
-d "email=${email}"
}
# 사용자 생성 반복문
i=1
while [ $i -le $USER_COUNT ]; do
username="user$(printf '%02d' $i)"
password="${username}P@ssw0rd$"
name="${username}"
email="${username}@example.com"
echo "Creating user: ${username}"
create_user "${username}" "${password}" "${name}" "${email}"
echo "------------------------"
i=$((i + 1))
done
restartPolicy: Never
backoffLimit: 1
테스트 사용자 삭제
apiVersion: batch/v1
kind: Job
metadata:
name: sonarqube-test-user-deletion
spec:
template:
spec:
containers:
- name: sonarqube-test-user-deletion
image: alpine
command: ["/bin/sh", "-c"]
args:
- |
# curl 설치
apk update && apk add curl
# SonarQube 서버 URL과 관리자 토큰
SONARQUBE_URL="http://sonar-sonarqube"
ADMIN_TOKEN="squ_b03e0441620c5b33d5b48749dd90b1c9f77c86ee"
# 삭제할 사용자 범위
START_USER=1
END_USER=30
# 사용자 삭제 함수
delete_user() {
username=$1
curl -s -u "${ADMIN_TOKEN}:" -X POST "${SONARQUBE_URL}/api/users/deactivate" \
-d "login=${username}"
}
# 사용자 삭제 반복문
i=$START_USER
while [ $i -le $END_USER ]; do
username="user$(printf '%02d' $i)"
echo "Deleting user: ${username}"
delete_user "${username}"
echo "------------------------"
i=$((i + 1))
done
restartPolicy: Never
backoffLimit: 1
LDAP 연결
SonaqQube와 LDAP연결은 sonar.properties파일에서 합니다.
실행된 Pod안에서 sonar.properties파일을 밖으로 복사한 후 LDAP설정 부분을 고친 후,
그 파일을 이용하여 ConfigMap을 만들고,
Deployment yaml 에서 ConfigMap을 마운트 해야 합니다.
1) sonar.properties파일 수정
아래 예제와 같이 pod에서 sonar.properties 파일을 밖으로 복사합니다.
k cp sonar-sonarqube-7bbd8bdd74-t64qc:/opt/bitnami/sonarqube/conf/sonar.properties sonar.properties
수정된 sonar.properties파일은 아래 LDAP 서버 설치에 기준하여 아래와 같습니다.
https://happycloud-lee.tistory.com/117?category=832250
...
# LDAP CONFIGURATION
# Enable the LDAP feature
sonar.security.realm=LDAP
# Set to true when connecting to a LDAP server using a case-insensitive setup.
# sonar.authenticator.downcase=true
# URL of the LDAP server. Note that if you are using ldaps, then you should install the server certificate into the Java truststore.
ldap.url=ldap://ldap-openldap.ldap.svc.cluster.local
# Bind DN is the username of an LDAP user to connect (or bind) with. Leave this blank for anonymous access to the LDAP directory (optional)
ldap.bindDn=cn=admin,dc=myldap,dc=io
# Bind Password is the password of the user to connect with. Leave this blank for anonymous access to the LDAP directory (optional)
ldap.bindPassword=P@ssw0rd$
# Possible values: simple | CRAM-MD5 | DIGEST-MD5 | GSSAPI See http://java.sun.com/products/jndi/tutorial/ldap/security/auth.html (default: simple)
# ldap.authentication=simple
# See :
# * http://java.sun.com/products/jndi/tutorial/ldap/security/digest.html
# * http://java.sun.com/products/jndi/tutorial/ldap/security/crammd5.html
# (optional)
# ldap.realm=example.org
# Context factory class (optional)
# ldap.contextFactoryClass=com.sun.jndi.ldap.LdapCtxFactory
# Enable usage of StartTLS (default : false)
# ldap.StartTLS=true
# Follow or not referrals. See http://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html (default: true)
# ldap.followReferrals=false
# USER MAPPING
# Distinguished Name (DN) of the root node in LDAP from which to search for users (mandatory)
ldap.user.baseDn=ou=users,dc=myldap,dc=io
# LDAP user request. (default: (&(objectClass=inetOrgPerson)(uid={login})) )
ldap.user.request=(&(objectClass=inetOrgPerson)(uid={login}))
# Attribute in LDAP defining the user’s real name. (default: cn)
ldap.user.realNameAttribute=cn
# Attribute in LDAP defining the user’s email. (default: mail)
ldap.user.emailAttribute=email
# GROUP MAPPING
# Distinguished Name (DN) of the root node in LDAP from which to search for groups. (optional, default: empty)
ldap.group.baseDn=ou=groups,dc=myldap,dc=io
# LDAP group request (default: (&(objectClass=groupOfUniqueNames)(uniqueMember={dn})) )
ldap.group.request=(&(objectClass=groupOfUniqueNames)(member={dn}))
# Property used to specifiy the attribute to be used for returning the list of user groups in the compatibility mode. (default: cn)
# ldap.group.idAttribute=sAMAccountName
...
2) ConfigMap 만들기
k create cm sonar-properties --from-file=sonar.properties
3) Deployment yaml 수정
먼저 Deploy 객체에서 deployment yaml을 파일로 만듭니다.
k get deploy sonar-sonarqube -o yaml > deploy.yaml
아래와 같이 initContainers에서 ConfigMap으로 부터 '/sonar-properties' 디렉토리로 마운트 한 후, sonar.properties파일을 덮어 씁니다.
apiVersion: apps/v1
kind: Deployment
...
spec:
...
template:
...
spec:
...
containers:
...
initContainers:
- args:
- -ec
- |
#!/bin/bash
. /opt/bitnami/scripts/liblog.sh
info "Copying base dir to empty dir"
# In order to not break the application functionality (such as upgrades or plugins) we need
# to make the base directory writable, so we need to copy it to an empty dir volume
cp -r --preserve=mode /opt/bitnami/sonarqube /emptydir/app-base-dir
info "update sonar.properties"
cp --preserve=mode /sonarqube-conf/sonar.properties /emptydir/app-base-dir/conf/
info "Copy operation completed"
...
volumeMounts:
- mountPath: /emptydir
name: empty-dir
- mountPath: /sonarqube-conf
name: sonar-properties
volumes:
- emptyDir: {}
name: empty-dir
- name: sonarqube
persistentVolumeClaim:
claimName: sonar-sonarqube
- name: sonar-properties
configMap:
name: sonar-properties
4) 재배포 및 테스트
기존 Pod를 지우고 다시 생성 합니다.
k delete -f deploy.yaml
k apply -f deploy.yaml
LDAP에 등록한 user로 로그인 해 봅니다.