一次完整的Jenkins部署

具体场景

Jenkins以Docker运行,流水线任务需要部署Spring Boot项目到新的容器中

Jenkins安装

启动

networks:
  1panel-network:
    external: true

volumes:
  jenkins_data:
    external: true

services:
  jenkins:
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkins/jenkins:lts-jdk17
    ports:
      - "20071:8080"     # Web 访问端口
      - "50000:50000"    # 添加Agent通信端口
    volumes:
      - jenkins_data:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/bin/docker:/usr/bin/docker
      - /usr/libexec/docker/cli-plugins/docker-compose:/usr/libexec/docker/cli-plugins/docker-compose
      - /opt/1panel/apps/jenkins/jenkins/tmp:/compose-config/server@tmp		# Jenkins流水线执行命令时会有临时路径
      - /opt/1panel/apps/server/server:/compose-config/server:rw    # Java后端项目目录
    networks:
      - 1panel-network
    restart: on-failure
    container_name: jenkins        # 固定容器名称,便于维护
    user: "1000"                   # 避免使用root用户(提高安全性)
    environment:
      - TZ=Asia/Shanghai           # 时区设置
    security_opt:
      - no-new-privileges          # 禁止权限提升
    group_add:
      - "${DOCKER_GID}"            # 需获取宿主机docker组的GID
#!/bin/bash

# Jenkins服务管理脚本

COMPOSE_FILE="/opt/1panel/apps/jenkins/jenkins/docker-compose.yaml"
CONTAINER_NAME="jenkins"

# 获取docker组GID
export DOCKER_GID=$(getent group docker | cut -d: -f3)

# 检查是否为root用户
check_root() {
    if [ "$(id -u)" != "0" ]; then
        echo "请使用root权限运行此脚本"
        exit 1
    fi
}

# 启动Jenkins
start() {
    echo "正在启动Jenkins服务..."
    # 创建并授权卷
    docker volume create jenkins_data
    sudo chown -R 1000:1000 $(docker volume inspect jenkins_data -f '{{.Mountpoint}}')
    # 启动服务
    docker compose -f $COMPOSE_FILE up -d
    if [ $? -eq 0 ]; then
        echo "Jenkins服务已成功启动"
    else
        echo "Jenkins服务启动失败"
        exit 1
    fi
}

# 停止Jenkins
stop() {
    echo "正在停止Jenkins服务..."
    docker compose -f $COMPOSE_FILE down
    if [ $? -eq 0 ]; then
        echo "Jenkins服务已成功停止"
    else
        echo "Jenkins服务停止失败"
        exit 1
    fi
}

# 检查Jenkins状态
status() {
    if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
        echo "Jenkins服务正在运行"
        docker ps --filter name=${CONTAINER_NAME} --format "容器ID: {{.ID}}\n状态: {{.Status}}\n端口: {{.Ports}}"
    else
        echo "Jenkins服务未运行"
    fi
}

# 使用说明
usage() {
    echo "使用方法: $0 {start|stop|status}"
    echo "  start  - 启动Jenkins服务"
    echo "  stop   - 停止Jenkins服务"
    echo "  status - 查看Jenkins服务状态"
    exit 1
}

# 主程序
case "$1" in
    start)
        check_root
        start
        ;;
    stop)
        check_root
        stop
        ;;
    status)
        status
        ;;
    *)
        usage
        ;;
esac

exit 0

准备工作

1、启动:略,教程很多;这里我建议先不要下载插件,后面我们配置完镜像源后再下载自己需要的;

2、替换镜像源:清华源

在宿主机执行命令更新文件;PS:如果完全按照我上面的文件运行的Jenkins的情况下

sed -i 's|updates.jenkins.io/download|mirrors.tuna.tsinghua.edu.cn/jenkins|g' /var/lib/docker/volumes/jenkins_data/_data/updates/default.json
sed -i 's|www.google.com|www.baidu.com|g' /var/lib/docker/volumes/jenkins_data/_data/updates/default.json

3、配置Maven(系统管理 --> 全局工具配置 --> Maven 安装)
image

4、插件:Chinese (Simplified)、Git、DingTalk、Pipeline、Pipeline Utility Steps、Docker API Plugin、Docker Pipeline、Timestamper、Workspace Cleanup Plugin

搭建流水线

我这个搭建就很简单了,总共就两步

第一步:新建任务
image

第二步:Pipeline脚本,按照注释修改成自己所需要的

