20 分钟搞定:Jenkins + Docker 一键流水线,自动构建镜像并部署到远程服务器

20 分钟搞定:Jenkins + Docker 一键流水线,自动构建镜像并部署到远程服务器

Jenkins 后端服务流水线部署脚本

节点设置

此处配置的节点是用来执行脚本中的每一个步骤(stage)的,包括但不限于代码构建、镜像构建/推送等

Groovy 复制代码
agent any
agent { label 'master' }
  • 可通过 agent 设置流水线使用到节点
    • any 表示任意节点
    • { label 'master' } 表示标签为 master 到节点
  • 此处可使用的节点可在节点和云管理查看。查看路径:右上角齿轮图标"系统设置" --> 节点和云管理 --> 节点列表
  • master 节点是内置节点,默认没有标签,可在 master 节点详情内 --> 配置从节点设置标签
  • 备注:设置节点标签时注意大小写、空格

环境变量设置

此处配置的环境变量可在整个脚本内使用,将动态的变量设置在此处可形成通用脚本,需要复制流水线时修改此处的变量即可

Groovy 复制代码
environment {
    // Git 仓库配置
	GIT_URL = 'git@git.xxx.com:xxx.git' // 替换为你的代码仓库
	GIT_KEY_ACR_CRED = 'git-ssh-key'
    // Docker 镜像相关配置
    DOCKER_IMAGE_REGISTRY = 'registry.xxx.aliyuncs.com'  // 替换为你的镜像仓库
    DOCKER_IMAGE_ACR_CRED = 'docker-cred'
    IMAGE_PRE_NAME = 'xxxx'  // 镜像名称前缀
    IMAGE_NAME = 'xxx-service'  // 替换为你的应用名称
    // 远程服务器
    REMOTE_HOST = 'xxx.xxx.xxx.xx' // 服务器 IP
    REMOTE_HOST_ACR_CRED = 'host-cred'
}
  • GIT_URL 代码仓库:存储代码的仓库,用来获取代码至 jenkins
  • GIT_KEY_ACR_CRED:访问代码仓库的凭据
  • DOCKER_IMAGE_REGISTRY 镜像仓库:存储 docker 镜像的仓库,可拉取/推送镜像
  • DOCKER_IMAGE_ACR_CRED:用来访问镜像仓库的凭据
  • IMAGE_PRE_NAME:镜像名称前缀
  • IMAGE_NAME:应用名称,用来拼接镜像名称
  • REMOTE_HOST 远程服务器 IP:我们需要运行服务的服务器 IP
  • REMOTE_HOST_ACR_CRED:用来访问远程服务器的凭据
  • DOCKER_IMAGE_ACR_CRED、DOCKER_IMAGE_ACR_CRED、REMOTE_HOST_ACR_CRED 需要去凭据管理 添加
    • 添加路径:右上角齿轮图标"系统设置" --> 凭据管理 --> 在界面上找到选一个点进去
    • 点击右上角Add Credentials添加
    • 类型可选择username with passwordSSH username with private key
    • 其中的 ID 就是我们需要的值,可根据喜好设置,不填写会自动生成

构建工具设置

这里设置构建代码的 Maven 工具

Groovy 复制代码
tools {
    // Install the Maven version configured as "M3" and add it to the path.
    maven "Maven3"
}
  • 这里设置的工具需要在全局工具配置添加
  • 添加路径:右上角齿轮图标"系统设置" --> 全局工具配置
  • 找到Maven 配置,这里可用设置 maven 本地仓库、settings.xml 文件
  • 找到Maven 安装安装 Maven 时注意 Name,这里填写的信息就是脚本中使用的
  • 安装 Maven 时可选择自动安装,可选版本。建议版本与开发保持一致

代码检出

拉取仓库中的代码 此操作属于运行在节点的步骤,需要添加在 stages 对象中

Groovy 复制代码
stage('Checkout') {
    steps {
        // Get some code from a GitHub repository
        git branch: 'master', 
        url: GIT_URL,
        credentialsId: GIT_KEY_ACR_CRED
    }
}
  • git branch: 'master':用于拉取的分支
  • url: GIT_URL
    • 设置代码仓库地址,可以使用环境变量中的值,也可直接填写代码仓库字符串**'git@git.xxx.com:xxx.git'**
  • credentialsId:用于设置仓库访问凭据

工程构建

使用 Maven 构建 Maven 工程中的 Java 代码 此操作属于运行在节点的步骤,需要添加在 stages 对象中

Groovy 复制代码
stage('Build') {
    steps {
        // Run Maven on a Unix agent.
        sh "mvn -Dmaven.test.failure.ignore=true clean package"

        // To run Maven on a Windows agent, use
        // bat "mvn -Dmaven.test.failure.ignore=true clean package"
    }

    post {
        // If Maven was able to run the tests, record the test results and archive the jar file.
        success {
            archiveArtifacts 'target/*.jar'
        }
    }
}
  • sh "mvn -Dmaven.test.failure.ignore=true clean package"
    • 先清理上次构建的产物,然后重新打包
  • post 是后置处理器
    • success 当这个步骤运行成功后所做的操作
    • 此处所做的操作是归档,可在流水线每次的运行记录内Build Artifacts位置找到

