基于Jenkins实现项目部署

 2018-07-06 12:16:14     Jenkins  持续集成  开源   925


导读: Jenkins 有很多中创建任务的方式,这里,我只测试了常用的三种方式,来实现简单的自动化部署,分别是 Freestyle、Pipeline、Open Blue Ocean。

假设,我们有一个项目,放在 Git 上维护,部署在 slave-web-1、slave-web-2 两台服务器上,基于 Jenkins , 来实现自动化部署。

服务器信息说明:

域名 IP 作用
master 192.168.1.1 部署 jenkinsmaven 服务
slave-web-1 192.168.1.2 业务部署服务器
slave-web-2 192.168.1.3 业务部署服务器
scm 172.31.2.189 git 等项目仓库服务器

下面,我们用三种不同的方式来实现自动化部署。

1、自由风格(Freestyle)


首先,进入新建任务页,填写项目名称,选择 “Freestyle project”,点击 “确定”,进入构建配置页面。

jenkins-freestyle-1

然后,在 “源码管理” 区域,填写项目在 Git 的信息。(需要 Jenkins 服务器拥有从 Git 服务拉取项目的权限)

jenkins-freestyle-2

下一步,在 “构建” 区域,可以编写项目构建的脚步。例如:mvn clean package。(这里的项目是一个静态脚本项目,构建操作是将项目打包)

jenkins-freestyle-3

最后,选择 “Send files or execute commands over SSH”,点击 “Add Server”,配置部署节点 “SSH Server” 信息。多少部署节点就对应多少配置信息。

