JenkinsFile完整CI/CD流程实用案例

通过此JenkinsFile实现 

拉取->编译->测试->代码质量扫描->docker镜像构建->构建后推送至harbor->部署->清理工作区与通知

​ ps:Triggers触发器部分待完成后添加

一 环境介绍:

​ 三台虚拟机,Debian12,提前将地址信息写入所有虚拟机/etc/hosts文件

​ Jenkins: jen.70o70.com,192.168.8.100

​ harbor: jen.70o70.com,192.168.8.100

​ Gitlab: git.70o70.com,192.168.8.101

​ SonarQube: reg.70o70.com,192.168.8.102

​ Jenkins node: linux.agent,192.168.8.102

二 部署阶段

1、部署Jenkins
# 准备jdk环境
apt install openjdk-17-jdk

# 下载并安装Jenkins.deb包
wget https://mirrors.ustc.edu.cn/jenkins/debian-stable/jenkins_2.504.2_all.deb
dpkg -i jenkins_2.504.2_all.deb

# 运行脚本测试jenkins国内插件源速度
curl -sSL https://cdn.jsdelivr.net/gh/lework/jenkins-update-center/speed-test.sh | bash

# 修改Jenkins插件下载源,没有就新建
vim /var/lib/jenkins/hudson.model.UpdateCenter.xml
<?xml version='1.1' encoding='UTF-8'?>
<sites>
  <site>
    <id>default</id>
    <url>https://mirrors.huaweicloud.com/jenkins/update-center.json</url>
  </site>
</sites>
# 删除Jenkins更新缓存
rm -rf /var/lib/jenkins/updates/default.json
2、部署Gitlab

​ Gitlab较为占用资源,建议最小6G内存

# 请优先参考官网教程
https://gitlab.cn/install/

