SonarQube安装配置使用


🛡️ + Jenkins 全链路代码质量门禁实战(含完整 Pipeline)

本文覆盖:

SonarQube 部署 → Jenkins 配置 → Pipeline 集成 → Webhook 优化 → 生产级 CI/CD


一、SonarQube 部署(Docker Compose)

1️⃣ 系统内核参数(必须)

SonarQube 内置 Elasticsearch,不配置会直接启动失败。

复制代码
sysctl -w vm.max_map_count=524288
sysctl -w fs.file-max=131072
ulimit -n 131072
ulimit -u 8192

📌 备注

  • 生产环境建议写入 /etc/sysctl.conf
  • 否则宿主机重启后参数失效

2️⃣ Docker Compose 编排文件

复制代码
version: '3'

services:
  sonar-db:
    image: postgres:16
    container_name: sonar-db
    restart: always
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
      POSTGRES_DB: sonarqube
    volumes:
      # PostgreSQL 数据持久化,防止升级或重启丢数据
      - ./data/postgres:/var/lib/postgresql/data
    networks:
      - sonar-net

  sonarqube:
    image: sonarqube:10.2-community
    container_name: sonarqube
    depends_on:
      - sonar-db
    restart: always
    ports:
      - "9000:9000"
    environment:
      # JDBC 数据库连接信息
      SONAR_JDBC_URL: jdbc:postgresql://sonar-db:5432/sonarqube
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
      # 禁用 ES 引导检查(仅测试/学习环境)
      SONAR_ES_BOOTSTRAP_CHECKS_DISABLE: "true"
      TZ: Asia/Shanghai
    volumes:
      # SonarQube 数据、插件、日志持久化
      - ./data/sonarqube_data:/opt/sonarqube/data
      - ./data/sonarqube_extensions:/opt/sonarqube/extensions
      - ./data/sonarqube_logs:/opt/sonarqube/logs
    networks:
      - sonar-net

networks:
  sonar-net:
    driver: bridge

📌 备注

  • PostgreSQL 与 SonarQube 通过自定义桥接网络通信
  • 不建议在生产环境关闭 ES 检查

3️⃣ 初始化 SonarQube

  • 访问:http://<IP>:9000
  • 默认账号:admin / admin
  • 首次登录强制修改密码

二、生成 SonarQube Token(CI/CD 最关键)

复制代码
右上角头像 → My Account → Security → Generate Tokens
Token 名称:jenkins

⚠️ Token 只显示一次,务必保存


三、Jenkins 配置 SonarQube

1️⃣ 安装插件

复制代码
Manage Jenkins → Plugins
搜索:SonarQube Scanner
安装 → 重启 Jenkins

2️⃣ 添加凭据

|-------------|-----------------|
| 项 | 值 |
| Kind | Secret text |
| Secret | 粘贴 Sonar Token |
| ID | sonarqube-token |
| Description | SonarQube Token |

📌 备注

  • 不要在 Jenkinsfile 中明文写 Token
  • 多环境可创建多个 Token

3️⃣ 配置 SonarQube Server

复制代码
Manage Jenkins → Configure System → SonarQube servers

|----------------------|--------------------|
| 项 | 值 |
| Name | sonarqube |
| Server URL | http://<IP>:9000 |
| Authentication Token | sonarqube-token |


四、Jenkins Pipeline(完整 + 详细注释)

✅ 支持 正常发布 + 版本回滚

✅ 包含 SonarQube 扫描 + 质量门禁

✅ 包含 钉钉审批 + K8s 部署