SSH Server 配置:

  • Name: 部署节点IP或Host(配置Host,需要在 Jenkins 服务器上配置 Host 信息)
  • Source files: 需要发送的源文件地址,该地址是相对路径(相对于 {jenkins_home}/workspace/{JOB_NAME}
  • Remove prefix: 排除的目录或文件
  • Remote directory: 源文件在远程节点存放的相对目录(相对于 “节点管理” 中 “远程工作目录” 的路径,详细请看 持续集成工具 — Jenkins
  • Exec command: 在远程部署节点需要执行的脚本命令(可是解压项目、停止服务,重启服务等操作)

这样,执行任务构建操作(或者在 Open Blue Ocean 界面执行运行操作),就可以将项目发送到部署节点。

jenkins-freestyle-4

2、流水线(Pipeline)


相对于 FreestylePipeline 更加灵活,尤其是有很多部署节点时,Pipeline 更加适用。使用 Pipeline,需要先了解 Pipeline 的语法,可以看 Pipeline SyntaxPipeline 入门

首先,进入新建任务页,填写项目名称,选择 “Pipeline”,点击 “确定”,进入构建配置页面。

jenkins-pipeline-1

根据需要,可以选择构建触发器。

然后,编写 Pipeline 脚本。

jenkins-pipeline-2

Pipeline 脚本分 Declarative PipelineScripted Pipeline。这里采用的是 Scripted Pipeline

node('master') {
    def mvnHome
    def jdkHome
    def workspace = pwd()

    def clusterNodes="web-1,web-2,web-3,web-4"
    def clusterNodesArray = clusterNodes.split(",")

    stage('Ready') {
        mvnHome = tool 'MAVEN_HOME'
        jdkHome = tool 'JAVA_HOME'

        echo "------------------------------------------"
        sh "'${mvnHome}/bin/mvn' -v"

        echo "------------------------------------------"
        sh "'${jdkHome}/bin/java' -version"

        echo "------------------------------------------"
        echo "current path: ${workspace}"

        echo "------------------------------------------"
        echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
        echo "BUILD_DISPLAY_NAME: ${env.BUILD_DISPLAY_NAME}"
        echo "JOB_NAME: ${env.JOB_NAME}"
        echo "NODE_LABELS: ${env.NODE_LABELS}"
        echo "WORKSPACE: ${env.WORKSPACE}"
        echo "JOB_URL: ${env.JOB_URL}"
        echo "BRANCH_NAME: ${env.BRANCH_NAME}"

        timeout(time: 60, unit: 'SECONDS') {
            input message: "this action will stop service, are you sure you want to execute?", ok: "yes"
        }        

    }

    stage('Build') {
        git 'git@scm-git:/home/git/repo/spring-boot-test.git'

        sh "'${mvnHome}/bin/mvn' -DshipTests clean package"
        echo "build number: ${currentBuild.number}"
        echo "build result: ${currentBuild.result}"
        echo "build currentResult: ${currentBuild.currentResult}"
        echo "build displayName: ${currentBuild.displayName}"

        sh "cd ${env.WORKSPACE} && true"

        if (currentBuild.currentResult == 'SUCCESS') {
            echo "BUILD SUCCESS"

        }else {
            echo "BUILD FAILED"
        }
    }

    stage('Deploy') {
        timeout(time: 60, unit: 'SECONDS') {
            for (slave in clusterNodesArray) {
                echo "publish project to ${slave}"
                sh """
                    scp -r target/spring-boot-test.tar.gz user@${slave}:/work/app/jenkins/upload

                    ssh user@${slave} "service tomcat stop && cd /work/app/auto-deploy && sh +x ./bin/service-dubbo-common.sh"
                """
            }
        }

        echo "all slave node are deployed."
    }

    stage('Verify') {
        echo "verify service."
        for (slave in clusterNodesArray) {
            timeout(time: 5, unit: 'SECONDS') {//超时设置
                echo "verify ${slave} url"
            }
        }
    }
}

脚本说明:

  • 第一步(Ready):构建准备工作,查看构建环境,让操作者进行操作任务,防止误操作。
  • 第二步(Build):构建项目,通过 git 获取最新项目,通过 maven 打包构建。
  • 第三步(Deploy):遍历所有节点,将打包项目发布到所有节点,并执行相关命令。
  • 第四部(Verify):验证所有节点服务。

3、Open Blue Ocean


BlueOcean 重新考虑了 Jenkins 的用户体验。BlueOceanJenkins Pipeline 设计,但仍然兼容自由式工作,减少了团队成员的混乱,增加了清晰度。

我们模仿 Pipeline 构建项目的方式,来创建一个 BlueOcean 任务。

首先,在 BlueOcean 界面,点击 “创建流水线”,进入构建页面。选择代码仓库,并填写相关信息(可能会生成一个认证key,需要将 key 加到 代码仓库服务器上)。

jenkins-blueocean-1

进入 Pipeline 构建页面,默认会有一个 Start 阶段,在这里,可以配置 Pipeline 的全局变量和参数。

jenkins-blueocean-2

点击 Start 后面的 “+”,可以添加阶段。填写阶段名称,然后添加该阶段包含的步骤,步骤类型有很多种,根据需要进行选择。

jenkins-blueocean-3

例如,我们选择 “Shell Script” 类型。

jenkins-blueocean-4

jenkins-blueocean-5

添加完所有阶段后,最终图形如下:

jenkins-blueocean-6

以上三种方式,更倾向于采用 PipelineBlueOcean 虽然方便、简介,但是还需要完善。

运行


BlueOcean 主界面或任务列表界面,都可以运行任务。

例如:在 BlueOcean 界面运行任务,可以查看详细的信息输出。

jenkins-run-1

如果执行失败,会终止运行,并提示错误信息。

jenkins-blueocean-6

也可以直接在任务列表点击 “构建” 来运行。在 “Stage View” 可以查看每一阶段的执行时间和结果。

jenkins-blueocean-6

除此之外,还有许多其它高级应用,在今后的使用过程中,逐步学习。

4、注意事项


4.1、从节点环境变量问题


使用 ssh 启动 Tomcat 项目时,可能会遇到下面错误信息。

Neither the JAVA_HOME nor the JRE_HOME environment variable is defined

At least one of these environment variable is needed to run this program

这个错误是因为环境变量是通过 /etc/profile 配置的原因导致。

/etc/profile: 此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行。并从/etc/profile.d目录的配置文件中搜集shell的设置

/etc/bashrc: 为每一个运行bash shell的用户执行此文件。当bash shell被打开时,该文件被读取(即每次新开一个终端,都会执行bashrc)

查看 /etc/bashrc 代码,发现它会引用 /etc/profile.d/ 下的所有 .sh 文件。所以,解决这个问题有两种方式:

  • 1、将环境变量配置到 /etc/bashrc
  • 2、将环境变量配置到 /etc/profile.d/ 下(推荐)

注意:
如果是服务自启动脚本,通过 rc.local 调用 shell,也会出现无法找到环境变量的错误,因为系统的任何一个用户都没有登录过,这种情况下,可以在 rc.local 调用 shell 前,加载用户环境变量 source /etc/profile

4.2、进程问题


通过 SSH 远程运行从节点脚本时,远程会话结束以后会把 SSH 下的所有子进程干掉。这时,就可能出现 Tomcat 启动成功了,过一会进程消失了,但是在节点服务器运行脚本又不会消失的现象。

有两种解决方法:

1、在脚本中加入 nohup 来执行关键命令;

nohup ${TOMCAT_HOME}/bin/startup.sh > /dev/null 2>&1 &

2、在 Jenkins 的节点管理中增加变量。

key=BUILD_ID
value=DONTKILLME

参考