Operations 17 min read

Block Bad Code Deployments: 3 Jenkins Quality Gate Patterns with SonarQube

This tutorial demonstrates three methods to enforce SonarQube quality gates in Jenkins pipelines—freestyle job chaining, Pipeline waitForQualityGate step, and shared library encapsulation—so deployments only proceed when code meets coverage, duplication, and severity thresholds.

Cilantro Loves Linux
Cilantro Loves Linux
Cilantro Loves Linux
Block Bad Code Deployments: 3 Jenkins Quality Gate Patterns with SonarQube

Theory: What Is a Quality Gate?

A quality gate sets a hard threshold for code—e.g., new-code coverage ≥ 60%, no blocker/critical issues, duplication < 5%. When SonarQube analysis fails the gate, Jenkins marks the build failed/unstable and halts downstream deployment stages.

Jenkins + SonarQube Integration Flow

Jenkins triggers build, compiles, runs tests.

Jenkins invokes SonarQube scan via Maven plugin or sonar-scanner.

SonarQube evaluates the quality gate (OK/ERROR).

SonarQube calls back Jenkins through a webhook with the gate result.

Jenkins proceeds to deployment on OK; aborts on ERROR/FAILED.

In freestyle jobs, the Quality Gate post-build action (from SonarQube Scanner for Jenkins) marks the build failed when the gate fails. In Pipeline, the waitForQualityGate abortPipeline: true step blocks the pipeline until the webhook returns a result.

Docker-Compose Deployment Notes

The article's Jenkins runs in docker-compose:

services:
  jenkins:
    image: jenkins/jenkins:lts
    container_name: jenkins
    ports:
      - "8080:8080"
    volumes:
      - ./jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock

All build commands (mvn, kubectl, helm) execute inside the Jenkins container.

Enter the container with docker exec -it jenkins bash for debugging.

For deployment steps (e.g., kubectl to K8s), ensure the Jenkins image includes kubectl or mounts it, and that KUBECONFIG or cluster config is accessible.

Quality Gate & Webhook Configuration

Quality Gate policy in SonarQube for project k8s-dashboard:

New code coverage ≥ 60%

No blocker/critical issues in new code

Duplication < 5%

Set as default for the project.

Webhook to Jenkins (Administration → Configuration → Webhooks):

Name: jenkins-ci URL (same docker network): http://jenkins:8080/jenkins/sonarqube-webhook/ Or host IP:

http://192.168.145.129:8080/jenkins/sonarqube-webhook/

Prerequisites in Jenkins

SonarQube Scanner for Jenkins plugin installed.

SonarQube server named sonarqube configured.

Credential sonarqube-token created.

Global Tool Configuration: sonar-scanner at /opt/tools/sonar-scanner.

Three Implementation Approaches

Approach 1: Freestyle Job + Downstream Deployment Job

Job A ( k8s-dashboard-sonar-freestyle): checkout → Maven build → SonarQube scan → Quality Gate post-action (fail build on gate failure). Job B ( k8s-dashboard-deploy): triggered only when Job A is stable/successful. Build step uses echo placeholder for deployment verification.

echo "===== 开始部署 k8s-dashboard 到测试环境 ====="
echo "本次仅验证质量门阻断逻辑,暂不执行真实 kubectl 部署"
# kubectl apply -f k8s-dashboard-deployment.yaml
# kubectl apply -f k8s-dashboard-service.yaml
echo "✅ 部署阶段已到达,说明质量门通过后才会继续执行"

Result: Gate failure in Job A marks it failed → Job B not triggered.

Approach 2: Pipeline with waitForQualityGate (Recommended)

