docker +jenkins使用pipeline方式发布springboot项目到远程服务器

众所周知,jenkins更新到2.0了,2.0版本的特点之一就是Pipeline as Code,这里我们来体验下编写pipeline代码发布项目

1. 操作系统是ubuntu
2. jenkins是运行在docker容器中的
3. 目标服务器上有docker环境。部署过程是把jar包和脚本生成的Dockerfile,deploy.sh一起发送到目标服务器上,执行deploy.sh把jar打包成docker镜像再启动镜像

关于如何在docker中运行jenkins,网上教程一搜一大把,我就不细说了,主要的shell命令我会贴出来

# ubuntu安装docker
参考:https://www.runoob.com/docker/ubuntu-docker-install.html
# docker安装jenkins
sudo docker pull jenkins/jenkins
# 运行docker镜像
sudo docker run -d -p 10240:8080 -p 10241:50000 -v /home/jenkins_mount:/var/jenkins_home -v /etc/localtime:/etc/localtime --name my-jenkins jenkins/jenkins
# 其中/home/jenkins_mount(自定义,不一定非要是这个目录)为jenkins挂载在宿主机上的目录,jenkins初始登陆密码也在这里,后期构建代码,历史,自动安装的jdk,maven等文件都在这里,可以这么理解(jenkins运行后,里面提到的一切指向/var/jenkins_home/**地址其实都是指向/home/jenkins_mount/**)

1.前期准备

安装必要的jenkins插件:

  • Maven Integration plugin : 因为springboot项目是基于maven构建的,需要maven打包
  • Pipeline : jenkins初始化的时候会默认安装
  • Publish Over SSH : 因为我们要发往远程服务器,所以要装,如果本地docker运行项目,则不需要这个插件
  • Blue Ocean : 蓝海了,UI插件,选装,安装后访问地址:【jenkins地址】/blue

2.配置jenkins

2.1 配置SSH

进入Manage Jenkins -> Configure System找到 Publish over SSH(安装了Publish Over 	SSH插件才有这项)

SSH Servers主要配置如下:

SSH Server Name: ssh配置名称(自定义)记住这个名称,pipeline代码中要用到
Hostname: 主机IP
Username: ssh账户名
Remote Directory: 远程路径,可以理解为ssh连接上后自动cd到目录
port: ssh端口,一般默认为22
Proxy password: ssh密码

2.2 配置Maven环境

  • 进入Manage Jenkins -> Global Tool Configuration找到最下面 Maven(安装了Maven Integration plugin件才有这项)
  • 选择Maven安装
    这里有两个方式可以选:
    1.使用宿主机的maven环境
    2.让jenkins自己安装Maven并使用默认Maven设置
    我这里选择第二种
    Maven安装配置如下:
Maven Name: maven的名称
自动安装: 勾选上,(从Apache安装)选择版本。
# 构建项目的时候选择这个Maven Name的maven环境,第一次构建检测到没有该Maven环境的话jenkins会自动安装,所以第一次构建巨慢😭

⚠️ 注意

我这里使用的是在docker中运行jenkins,如果宿主机有maven环境直接配置到jenkins里面肯定用不了,需要用docker的数据卷 -v 挂载到jenkins里面才可以访问。

⚠️ 注意

3.新建Item

3.1 进入jenkins主界面新建Item

  • 这里简略直接新建构建功能,实际情况下可能要新建文件夹来对项目进行分类

3.2 选择流水线(Pipeline)

3.3 General配置

  • 选择丢弃旧的构建(最好配置一下,防止占机器磁盘)
策略: Log Rotation
保持构建的天数: 不设置
保持构建的最大个数: 视情况设置

流水线(Pipeline)配置

  • 定义:选择 Pipeline script 或者 Pipeline script from SCM

Pipeline script: 需要在jenkins里面写pipeline脚本
Pipeline script from SCM: 需要在项目一级目录下新建 Jenkinsfile 文件,再将pipeline脚本写在里面,这种方式相较于上面那种方式,需要多如下配置:
勾选 Pipeline script from SCM 后,配置

SCM: 选择git
Repository URL: 代码仓库地址
Credentials: git账户密码密钥的ID,在Manage Jenkins->Manage Credentials里面可以找到,没有的话,就新增一个
Branches to build: 选择代码分支
脚本路径: 默认Jenkinsfile,需要跟项目一级目录下的pipeline脚本文件名一样,建议和默认保持一样

# 其他没提到的设置保持默认吧

我这里选择的是 Pipeline script ,因为觉得把拉取代码也集成到pipeline脚本里统一管理好一点,没有割裂感

脚本如下,视情况改一下:

def gitUrl = '【改成你的代码仓库地址】'
// maven的默认安装地址
def maven_home = '/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/apache-maven3.8.6/bin'
def project = '【改成你的项目名称】'
def jar_name = '【改成你的项目打成jar包后的jar包文件名】'
def env ='【改成你的项目环境,yml文件环境】'
def port = '【改成你的项目端口号】'
def proxy_port = '【改成你的项目映射到docker宿主机的端口号】'
// jar_home: 比如项目为多module项目,文件夹层级为parent->api(parent下有api,db,common等子module,则jar_home为api/target)
def jar_home = '【改成你的项目打包后相对于一级目录的路径】'
def deploy_home = '【改成你的远程服务器上部署的目录】'
def branch = '【改成你的代码分支】'
// 保存在jenkins凭据中的凭据ID
def credentialsId = '【改成你存在jenkins里面的代码仓库账号密码凭据ID】'
def remoteId = '【改成你的ssh服务器设置ID,对应2.1里面的SSH Server Name】'