复制代码
pipeline {
  agent any

  // ================== 流水线参数 ==================
  parameters {
    choice(
      name: 'DEPLOY_TYPE',
      choices: ['deploy', 'rollback'],
      description: 'deploy = 正常发布,rollback = 版本回滚'
    )
    string(
      name: 'ROLLBACK_VERSION',
      defaultValue: '',
      description: '回滚时必须填写版本号,如:1.0.0-5-a1b2c3d'
    )
  }

  // ================== 全局环境变量 ==================
  environment {
    APP_NAME      = "cice-testing"
    REGISTRY      = "crpi-7amxwknx8zozpm09.cn-beijing.personal.cr.aliyuncs.com/sunlipeng"
    IMAGE         = "${REGISTRY}/${APP_NAME}"
    BASE_VERSION  = "1.0.0"
    NAMESPACE     = "default"

    // Maven 本地仓库缓存,加速构建
    MAVEN_CACHE_DIR = '/var/lib/jenkins/maven_cache'
  }

  // ================== 流水线全局选项 ==================
  options {
    timeout(time: 30, unit: 'MINUTES')   // 防止流水线无限挂起
    disableConcurrentBuilds()           // 禁止并发构建
    buildDiscarder(logRotator(numToKeepStr: '10')) // 保留最近 10 次构建
  }

  stages {

    // ============================================
    // 分支一:正常发布流程
    // ============================================
    stage('Normal Deploy Flow') {
      when { expression { params.DEPLOY_TYPE == 'deploy' } }

      stages {

        // ---------- Git 拉取代码 ----------
        stage('Git Pull') {
          steps {
            script {
              git branch: 'master',
                  url: 'https://gitee.com/sun-lipeng123/cice-testing.git',
                  credentialsId: 'git-creds'
            }
          }
        }

        // ---------- 生成唯一版本号 ----------
        stage('Generate Version') {
          steps {
            script {
              def gitShortHash = sh(
                script: 'git rev-parse --short HEAD',
                returnStdout: true
              ).trim()

              env.FINAL_TAG = "${BASE_VERSION}-${BUILD_NUMBER}-${gitShortHash}"
              echo "✅ 生成新版本号: ${FINAL_TAG}"
            }
          }
        }

        // ---------- 编译 & 单元测试 ----------
        stage('Build & Unit Test') {
          steps {
            sh """
              mkdir -p ${MAVEN_CACHE_DIR}
              mvn clean test package -Dmaven.repo.local=${MAVEN_CACHE_DIR}
            """
          }
          post {
            success {
              // 归档构建产物,便于回滚或下载
              archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
            }
          }
        }

        // ---------- SonarQube 代码扫描 ----------
        stage('SonarQube Analysis') {
          steps {
            withSonarQubeEnv('sonarqube') {
              sh """
                mvn sonar:sonar \
                  -Dsonar.projectKey=${APP_NAME} \
                  -Dsonar.projectName=${APP_NAME} \
                  -Dsonar.sources=.
              """
            }

            // 等待 SonarQube 质量门禁结果
            timeout(time: 3, unit: 'MINUTES') {
              waitForQualityGate abortPipeline: false
            }
          }
        }

        // ---------- 人工审批 ----------
        stage('Production Approval') {
          steps {
            script {
              withCredentials([string(credentialsId: 'dingtalk-webhook', variable: 'TOKEN')]) {

                def msg = """【上线审批】
项目:${APP_NAME}
版本:${FINAL_TAG}
构建号:${BUILD_NUMBER}
请登录 Jenkins 点击【确认部署】
构建地址:${BUILD_URL}"""

                def json = '{"msgtype":"text","text":{"content":"' + msg.replaceAll("\n", "\\\\n") + '"}}'
                sh "curl -s -X POST https://oapi.dingtalk.com/robot/send?access_token=\${TOKEN} -H 'Content-Type: application/json' -d '${json}'"
              }

              // 人工确认后才允许继续
              input message: '确认将此版本部署到生产环境吗?', ok: '确认部署', submitter: 'admin'
            }
          }
        }

        // ---------- 构建并推送 Docker 镜像 ----------
        stage('Docker Build & Push') {
          steps {
            withCredentials([usernamePassword(
              credentialsId: 'docker-aliyun-creds',
              usernameVariable: 'DOCKER_USER',
              passwordVariable: 'DOCKER_PASS'
            )]) {
              sh """
                echo \$DOCKER_PASS | docker login -u \$DOCKER_USER --password-stdin \$REGISTRY
                docker build -t \${IMAGE}:\${FINAL_TAG} .
                docker push \${IMAGE}:\${FINAL_TAG}
              """
            }
          }
        }

        // ---------- 部署到 Kubernetes ----------
        stage('Deploy to K8s') {
          steps {
            withCredentials([file(credentialsId: 'kubeconfig-prod', variable: 'KUBECONFIG_FILE')]) {
              sh """
                export KUBECONFIG=\$KUBECONFIG_FILE
                sed -i "s|image: .*|image: \${IMAGE}:\${FINAL_TAG}|g" k8s.yaml
                kubectl apply -f k8s.yaml

                # 确保 Pod 真正启动成功
                kubectl rollout status deployment/jenkins-demo -n ${NAMESPACE} --timeout=300s
              """
            }
          }
        }
      }
    }

    // ============================================
    // 分支二:版本回滚流程
    // ============================================
    stage('Rollback Flow') {
      when { expression { params.DEPLOY_TYPE == 'rollback' } }

      steps {
        script {
          if (params.ROLLBACK_VERSION == '') {
            error "❌ 回滚模式下,必须填写 ROLLBACK_VERSION 参数!"
          }

          echo "🚀 开始回滚 ${APP_NAME} 到版本: ${params.ROLLBACK_VERSION}"

          withCredentials([file(credentialsId: 'kubeconfig-prod', variable: 'KUBECONFIG_FILE')]) {
            sh """
              export KUBECONFIG=\$KUBECONFIG_FILE
              sed -i "s|image: .*|image: \${IMAGE}:${params.ROLLBACK_VERSION}|g" k8s.yaml
              kubectl apply -f k8s.yaml

              kubectl rollout status deployment/jenkins-demo -n ${NAMESPACE} --timeout=300s
            """
          }
        }
      }
    }
  }

  // ================== 构建结果通知 ==================
  post {
    success {
      script {
        def actionType = params.DEPLOY_TYPE == 'rollback' ? "✅ 回滚成功" : "✅ 部署成功"
        def targetVersion = params.DEPLOY_TYPE == 'rollback' ? params.ROLLBACK_VERSION : env.FINAL_TAG

        withCredentials([string(credentialsId: 'dingtalk-webhook', variable: 'TOKEN')]) {
          def msg = """${actionType}
项目:${APP_NAME}
目标版本:${targetVersion}
访问地址:http://<你的节点IP>:30080"""

          def json = '{"msgtype":"text","text":{"content":"' + msg.replaceAll("\n", "\\\\n") + '"}}'
          sh "curl -s -X POST https://oapi.dingtalk.com/robot/send?access_token=\${TOKEN} -H 'Content-Type: application/json' -d '${json}'"
        }
      }
    }

    failure {
      script {
        withCredentials([string(credentialsId: 'dingtalk-webhook', variable: 'TOKEN')]) {
          def actionType = params.DEPLOY_TYPE == 'rollback' ? "❌ 回滚失败" : "❌ 构建/部署失败"
          def msg = """${actionType}
项目:${APP_NAME}
构建地址:${BUILD_URL}
请及时排查问题!"""

          def json = '{"msgtype":"text","text":{"content":"' + msg.replaceAll("\n", "\\\\n") + '"}}'
          sh "curl -s -X POST https://oapi.dingtalk.com/robot/send?access_token=\${TOKEN} -H 'Content-Type: application/json' -d '${json}'"
        }
      }
    }
  }
}