Pipeline job k8s-dashboard-ci-cd using Pipeline script from SCM (Git repo ssh://[email protected]:2222/root/k8s-dashboard.git, branch main, script Jenkinsfile).

Key Jenkinsfile snippet:

pipeline {
  agent any
  stages {
    stage('⏱ 等待质量门结果') {
      steps {
        timeout(time: 2, unit: 'MINUTES') {
          script {
            // Requires SonarQube Scanner for Jenkins plugin and webhook configured
            waitForQualityGate abortPipeline: true
          }
        }
      }
    }
    // stage('🚀 部署到测试环境') { ... } // commented during verification
  }
  post {
    success { echo "✅ 流水线执行完成:SonarQube 扫描与质量门验证成功" }
    failure { echo "❌ 流水线失败,请查看控制台日志:${env.BUILD_URL}console" }
  }
}

Key points: withSonarQubeEnv and mvn sonar:sonar reused from earlier validated config. waitForQualityGate() blocks until webhook callback; wrapped in timeout. abortPipeline: true fails the pipeline immediately on gate failure, skipping later stages.

Deployment stage placed after successful gate; commented out during local verification.

Docker-compose specifics:

Jenkins must reach SonarQube via service name sonarqube or host IP.

Because JENKINS_OPTS=--prefix=/jenkins, webhook URL must include /jenkins prefix. PENDING / IN_PROGRESS states are normal while SonarQube background task runs.

Approach 3: Shared Library my-shared-lib@main Encapsulation

For multiple microservices ( k8s-dashboard, user-service, order-service), encapsulate gate+deploy logic in a shared library.

Library structure:

my-shared-lib/
└── vars/
    ├── gitCheckout.groovy
    ├── mavenBuild.groovy
    ├── sonarScan.groovy
    └── qualityGateAndDeploy.groovy
vars/qualityGateAndDeploy.groovy

:

/**
 * Quality gate check + deploy composite function
 * @param config Map with:
 *   deployScript  - Shell script string (required)
 *   timeoutMinutes - wait timeout (default 3)
 */
def call(Map config = [:]) {
  def deployScript  = config.deployScript
  def timeoutMinutes = config.timeoutMinutes ?: 3

  if (!deployScript) {
    error 'qualityGateAndDeploy: deployScript is required'
  }

  stage('⏱ 等待质量门结果') {
    timeout(time: timeoutMinutes, unit: 'MINUTES') {
      script {
        def qg = waitForQualityGate()
        if (qg.status != 'OK') {
          error "质量门未通过,状态:${qg.status},原因:${qg.description}"
        }
        echo "✅ 质量门通过:${qg.status}"
      }
    }
  }

  stage('🚀 执行部署') {
    sh """
      echo "===== 开始执行部署(质量门已通过) ====="
      ${deployScript}
    """
  }
}

Configure library in Jenkins: Manage Jenkins → System → Global Pipeline Libraries → name my-shared-lib, default version main, Git SCM with credentials.

Project Jenkinsfile using the library:

@Library('my-shared-lib@main') _

pipeline {
  agent any
  tools { jdk 'JDK11'; maven 'Maven3.9.10' }
  environment {
    GIT_URL = 'ssh://[email protected]:2222/root/k8s-dashboard.git'
    BRANCH_NAME = 'main'
    SONAR_PROJECT_KEY = 'k8s-dashboard'
  }
  stages {
    stage('📥 标准化代码拉取') { steps { script { gitCheckout(repoUrl: GIT_URL, branch: BRANCH_NAME, depth: 1) } } }
    stage('🔨 标准化 Maven 构建') { steps { script { mavenBuild(goals: 'clean verify', skipTests: false) } } }
    stage('🔍 标准化 Sonar 扫描') { steps { script { sonarScan(projectKey: SONAR_PROJECT_KEY, projectName: 'k8s-dashboard', sonarServer: 'sonarqube', mavenGoals: 'clean verify') } } }
    stage('⛔ 质量门检查并按需部署') {
      steps {
        script {
          qualityGateAndDeploy(deployScript: '''
            echo "当前先验证共享库中的质量门链路,暂不执行真实部署"
            # kubectl apply -f k8s-dashboard-deployment.yaml
            # kubectl apply -f k8s-dashboard-service.yaml
          ''')
        }
      }
    }
  }
  post {
    success { echo """==================================
✅ k8s-dashboard 质量门通过,共享库链路验证成功
构建地址:${env.BUILD_URL}
==================================""" }
    failure { echo """==================================
❌ 质量门未通过或共享库链路执行失败
请查看控制台日志:${env.BUILD_URL}console
==================================""" }
  }
}

Effect: sonarScan uploads results; qualityGateAndDeploy waits for gate then runs deploy script. Any service reuses these two functions for consistent gate enforcement.

Summary & Selection Guide

Freestyle + Downstream Job

Best for: Existing freestyle jobs, simple deployment chains

Advantages: Visual config, low migration cost

Considerations: Logic split across jobs, limited cross-project reuse

Pipeline + waitForQualityGate

Best for: New projects, CI/CD as code

Advantages: Gate logic visible, auditable, rollback-friendly

Considerations: Requires Jenkinsfile/Groovy and plugin knowledge

Shared Library my-shared-lib@main

Best for: Multi-microservice, enterprise standardization

Advantages: Single maintenance point, uniform standards

Considerations: Needs library versioning, well-designed params/extension points

These three practices evolve a team from "build success = deploy" to "code must pass quality gate before deployment eligibility." For Maven Java projects like k8s-dashboard, moving the gate into the pipeline raises overall code quality and engineering discipline, laying groundwork for further governance (code ownership, change audit, canary releases).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CI/CDKubernetesPipelineSonarQubeShared LibraryJenkinsdocker-composeQuality Gate
Cilantro Loves Linux
Written by

Cilantro Loves Linux

Focused on Linux system operations and maintenance technology exchange, regularly publishing in-depth technical articles covering core areas such as system architecture, performance optimization, and security hardening. Whether you are a beginner or a seasoned expert, you can find valuable resources to enhance your skills and solve problems here. Follow us to explore the mysteries of Linux operations!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.