实践002-Gitlab CICD静态代码检查

后端项目单元测试

后端 java 项目的静态代码检测主要包括:单元测试和静态代码检查。

编写测试流水线

[root@gitclient apiserver]# vim .gitlab-ci.yml
stages:
  - compile

unittest:
  stage: compile
  image: maven:3.8.5-openjdk-17
  script:
    - mvn verify -Dmaven.test.failure.ignore=true
    - ls target/surefire-reports/*.xml
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  artifacts:
    when: always
    reports:
      junit:
        - target/surefire-reports/TEST-*.xml
        - target/failsafe-reports/TEST-*.xml
  tags:
    - study-runner
    
[root@gitclient apiserver]# git add .gitlab-ci.yml
[root@gitclient apiserver]# git commit -m "Test mvn verify"
[root@gitclient apiserver]# git push origin main

提示:maven 所使用的 jdk 版本需要和创建后端项目的 java 版本一致。

提交流水线后,等待测试完成。
160
查看测试结果。
161

SonarQube代码检测平台

SonarQube介绍

SonarQube 是一个开源平台,用于持续检查代码质量并执行自动化分析。它可以与 Jenkins 或 Gitlab 、 Actions 等集成,以便在 CI/CD 流程中自动进行代码审查。

其内核是设计思想是 “质量即代码”(Quality as Code) 理念。

SonarQube 将代码质量分解为三个正交维度:

  • 可靠性(Reliability):预防运行时缺陷
  • 安全性(Security):消除漏洞攻击面
  • 可维护性(Maintainability):降低技术维护难度

SonarQube部署

本实验基于已有的 Kubernetes 集群和 Longhorn 持久化进行部署,保障 SonarQube 的健壮性和数据持久化。
部署 SonarQube 之前需要先部署 PostgreSQL 。

对于 Kubernetes 和 Longhorn 部署,不在此文章范围内,可自行参考: 附039.Kubernetes_v1.32.2生产环境高可用部署

  • 确认当前环境
    确认当前环境具备 StorageClass ,用于给 sonarqube 提供持久化数据。
root@master01:~# mkdir sonarqube
root@master01:~# cd sonarqube/
root@master01:~/sonarqube# kubectl get sc
NAME                 PROVISIONER          RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
longhorn (default)   driver.longhorn.io   Delete          Immediate           true                   15d
longhorn-static      driver.longhorn.io   Delete          Immediate           true                   15d
  • 创建PostgreSQL PVC
root@master01:~/sonarqube# kubectl create namespace sonarqube

root@master01:~/sonarqube# cat <<EOF > postgresqlpvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgresql-pvc
  namespace: sonarqube
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 1Gi
EOF

root@master01:~/sonarqube# kubectl apply -f postgresqlpvc.yaml
  • 部署PostgreSQL
    部署 postgresql ,创建 SonarQube 所需的用户名、密码、数据库DB,使用已创建的 PVC 。
    同时将 postpresql 对外暴露服务,以便于后续 SonarQube 调用。
root@master01:~/sonarqube# cat <<EOF > postgresqldeployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
  namespace: sonarqube
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:17.4
        env:
        - name: POSTGRES_USER
          value: sonar
        - name: POSTGRES_PASSWORD
          value: sonar1234
        - name: POSTGRES_DB
          value: sonardb
        - name: PGDATA
          value: /var/lib/postgresql/data
        ports:
        - containerPort: 5432
        volumeMounts:
        - name: postgres-data
          mountPath: /var/lib/postgresql
        - mountPath: /etc/localtime
          name: timeconfig
          readOnly: true
      volumes:
      - name: postgres-data
        persistentVolumeClaim:
          claimName: postgresql-pvc
      - name: timeconfig
        hostPath:
          path: /etc/localtime
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: sonarqube
spec:
  type: NodePort
  selector:
    app: postgres
  ports:
    - protocol: TCP
      port: 5432
      targetPort: 5432
      nodePort: 31003
EOF

root@master01:~/sonarqube# kubectl apply -f postgresqldeployment.yaml

确认 postgresql 部署情况:

root@master01:~/sonarqube# kubectl -n sonarqube get pods -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
postgres-cf69988db-4hr2l   1/1     Running   0          16s   10.10.30.97   worker02   <none>           <none>
root@master01:~/sonarqube# kubectl -n sonarqube get svc -o wide
NAME       TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE   SELECTOR
postgres   NodePort   10.20.2.220   <none>        5432:31003/TCP   19s   app=postgres
root@master01:~/sonarqube# kubectl -n sonarqube get pvc -o wide
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE   VOLUMEMODE
postgresql-pvc   Bound    pvc-91fad7aa-b315-48bb-9e67-ff27125605ac   1Gi        RWO            longhorn       <unset>                 34s   Filesystem
  • 部署SonarQube pvc
    sonarqube 主要目录均配置持久化存储。
root@master01:~/postgresql# vim sonarqubepvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sonarqube-data-pvc
  namespace: sonarqube
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 2Gi
      
---      
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sonarqube-extensions-pvc
  namespace: sonarqube
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 500Mi

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sonarqube-logs-pvc
  namespace: sonarqube
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 200Mi

---      
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sonarqube-config-pvc
  namespace: sonarqube
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 200Mi

root@master01:~/postgresql# kubectl apply -f sonarqubepvc.yaml
  • 部署SonarQube
    为了多个主要目录都做持久化,对 data 、extensions 、 conf 、logs均做单独 PVC 挂载。
    若单独挂载,则需要对 Pod 内部的容器权限使用 initContainers 提前进行设置。
    同时 sonarqube 在后续配置和 gitlab 集成的时候,本环境的 gitlab 采用了自签名证书,所以需要将 CA 添加到 sonarqube 中,否则无法通过证书校验。
kubectl -n sonarqube create configmap gitlab-ca \
  --from-file=myCA.crt=/gitlab/config/certs/myCA.crt

root@master01:~/sonarqube# vim sonarqubedeployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sonarqube
  namespace: sonarqube
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sonarqube
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: sonarqube
    spec:
      initContainers:
      - name: volume-permission-fix
        image: uhub.service.ucloud.cn/imxhy/xhyops:v2
        command: ["sh", "-c", "chown -R 1000:1000 /opt/sonarqube && update-ca-certificates"]
        volumeMounts:
        - name: sonarqube-data
          mountPath: /opt/sonarqube/data
        - name: sonarqube-extensions
          mountPath: /opt/sonarqube/extensions
        - name: sonarqube-logs
          mountPath: /opt/sonarqube/logs
        - name: sonarqube-conf
          mountPath: /opt/sonarqube/conf
        - name: ca-cert
          mountPath: /etc/ssl/certs/myCA.crt
          subPath: myCA.crt

      containers:
      - name: sonarqube
        image: sonarqube:9.9.8-community
        env:
        - name: SONAR_JDBC_URL
          value: jdbc:postgresql://postgres:5432/sonardb
        - name: SONAR_JDBC_USERNAME
          value: sonar
        - name: SONAR_JDBC_PASSWORD
          value: sonar1234
        - name: SONAR_WEB_JAVAOPTS
          value: "-Xmx2048m -Xms1024m -Dsonar.web.context=/ -Dsonar.core.serverBaseURL=http://172.24.8.180:31004"
        - name: SONAR_CE_JAVAOPTS
          value: "-Xmx2048m"
        - name: TZ
          value: Asia/Shanghai
        ports:
        - containerPort: 9000
        volumeMounts:
        - name: sonarqube-data
          mountPath: /opt/sonarqube/data
        - name: sonarqube-extensions
          mountPath: /opt/sonarqube/extensions
        - name: sonarqube-logs
          mountPath: /opt/sonarqube/logs
        - name: sonarqube-conf
          mountPath: /opt/sonarqube/conf
        - mountPath: /etc/localtime
          name: timeconfig
          readOnly: true
      volumes:
      - name: sonarqube-data
        persistentVolumeClaim:
          claimName: sonarqube-data-pvc
      - name: sonarqube-extensions
        persistentVolumeClaim:
          claimName: sonarqube-extensions-pvc
      - name: sonarqube-logs
        persistentVolumeClaim:
          claimName: sonarqube-logs-pvc
      - name: sonarqube-conf
        persistentVolumeClaim:
          claimName: sonarqube-config-pvc
      - name: timeconfig
        hostPath:
          path: /etc/localtime
      - name: ca-cert
        configMap:
          name: gitlab-ca
          items:
          - key: myCA.crt
            path: myCA.crt
---
apiVersion: v1
kind: Service
metadata:
  name: sonarqube
  namespace: sonarqube
spec:
  type: NodePort
  selector:
    app: sonarqube
  ports:
    - protocol: TCP
      port: 9000
      targetPort: 9000
      nodePort: 31004

root@master01:~/sonarqube# kubectl apply -f sonarqubedeployment.yaml
  • 确认部署情况
    确认 postgresql 和 sonarqube 部署情况。
root@master01:~/sonarqube# kubectl -n sonarqube get pods -o wide
NAME                         READY   STATUS    RESTARTS   AGE    IP           NODE       NOMINATED NODE   READINESS GATES
postgres-ccfdf8967-s6wz7     1/1     Running   0          116m   10.10.5.42   worker01   <none>           <none>
sonarqube-6678c6fb95-d86mt   1/1     Running   0          100m   10.10.5.36   worker01   <none>           <none>

root@master01:~/sonarqube# kubectl -n sonarqube get pvc -o wide
NAME                       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE    VOLUMEMODE
postgresql-pvc             Bound    pvc-456bcb6d-3630-487d-8cab-1cb88677f5e4   1Gi        RWO            longhorn       <unset>                 123m   Filesystem
sonarqube-config-pvc       Bound    pvc-54759240-43d8-4923-a953-4e919dcf5e30   200Mi      RWO            longhorn       <unset>                 114m   Filesystem
sonarqube-data-pvc         Bound    pvc-f66670e0-fd71-49a7-ad4a-a9748e62156c   2Gi        RWO            longhorn       <unset>                 114m   Filesystem
sonarqube-extensions-pvc   Bound    pvc-c1b5855f-e2d5-4fc5-b82f-cb43bdb25ad6   500Mi      RWO            longhorn       <unset>                 114m   Filesystem
sonarqube-logs-pvc         Bound    pvc-bb085d54-4b64-4290-a731-198283efedf2   200Mi      RWO            longhorn       <unset>                 114m   Filesystem

root@master01:~/sonarqube# kubectl -n sonarqube get svc -o wide
NAME        TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE     SELECTOR
postgres    NodePort   10.20.2.220    <none>        5432:31003/TCP   77m     app=postgres
sonarqube   NodePort   10.20.245.54   <none>        9000:31004/TCP   2m29s   app=sonarqube

浏览器通过端口访问: http://172.24.8.180:31004
162

  • ingress暴露
    当前环境已存在 ingress ,所以可以进一步采用 ingress 暴露 sonarqube 服务。
root@master01:~/sonarqube# ll certs/
total 12
drwxr-xr-x 2 root root   58 Apr 28 21:47 ./
drwxr-xr-x 3 root root  164 Apr 28 21:46 ../
-rw-r--r-- 1 root root 4482 Apr 28 21:47 sq.linuxsb.com.crt
-rw-r--r-- 1 root root 1704 Apr 28 21:47 sq.linuxsb.com.key

root@master01:~/sonarqube# mv certs/sq.linuxsb.com.crt certs/tls.crt
root@master01:~/sonarqube# mv certs/sq.linuxsb.com.key certs/tls.key

root@master01:~/sonarqube# kubectl -n sonarqube create secret tls tls-sonarqube-ingress \
  --cert=/root/sonarqube/certs/tls.crt \
  --key=/root/sonarqube/certs/tls.key
root@master01:~/sonarqube# vim sonarqubeingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sonarqube-ingress
  namespace: sonarqube
spec:
  ingressClassName: "nginx"
  rules:
  - host: sq.linuxsb.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: 
            name: sonarqube
            port:
              number: 9000
  tls:
  - hosts:
    - sq.linuxsb.com
    secretName: tls-sonarqube-ingress

[root@master01 manifests]# kubectl apply -f sonarqubeingress.yaml

浏览器访问: https://sq.linuxsb.com/ ,使用默认用户名和密码 admin/admin 登录 。
163
首次登录需要修改密码:
164
成功登录。
165
提示:更多详细部署参考: Kubernetes 集群中部署 SonarQube 服务

sonarqube 与 gitlab 集成

gitlab 创建 Token

SonarQube 搭建完成后,需要和 Gitlab 平台集成,从而实现 和 Gitlab 上 代码仓联动。

  • 生成Token
    在 gitlab 上创建一个 Token ,后续用于 sonarqube 认证。该 Token 需要有足够的权限,能访问 Gitlab 上的所有项目。
    偏好设置 ——> 访问令牌 ——> 添加新令牌。
    166

创建不限期的所有权限的 Token 。
167

复制创建的 Token , glpat-hGsgfY1YyB79-5otzKMq 。
168

配置 sonarqube 集成 gitlab

登录 http://sq.linuxsb.com , Administration ——> Configuration ——> DevOps Platform Integrations ——> GitLab 。
169

Create configuration:
170

Check configuration ,检查配置。
171

sonarqube 集成 gitlab 账号

sonarqube 可以集成 gitlab 的账号进行登录。

  • 创建应用
    gitlab 上创建应用,用户头像 ——> 偏好设置 ——> 应用,新建应用。
    172

设置应用名称,以及固定 URI : [sonarqube域名]/oauth2/callback/gitlab 。
173

记录相关值,后续用于在 sonarqube 上配置。
174

确认创建完成。
175

  • 配置sonarqube
    使用 admin 用户登录,Administration ——> Configuration ——> Authentication ——> GitLab 。
    enabled 开启,配置 gitlab url,应用ID 以及 secret,将 gitlab 所创建的相关信息复制。
    176

GitLab认证通常允许用户注册,但没有提供允许的组列表,这是潜在的不安全,因此建议配置一个允许的组列表。
176-1

Administration ——> Configuration ——> General ,配置 Server base URL ,配置为 sonarqube 的主域名。
177

  • 确认验证
    退出登录,重新访问 https://sq.linuxsb.com ,确认可以出现 Login with GitLab 。
    178

如果是自签名证书,可能出现告警,继续即可。
179

使用 gitlab 账号登录,如 root 用户,通常建议可以为 sonarqube 单独创建一个其他用户。
180

由于实验目的,直接使用 gitlab 的 root 用户来登录 sonarqube ,会提示高权限风险,进行授权即可。
181

确认能正常使用 gitlab 用户登录。
182

配置Java后端项目

配置后端Java项目静态代码检查

sonarqube平台配置成功后,可以使用该平台对后端 Java 项目进行静态代码检查。

183

输入已创建的Token: glpat-hGsgfY1YyB79-5otzKMq 。

184

选择当前gitlab平台中已有的 apiserver java项目,设置。

185

选择持续集成工具,Gitlab CI。

186

使用 GitLab CI 分析项目中选择 Maven ,复制,将内容写入后端项目的pom.xml文件,然后单击 continue 。

187

添加环境变量,按照指示在gitlab中添加相应环境变量。
188

创建 SONAR_TOEN 变量,新生成一个Token,sqp_0bbc8fe52839d45f84c4e5ca28222f07d5463133 。

189

复制对应的Token,后续用于在gitlab创建变量。

190

登录gitlab,创建一个 SONAR_TOKEN 的变量,变量值为所创建value。
191

创建 SONAR_HOST_URL 变量。

192

确认所创建的变量。

193

创建CI流程文件 .gitlab-ci.yml ,内容直接复制,然后根据需要修改即可。

194

sonarqube-check:
  image: maven:3.6.3-jdk-11
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
    GIT_DEPTH: "0"  # Tells git to fetch all the branches of the project, required by the analysis task
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script: 
    - mvn verify sonar:sonar -Dsonar.projectKey=mygroup_apiserver_AZZ8-s2f7mv8sZMUbW1V
  allow_failure: true
  only:
    - main

创建流水线

根据 sonarqube 提示,在pom.xml中追加对应内容

[root@gitclient apiserver]# vi pom.xml
#……
    <properties>
        <java.version>17</java.version>
        <sonar.qualitygate.wait>true</sonar.qualitygate.wait>           #追加
    </properties>
#……

根据sonarqube提示的内容创建流水线:

[root@gitclient apiserver]# vim .gitlab-ci.yml
stages:
  - compile

sonarqube-check:
  stage: compile
  image: maven:3.8.5-openjdk-17
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
    GIT_DEPTH: "0"  # Tells git to fetch all the branches of the project, required by the analysis task
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - mvn verify sonar:sonar -Dsonar.projectKey=mygroup_apiserver_AZZ8-s2f7mv8sZMUbW1V
  allow_failure: true
  only:
    - main
  tags:
    - study-runner

提示:由于JAVA后端采用的是 java 17,所以需要修改maven为兼容的版本。

人为制造不规范的代码:

[root@gitclient apiserver]# vim src/main/java/com/example/apiservice/controller/HelloWorld.java
package com.example.apiservice.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo")
public class HelloWorld {
    @RequestMapping("/hello")
    public String hello() {
        int a = 100/10;                         #随意新增不规范代码进行模拟
        return "Hello World!";
    }
}

提交流水线:

[root@gitclient apiserver]# git add .
[root@gitclient apiserver]# git commit -m "Test SonarQube Check"
[root@gitclient apiserver]# git push origin main

提交流水线后,待gitlab流水线跑完,sonarqube的代码检测会有几个检测结果。
195

查看问题,可以查看人为模拟的不规范代码被正确识别。

196

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木二_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值