pipeline {
    agent any
    stages {
        stage('代码更新'){
            steps {
            	// 指定分支从代码仓库拉去代码
                git branch: "$branch",credentialsId: "$credentialsId",url: "$gitUrl"
            }
        }
        stage('代码编译'){
            steps {
            // 执行shell,用maven打包项目
                sh """
                 $maven_home/mvn clean compile
                 $maven_home/mvn package
                """
            }
        }
        stage('生成Dockerfile'){
            steps {
                // 动态生成Dockerfile
                sh """
                    echo '''
                        FROM openjdk:8-jre
                        MAINTAINER Mroldx
                        ENV PROJECT_NAME delivery-api
                        ENV PROJECT_HOME /home/deployment
                        RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
                        RUN echo 'Asia/Shanghai' >/etc/timezone
                        RUN mkdir \$PROJECT_HOME && mkdir \$PROJECT_HOME/logs
                        COPY $jar_name /application.jar
                        ENTRYPOINT ["java", "-jar","/application.jar","--spring.profiles.active=$env","-Dfile.encoding=UTF-8"]
                    ''' > Dockerfile
                """
            }
        }
        stage('生成deploy.sh'){
            steps {
                // 动态生成dockerfile
                sh """
                    echo '''
                        #!/bin/bash
                        #项目占用端口
                        APP_PORT=$port
                        APP_PROXY=$proxy_port
                        # 项目名字
                        APP_NAME=$project
                        # 项目根目录
                        APP_HOME=$deploy_home/$project
                        # 项目日志输出目录
                        APP_LOG_OUT=$deploy_home/logs
                        # 镜像的tag
                        APP_TAG=2.0
                        mkdir -p \${APP_HOME}
                        mkdir -p \${APP_LOG_OUT}
                        echo "清理已有容器及镜像资源"
                        docker stop \${APP_NAME} && docker rm \${APP_NAME}
                        echo "清理已有容器及镜像资源成功!!!!"
                        echo "镜像制作"
                        docker build -t \${APP_NAME}:\${APP_TAG} .
                        echo "镜像制作完成"
                        echo "开始运行"
                        docker run -d --name \${APP_NAME} -p \${APP_PROXY}:\${APP_PORT} -v \${APP_LOG_OUT}:/logs \${APP_NAME}:\${APP_TAG}
                        echo "已成功运行"
                    ''' > deploy.sh
                """
            }
        }
        stage('打包文件'){
            steps{
            	// 将生成的Dockerfile,deploy.sh 和jar包整成压缩包发往远程服务器
                sh """
                rm -rf deploys
                mkdir deploys
                ls
                cp $jar_home/$jar_name  deploys/
                mv Dockerfile deploys/
                mv deploy.sh deploys/
                tar -zcvf deploys.tar.gz deploys/
                rm -rf deploys
                mv deploys.tar.gz $jar_home/
                """
            }
        }
        stage('发往远程'){
            steps {
            	// 必须装了Publish over SSH插件才能写这个
                sshPublisher(publishers: [sshPublisherDesc(configName: """$remoteId""", transfers: [sshTransfer(cleanRemote: false, excludes: '',
                        execCommand: """
                            echo '准备解压发布文件并部署'
                            cd $deploy_home/$project
                            #解压到当前目录,并去除一级目录
                            tar -zxvf deploys.tar.gz --strip-components 1
                            rm -rf deploys.tar.gz
                            sh deploy.sh
                            echo '部署成功'
                        """,
                        execTimeout: 120000,
                        flatten: false,
                        makeEmptyDirs: false,
                        noDefaultExcludes: false,
                        patternSeparator: '[, ]+',
                        remoteDirectory: """/$project""",
                        remoteDirectorySDF: false,
                        removePrefix: """$jar_home""",
                        sourceFiles: """$jar_home/deploys.tar.gz""")],
                        usePromotionTimestamp: false,
                        useWorkspaceInPromotion: false,
                        verbose: false)])
            }
        }
        stage('删除中间文件'){
            steps {
                sh """
                    cd $jar_home
                    rm -rf deploys.tar.gz
                """
            }
        }
    }
    post {
        success {
            println('项目发布成功!')
        }
        failure {
            println('项目发布失败!')
        }
    }
}

如果是Pipeline script from SCM方式,脚本里面省去拉去代码的步骤即可

脚本的核心流程是:

  1. 拉取代码
  2. maven打包
  3. 生成Dockerfile
  4. 生成deploy.sh
  5. 将Dockerfile,deploy.sh和jar包压缩成压缩包
  6. 将文件发往远程服务器,并在远程服务器解压文件,执行deploy.sh
  7. deploy.sh执行后,会根据Dockerfile将jar包构建成docker镜像,并运行
# Linux 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×