pipeline {
    agent any
    tools {
        maven 'apache-maven-3.9.11'
    }
    environment {
        // Docker 镜像信息
        APP_NAME = "app"
        DOCKER_REGISTRY = "registry.cn-hangzhou.aliyuncs.com"
        IMAGE_TAG = "${BUILD_ID}" // 使用构建ID作为镜像标签
        
        // 项目路径配置
        COMPOSE_PATH = "/compose-config/server"
        DOCKER_COMPOSE_FILE = "${COMPOSE_PATH}/docker-compose.yml"
        ENV_FILE = "${COMPOSE_PATH}/.env"
        APPLICATION_YML = "${COMPOSE_PATH}/application.yml"
    }
    stages {
        // 阶段 1: 代码检出
        stage('Checkout') {
            steps {
                script {
                    // 先获取代码
                    git branch: 'DEV_BASE',     // 你的分支
                    url: '',    // 你的代码地址
                    credentialsId: ''   // 你的Jenkins凭证ID
                    
                    // 获取最新commit message
                    env.COMMIT_MESSAGE = sh(
                        script: 'git log -1 --pretty=format:"%s"',
                        returnStdout: true
                    ).trim()
                    
                    echo "✅ 获取到提交信息: ${env.COMMIT_MESSAGE}"
                }
            }
        }
        
        // 阶段 2: Maven 构建
        stage('Maven Build') {
            steps {
                script {
                    // 确定目标jar包的实际路径
                    env.JAR_PATH = sh(
                        script: 'find . -name app.jar -print -quit',    // 这里记得替换成你的项目构建完成后的jar包名
                        returnStdout: true
                    ).trim()
                    
                    if (!env.JAR_PATH) {
                        error "❌ 找不到 app.jar 文件"
                    }
                    
                    echo "✅ 找到jar包位置: ${env.JAR_PATH}"
                }
                
                sh 'mvn clean package -DskipTests'
            }
        }
        
        // 阶段 3: 构建 Docker 镜像
        stage('Build Image') {
            steps {
                script {
                    // 登录阿里云容器镜像服务
                    withCredentials([usernamePassword(
                        credentialsId: 'aliyun-docker-creds',
                        usernameVariable: 'REG_USER',
                        passwordVariable: 'REG_PASSWORD'
                    )]) {
                        sh """
                        echo ${REG_PASSWORD} | docker login -u ${REG_USER} --password-stdin registry.cn-hangzhou.aliyuncs.com
                        """
                    }
                    // 上面这一步是因为我的Dockerfile里面采用私有镜像文件,不需要可以不要
                    
                    // 使用动态确定的jar路径
                    sh """
                    docker build \
                        -t ${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG} \
                        --build-arg JAR_PATH=${env.JAR_PATH} \
                        .
                    """
                }
            }
        }
        
        // 阶段 4: 更新 docker-compose 配置
        stage('Update Config') {
            steps {
                script {
                    // 更新 .env 文件中的镜像标签
                    sh '''
                        sed -i -r "s|IMAGE=.*|IMAGE=${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}|g" ${ENV_FILE}
                    '''
                }
            }
        }
        
        // 阶段 5: Docker Compose 部署
        stage('Deploy') {
            steps {
                script {
                    // 切换到 docker-compose 目录
                    dir(COMPOSE_PATH) {
                        // 删除旧容器 (保留数据卷)
                        sh 'docker compose down'
                        
                        // 使用 docker-compose 启动服务
                        sh 'docker compose up -d'
                        
                        // 清理旧镜像 (保留最近3次构建)
                        sh '''
                        CURRENT_IMAGE=${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}
                        docker images --format "{{.Repository}}:{{.Tag}}" \
                          | grep "${DOCKER_REGISTRY}/${APP_NAME}" \
                          | grep -v "${IMAGE_TAG}" \
                          | sort -Vr | tail -n +4 \
                          | xargs -r docker rmi 2>/dev/null || true
                        '''
                    }
                }
            }
        }
    }
    post {
        always {
            script {
                // 清理 Docker 登录凭证
                sh 'docker logout registry.cn-hangzhou.aliyuncs.com || true'
            }
        }
        success {
            echo "✅ ${APP_NAME} 部署成功! 镜像版本: ${IMAGE_TAG}"
        }
        failure {
            script {
                // 安全获取提交信息
                def commitMsg = env.COMMIT_MESSAGE ?: "无法获取提交信息"
                
                // 使用钉钉机器人ID发送通知
                dingtalk (
                    robot: '',      // 这里是之前安装的钉钉的消息推送配置的机器人ID,不需要这一整块都可以删除
                    type: 'ACTION_CARD',
                    title: "❌ ${APP_NAME} 构建失败通知",
                    text: [
                        "# 🔔 Jenkins构建失败通知",
                        "",
                        "### 📋 构建信息",
                        "---",
                        "- 🏷️ **应用名称**:`${APP_NAME}`",
                        "- 🔨 **构建编号**:`#${BUILD_NUMBER}`",
                        "- 📦 **镜像标签**:`${IMAGE_TAG}`",
                        "- 📝 **提交信息**:`${commitMsg}`",
                        "",
                        "### 🔍 快速操作",
                        "---",
                        "点击下方按钮查看详细信息"
                    ],
                    btnLayout: 'H',
                    btns: [
                        [title: '📄 查看构建日志', actionUrl: "${env.BUILD_URL}console"],
                        [title: '🏠 返回Jenkins首页', actionUrl: "${env.JENKINS_URL}"]
                    ]
                )
                
                // 控制台输出
                echo "❌ ${APP_NAME} 部署失败!"
                echo "提交信息: ${commitMsg}"
            }
        }
    }
}

第三步:其他都不用操作,直接保存就行

posted @ 2025-07-18 13:45  YuXuanTM  阅读(93)  评论(0)    收藏  举报