# 安装依赖
apt install -y curl openssh-server ca-certificates tzdata perl
# 配置软件源
curl -L get.gitlab.cn | bash
# apt安装
apt install -y gitlab-jh
# 修改url
grep ^[^#] /etc/gitlab/gitlab.rb
external_url 'http://git.70o70.com'

# 访问http://git.70o70.com
# 查看默认密码 用户名root 
cat /etc/gitlab/initial_root_password
3、部署docker harbor
# 先部署docker环境,这里不再赘述

# github下载离线包
wget https://github.com/goharbor/harbor/releases/download/v2.13.1/harbor-offline-installer-v2.13.1.tgz

# 创建工作目录
mkdir /apps
# 解压
tar xzf harbor-offline-installer-v2.13.0.tgz -C /apps/
cd /apps/harbor/
# 拷贝配置文件模板
cp harbor.yml.tmpl harbor.yml

# 修改hostname,测试环境注释443端口相关,修改admin密码
grep ^[^#] harbor.yml
hostname: jen.70o70.com
http:
port
  port: 80
  #  port: 443
  # The path of cert and key files for nginx
  #  certificate: /your/certificate/path
  #  private_key: /your/private/key/path
  # strong_ssl_ciphers: false
harbor_admin_password: 123456

# 创建一个harbor service文件,方便启停
vim /lib/systemd/system/harbor.service
[Unit]
Description=Harbor Cloud Native Registry
Documentation=https://goharbor.io
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/apps/harbor
ExecStart=/usr/bin/docker compose -f docker-compose.yml up -d
ExecStop=/usr/bin/docker compose -f docker-compose.yml down -v
ExecStopPost=/usr/bin/docker compose -f docker-compose.yml rm -f

[Install]
WantedBy=multi-user.target

# 加载service,设置开机自启
systemctl daemon-reload
systemctl enable --now harbor.service

# docker添加本地仓库http信任,建议所有安装docker的测试节点都添加
cat /etc/docker/daemon.json
{
  "insecure-registries": ["jen.70o70.com", "192.168.8.100"]
}
4、部署SonarQube

详见另一篇笔记https://www.cnblogs.com/publichotspot/p/18923197

192.168.8.102虚拟机也作jenkins node使用,需部署将要用到的docker环境

三 添加插件与设置环境

1,Jenkins添加插件
  • Docker Pipeline,Docker plugin (流水线调用docker使用)

​ 部署参考https://www.cnblogs.com/publichotspot/p/18923042
​ Jenkins添加harbor登录凭证,根据路径进入添加

  • webhook(后续触发器使用)

  • Gitlab plugin (调用gitlab使用)

​ 为jenkins创建令牌供调用令牌拉取gitlab仓库内容
​ 进入gitlib->项目->设置->访问令牌->添加新令牌

​ 创建时最小权限原则,选择read_repository只读.角色这里选择Developer

​ Jenkins添加令牌至全局变量

  • config file provider(使用自定maven配置文件)
# 可以使用阿里加速地址
<mirrors>
    <mirror>
        <id>Aliyun</id>
        <mirrorOf>*</mirrorOf>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
</mirrors>

  • DingTalk(钉钉通知)

    部署参考https://www.cnblogs.com/publichotspot/p/18925910

2,Jenkins agent配置

​ 部署参考https://www.cnblogs.com/publichotspot/p/18923042
文章内的静态节点部分

# 后台拉起Jenkins agent
nohup java -Xms256m -Xmx256m -jar agent.jar -url http://jen.70o70.com:8080/ -secret 8c465be9b208edf450bd8693145082285c24789a4e43bf2a883d9b8f8004618e -name "linux.agent" -webSocket -workDir "/home/jenkins"
3,docker镜像

将会用到两个docker镜像

# docker 镜像已上传夸克,需要请自取
# 链接:https://pan.quark.cn/s/644355e8a669
# 提取码:QR4R

​ docker load -i maven:3.9-eclipse-temurin-17-alpine

​ docker load -i eclipse-temurin:17-jdk-alpine

四 JenkinsFile

点击查看代码
pipeline {
    agent none // [1] 在顶层不指定全局agent,让每个阶段按需分配
    parameters {
        booleanParam(name: 'pushImage', defaultValue: true, description: 'Push Image to Harbor and Deploy?')
    }
    // 定义环境变量
    environment {
        // [2] 镜像仓库及项目信息
        REGISTRY = 'jen.70o70.com'
        PROJECT_NAME = 'spring-boot-helloworld'
        IMAGE_URL = "${REGISTRY}/test/${PROJECT_NAME}"
        IMAGE_TAG = "${BUILD_ID}"
        // [3] SonarQube 服务器配置名称
        SONARQUBE_ENV = 'SonarQube'
    }

    stages {
        // =================================================================
        // 阶段 1: 在动态的Maven容器中进行编译、测试和代码扫描
        // =================================================================
        stage('Build, Test & Scan') {
            agent {
                // [4] 使用一个包含Maven和JDK的Docker镜像作为此阶段的执行环境
                docker {
                    image 'maven:3.9-eclipse-temurin-17-alpine'
                    label 'linux.agent'
                    args '--add-host=reg.70o70.com:192.168.8.102'
                }
            }
            steps {
                // [5] 拉取代码
                git branch: 'main',
                    credentialsId: 'gitlab-readonly-credential',
                    url: "http://git.70o70.com/long/spring-boot-helloWorld.git"

                // [6] 编译、测试和打包
                configFileProvider([configFile(fileId: '702be63f-95f4-481e-aa9e-0a8200e14cae', variable: 'MAVEN_SETTINGS')]) {
                    sh "mvn -s ${MAVEN_SETTINGS} -B -DskipTests clean package"
                    sh "mvn -s ${MAVEN_SETTINGS} test"
                }

                // [7] 执行 SonarQube 扫描
                withSonarQubeEnv("${SONARQUBE_ENV}") {
                    sh 'mvn sonar:sonar'
                }
                timeout(time: 30, unit: 'MINUTES') {
                    waitForQualityGate abortPipeline: true
                }

                // [8] 核心步骤:暂存构建产物
                // 将编译好的JAR文件和Dockerfile打包暂存,以便后续阶段使用
                echo 'Stashing build artifacts...'
                stash includes: 'target/*.jar, Dockerfile', name: 'build-artifacts'
            }
        }

        // =================================================================
        // 阶段 2: 在一个专门的Agent节点上制作并推送镜像
        // =================================================================
        stage('Build & Push Image') {
            agent {
                // [9] 指定一个专门用于Docker操作的agent节点
                label 'linux.agent'
            }
            steps {
                // [10] 核心步骤:取出之前暂存的构建产物
                echo 'Unstashing build artifacts...'
                unstash 'build-artifacts'

                // [11] 使用取出的文件构建镜像
                // Dockerfile和JAR文件现在都在当前工作空间中
                script {
                    withCredentials([usernamePassword(
                        credentialsId: 'a504ce8e-9b2b-41e6-bc02-22c6afd4dd8e',
                        usernameVariable: 'REG_USER',
                        passwordVariable: 'REG_PASS'
                    )]) {
                        sh "docker login -u ${REG_USER} -p ${REG_PASS} ${REGISTRY}"
                        sh "docker build -t ${IMAGE_URL}:${IMAGE_TAG} ."
                        sh "docker push ${IMAGE_URL}:${IMAGE_TAG}"
                        sh "docker tag ${IMAGE_URL}:${IMAGE_TAG} ${IMAGE_URL}:latest"
                        sh "docker push ${IMAGE_URL}:latest"
                    }
                }
            }
        }
        stage('Deploy to Docker') {
            when { expression { params.pushImage } }
            agent { label 'linux.agent' }
            steps {
                script {
                    withCredentials([usernamePassword(
                        credentialsId: 'a504ce8e-9b2b-41e6-bc02-22c6afd4dd8e',
                        usernameVariable: 'REG_USER',
                        passwordVariable: 'REG_PASS'
                        )]) {
                            sh "docker login -u ${REG_USER} -p ${REG_PASS} ${REGISTRY}"
                        }
                        sh "docker stop ${PROJECT_NAME} || true"
                        sh "docker rm ${PROJECT_NAME} || true"
                        sh """
                        docker run -d \\
                        --name ${PROJECT_NAME} \\
                        -p 8080:8888 \\
                        --restart always \\
                        ${IMAGE_URL}:${IMAGE_TAG}
                        """
                }
            }
        }
    }

    // =================================================================
    // 构建后操作
    // =================================================================
    post {
        always {
            // 在 post 块中,使用 script 块来调用需要 agent 的步骤
            script {
                // 使用 node 来获取一个 agent 的执行上下文
                node('linux.agent') {
                    echo "Running post-build actions on agent..."
                    cleanWs()
                    dingtalk(
                        robot: 'DingTalkRobot01',
                        type: 'TEXT',
                        text: ["构建完成"]
                    )
                }
            }
        }
    }
}

posted @ 2025-06-12 20:29  公共热点  阅读(120)  评论(0)    收藏  举报