构建、推送 Dokcer 镜像

此操作属于运行在节点的步骤,需要添加在 stages 对象中

Groovy 复制代码
stage('Build and Push Docker Image') {
    steps {
        script {
            // 生成时间戳
            def timestamp = new Date().format('yyyyMMddHHmm', TimeZone.getTimeZone('Asia/Shanghai'))
            def imageTag = "${IMAGE_NAME}:${timestamp}"
            def fullImageNameWithTimestamp = "${DOCKER_IMAGE_REGISTRY}/${IMAGE_PRE_NAME}/${imageTag}"
            
            // 使用宿主机 Docker 构建镜像
            echo "Building Docker image: ${fullImageNameWithTimestamp}"
            sh "docker build -t ${fullImageNameWithTimestamp} ."
            
            withCredentials([usernamePassword(credentialsId: DOCKER_IMAGE_ACR_CRED, usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) {
                // 登录到镜像仓库
                echo "Login Docker..."
                sh "docker login --username \$REG_USER -p \$REG_PASS \$DOCKER_IMAGE_REGISTRY"
                // 推送镜像
                echo "Push Docker Image ${fullImageNameWithTimestamp}"
                sh "docker push ${fullImageNameWithTimestamp}"
            }
            
            // 输出构建信息
            echo "Successfully built and pushed image: ${fullImageNameWithTimestamp}"
            
            // 将镜像名称保存到环境变量,供后续步骤使用
            env.BUILT_IMAGE = fullImageNameWithTimestamp
        }
    }
}
  • 此处使用当前时间为镜像设置 tag
  • 镜像名称格式:<镜像仓库地址>/<镜像名称前缀>/<应用名称>:<当前时间>
  • sh "docker build -t ${fullImageNameWithTimestamp} ."
    • 使用 docker 构建镜像
  • withCredentials 使用凭据登陆、推送镜像
    • 登陆仓库: sh "docker login --username REG_USER -p REG_PASS $DOCKER_IMAGE_REGISTRY"
    • 推送镜像:sh "docker push ${fullImageNameWithTimestamp}"
    • 将镜像名称保存到环境变量,供后续步骤使用:env.BUILT_IMAGE = fullImageNameWithTimestamp

部署到远程服务器

此操作属于运行在节点的步骤,需要添加在 stages 对象中

Groovy 复制代码
stage('Deploy to Remote Host') {
    steps {
        withCredentials([usernamePassword(credentialsId: REMOTE_HOST_ACR_CRED, usernameVariable: 'REMOTE_USER', passwordVariable: 'REMOTE_PWD')]) {
            sh """
            sshpass -p \$REMOTE_PWD ssh -T -o StrictHostKeyChecking=no \
            \$REMOTE_USER@${REMOTE_HOST} << 'EOF'
            # 去往工作目录
            cd /app/${IMAGE_NAME}
            # 修改 .env 文件
            sed -i '/${IMAGE_NAME}/c\\SERVICE_V=${BUILT_IMAGE}' .env
            # 停止目标服务
            docker-compose stop ${IMAGE_NAME}
            # 删除目标容器
            docker-compose rm -f ${IMAGE_NAME}
            # 启动目标容器
            docker-compose up -d ${IMAGE_NAME}
EOF
            """
        }
    }
}
  • withCredentials:使用凭据连接远程服务器
  • 此处使用 sshpass 连接到远程服务器,这里部署 Jenkins 的容器/服务器中需要提前安装 sshpass
  • 此处 << 'EOF' ... EOF 不能缺失,末尾的EOF需要独占一行且前方不得有任何字符字符
  • cd /app/${IMAGE_NAME}
    • 定位至远程服务器的工作目录
  • sed -i '/ <math xmlns="http://www.w3.org/1998/Math/MathML"> I M A G E N A M E / c S E R V I C E V = {IMAGE_NAME}/c\\SERVICE_V= </math>IMAGENAME/cSERVICEV={BUILT_IMAGE}' .env
    • 修改 docker-compose 的配置文件,将 docker-compose 启动使用的镜像修改为前述步骤推送至仓库的镜像
  • 停止服务:docker-compose stop ${IMAGE_NAME}
  • 删除目标容器:docker-compose rm -f ${IMAGE_NAME}
  • 启动目标容器:docker-compose up -d ${IMAGE_NAME}

脚本源码

Groovy 复制代码
pipeline {
    agent { label 'master' }
    
    environment {
        // Git 仓库配置
    	GIT_URL = 'git@git.xxx.com:xxx.git' // 替换为你的代码仓库
    	GIT_KEY_ACR_CRED = 'git-ssh-key'
        // Docker 镜像相关配置
        DOCKER_IMAGE_REGISTRY = 'registry.xxx.aliyuncs.com'  // 替换为你的镜像仓库
        DOCKER_IMAGE_ACR_CRED = 'docker-cred'
        IMAGE_PRE_NAME = 'xxxx'  // 镜像名称前缀
        IMAGE_NAME = 'xxx-service'  // 替换为你的应用名称
        // 远程服务器
        REMOTE_HOST = 'xxx.xxx.xxx.xx' // 服务器 IP
        REMOTE_HOST_ACR_CRED = 'host-cred'
    }
    
    tools {
        // Install the Maven version configured as "M3" and add it to the path.
        maven "Maven3"
    }

    stages {
        stage('Checkout') {
            steps {
                // Get some code from a GitHub repository
                git branch: 'master', 
                url: GIT_URL,
                credentialsId: GIT_KEY_ACR_CRED
            }
        }
        
        stage('Build') {
            steps {
                // Run Maven on a Unix agent.
                sh "mvn -Dmaven.test.failure.ignore=true clean package"

                // To run Maven on a Windows agent, use
                // bat "mvn -Dmaven.test.failure.ignore=true clean package"
            }

            post {
                // If Maven was able to run the tests, record the test results and archive the jar file.
                success {
                    archiveArtifacts 'target/*.jar'
                }
            }
        }
        
        stage('Build and Push Docker Image') {
            steps {
                script {
                    // 生成时间戳
                    def timestamp = new Date().format('yyyyMMddHHmm', TimeZone.getTimeZone('Asia/Shanghai'))
                    def imageTag = "${IMAGE_NAME}:${timestamp}"
                    def fullImageNameWithTimestamp = "${DOCKER_IMAGE_REGISTRY}/${IMAGE_PRE_NAME}/${imageTag}"
                    
                    // 使用宿主机 Docker 构建镜像
                    echo "Building Docker image: ${fullImageNameWithTimestamp}"
                    sh "docker build -t ${fullImageNameWithTimestamp} ."
                    
                    withCredentials([usernamePassword(credentialsId: DOCKER_IMAGE_ACR_CRED, usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) {
                        // 登录到镜像仓库
                        echo "Login Docker..."
                        sh "docker login --username \$REG_USER -p \$REG_PASS \$DOCKER_IMAGE_REGISTRY"
                        // 推送镜像
                        echo "Push Docker Image ${fullImageNameWithTimestamp}"
                        sh "docker push ${fullImageNameWithTimestamp}"
                    }
                    
                    // 输出构建信息
                    echo "Successfully built and pushed image: ${fullImageNameWithTimestamp}"
                    
                    // 将镜像名称保存到环境变量,供后续步骤使用
                    env.BUILT_IMAGE = fullImageNameWithTimestamp
                }
            }
        }
        
        stage('Deploy to Remote Host') {
            steps {
                withCredentials([usernamePassword(credentialsId: REMOTE_HOST_ACR_CRED, usernameVariable: 'REMOTE_USER', passwordVariable: 'REMOTE_PWD')]) {
                    sh """
                    sshpass -p \$REMOTE_PWD ssh -T -o StrictHostKeyChecking=no \
                    \$REMOTE_USER@${REMOTE_HOST} << 'EOF'
                    # 去往工作目录
                    cd /app/${IMAGE_NAME}
                    # 修改 .env 文件
                    sed -i '/${IMAGE_NAME}/c\\SERVICE_V=${BUILT_IMAGE}' .env
                    # 停止目标服务
                    docker-compose stop ${IMAGE_NAME}
                    # 删除目标容器
                    docker-compose rm -f ${IMAGE_NAME}
                    # 启动目标容器
                    docker-compose up -d ${IMAGE_NAME}
EOF
                    """
                }
            }
        }
        
    }
}
相关推荐
用户4099322502124 小时前
如何在 FastAPI 中巧妙覆盖依赖注入并拦截第三方服务调用?
后端·ai编程·trae
泉城老铁4 小时前
Spring Boot中实现多线程分片下载
java·spring boot·后端
泉城老铁4 小时前
Spring Boot中实现多文件打包下载
spring boot·后端·架构
泉城老铁4 小时前
Spring Boot中实现大文件分片下载和断点续传功能
java·spring boot·后端
码事漫谈4 小时前
C++中虚函数与构造/析构函数的深度解析
后端
百思可瑞教育4 小时前
Spring Boot 参数校验全攻略:从基础到进阶
运维·服务器·spring boot·后端·百思可瑞教育·北京百思教育
武子康5 小时前
大数据-89 Spark应用必备:进程通信、序列化机制与RDD执行原理
大数据·后端·spark
shark_chili5 小时前
JITWatch实战指南:深入Java即时编译优化的黑科技工具
后端
绝无仅有5 小时前
从拉取代码到前端运行访问:Vue 前端项目的常规启动流程
后端·面试·github