五、启用 SonarQube Webhook(强烈推荐)

SonarQube 端配置

复制代码
Administration → Configuration → Webhooks

新增 Webhook:

复制代码
http://<jenkins-url>/sonarqube-webhook/

✅ 分析完成后 Sonar 主动通知 Jenkins

✅ 不再依赖 waitForQualityGate轮询

✅ 彻底解决 PENDING / 超时问题


六、总结

✅ 本文完整覆盖了:

  • SonarQube 部署
  • Jenkins 集成
  • 自动化代码扫描
  • 质量门禁
  • 生产审批
  • K8s 发布 & 回滚

📌 一句话总结

**没有 SonarQube 的 CI/CD,只是"能跑";

有了 SonarQube,才是"敢上线"。**

相关推荐
小义_2 小时前
【Kubernetes】(二十)ETCD 备份与恢复
容器·kubernetes·etcd
汪汪大队u2 小时前
基于 K8s 的物联网平台运维体系:Ansible+Zabbix 自动化监控与故障自愈(一)—— 环境准备与 Zabbix Server 部署
运维·kubernetes·自动化·ansible·zabbix
weelinking14 小时前
【企业级】企业级大模型合规实战:数据安全与跨境传输的技术解决方案
数据库·人工智能·机器学习·云计算·github
向日的葵00616 小时前
阿里云OSS从0到1实战:为宠物收养系统打造图片上传功能
python·阿里云·云计算·pillow·fastapi·宠物
SPC的存折18 小时前
19-2、K8s 三种 QoS 等级 & 与 Resources(requests_limits)的核心关联
云原生·容器·kubernetes
SPC的存折18 小时前
1、K8S-组件介绍
云原生·容器·kubernetes
SPC的存折19 小时前
20、K8S-Pod驱逐
java·docker·kubernetes
Kevin-anycode21 小时前
阿里云安装ali-instance-cli免公网打开 Web 界面(OpenClaw)
阿里云·云计算
sbjdhjd1 天前
02 (中)| K8s Pod 生产化落地:从配置到优化全流程
linux·运维·云原生·kubernetes·开源·podman·kubelet