专栏: 云原生 & DevOps
难度: 入门
标签: Jenkins CI/CD 流水线 Pipeline 自动化部署


前言

Jenkins 是国内用得最广的 CI/CD 工具。本文用一个完整的 Java 微服务项目,演示从代码提交到生产部署的全流程。


一、Jenkins 安装

# Docker方式(推荐,环境隔离)
docker run -d \
  --name jenkins \
  -p 8080:8080 -p 50000:50000 \
  -v jenkins_home:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  jenkins/jenkins:lts-jdk17

# 获取初始密码
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

二、Jenkinsfile 完整示例

// Jenkinsfile(存放在代码仓库根目录)
pipeline {
    agent any
    
    environment {
        APP_NAME    = 'myapp'
        IMAGE_REPO  = 'registry.example.com/myapp'
        K8S_NS      = 'production'
        GIT_CRED    = credentials('git-credentials')
    }
    
    options {
        buildDiscarder(logRotator(numToKeepStr: '10'))
        timeout(time: 30, unit: 'MINUTES')
        disableConcurrentBuilds()
    }
    
    triggers {
        // 监听GitHub webhook,push时自动触发
        githubPush()
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
                script {
                    env.GIT_COMMIT_SHORT = sh(
                        script: 'git rev-parse --short HEAD',
                        returnStdout: true
                    ).trim()
                    env.IMAGE_TAG = "${env.BUILD_NUMBER}-${env.GIT_COMMIT_SHORT}"
                }
            }
        }
        
        stage('Build') {
            steps {
                sh 'mvn clean package -DskipTests -q'
            }
        }
        
        stage('Unit Test') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    // 发布测试报告
                    junit 'target/surefire-reports/**/*.xml'
                }
            }
        }
        
        stage('Docker Build & Push') {
            steps {
                script {
                    withCredentials([usernamePassword(
                        credentialsId: 'registry-credentials',
                        usernameVariable: 'REGISTRY_USER',
                        passwordVariable: 'REGISTRY_PASS'
                    )]) {
                        sh """
                            docker login -u ${REGISTRY_USER} -p ${REGISTRY_PASS} registry.example.com
                            docker build -t ${IMAGE_REPO}:${IMAGE_TAG} .
                            docker push ${IMAGE_REPO}:${IMAGE_TAG}
                            docker rmi ${IMAGE_REPO}:${IMAGE_TAG}
                        """
                    }
                }
            }
        }
        
        stage('Deploy to Staging') {
            steps {
                sh """
                    kubectl set image deployment/${APP_NAME} \
                        ${APP_NAME}=${IMAGE_REPO}:${IMAGE_TAG} \
                        -n staging
                    kubectl rollout status deployment/${APP_NAME} -n staging --timeout=300s
                """
            }
        }
        
        stage('Smoke Test') {
            steps {
                sh 'sleep 10'
                sh 'curl -f http://staging.example.com/health || exit 1'
            }
        }
        
        stage('Deploy to Production') {
            when {
                branch 'main'
            }
            input {
                message '确认发布到生产环境?'
                ok '确认发布'
            }
            steps {
                sh """
                    kubectl set image deployment/${APP_NAME} \
                        ${APP_NAME}=${IMAGE_REPO}:${IMAGE_TAG} \
                        -n production
                    kubectl rollout status deployment/${APP_NAME} -n production --timeout=300s
                """
            }
        }
    }
    
    post {
        success {
            // 企业微信通知
            sh """
                curl -X POST 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY' \
                -H 'Content-Type: application/json' \
                -d '{"msgtype":"markdown","markdown":{"content":"## 构建成功\\n**项目:** ${APP_NAME}\\n**版本:** ${IMAGE_TAG}\\n**分支:** ${env.BRANCH_NAME}"}}'
            """
        }
        failure {
            sh """
                curl -X POST 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY' \
                -H 'Content-Type: application/json' \
                -d '{"msgtype":"markdown","markdown":{"content":"## 构建失败 \\n**项目:** ${APP_NAME}\\n**阶段:** ${env.STAGE_NAME}\\n**详情:** ${env.BUILD_URL}"}}'
            """
        }
        always {
            cleanWs()
        }
    }
}

三、常见问题解决

# Jenkins容器内运行docker命令无权限
docker exec -u root jenkins chmod 666 /var/run/docker.sock

# Kubectl在Jenkins中使用(挂载kubeconfig)
docker run -v ~/.kube:/root/.kube jenkins/jenkins:lts

# 流水线中获取环境变量
sh 'printenv | sort'

结语: Jenkins的核心价值在于把所有重复的手工操作自动化。一个好的Jenkinsfile就是一份可执行的发布手册。

更多推荐