最基础核心的Jenkins功能部署一个java应用
有的小伙伴可能刚刚接触 Jenkins 这个工具,也许已经接触了小有一段时间,可是每当面对 Jenkins 的安装,配置,使用,插件,脚本,代码,,等等的一堆问题,总是会有一种就算长了三头六臂也不够用的感觉。
其实,这种感觉,我也有过,因为学习 Jenkins 是我进入到现在任职的这家公司的第一任务,那时候自己莫说是 Jenkins,就连其他的 java 也都是一窍莫通的,于是乎,仅仅在 Jenkins 的安装以及所谓的插件的安装等问题上,就折腾了一周,其实每天都很煎熬,但是仍旧没见到什么成效,身边的运维大哥在我第二周终于安装成功了之后对我说,你这单是安装就搞了一周呀。这句话更加让原本就敏感的我感觉到阵阵的刺激,这种刺激在当时对自己心里想来好似一种嘲笑,但是现在想来,反而感激,琢磨起来,更像是一种激励了。
不管怎样,好在因为自己的坚持,功不唐捐,也总算是走出来了。这个过程中,也将自己所取得的一点点小小成就与大众分享,希望能够让更多的人受益。其实很多时候看到一些刚接触 Jenkins 的朋友着急的样子,就会想起自己当初在安装这个问题上卡了一周的经历,又看到有人想要花钱让别人帮忙部署,或者花钱让别人教自己的,其实学习的心情,或者掌握技能的心情,都是一样的,只不过,我总觉得,
笔记
人生一世,有时候该走的弯路,半米都不会少,如果你纵向绕开这半米弯路,那在面临到这半米弯路的时候,可能直接就倒下了。
所以,一句话,绝知此事要躬行就好了。
今天呢,是想单纯的写一篇 Jenkins 的入门文章,从安装,到使用,到配置,一路上都是针对新入门的人而言的,包括在这个过程中,会遇到哪些坑,有哪些需要注意的点,我都会尽量尽己所能分享,从而帮助一些新入门的朋友真正的尽量不入坑的将 Jenkins 构建项目体验一遍。
现在,废话已经够多了,直接进入正题。
# 1,浅谈项目部署流程。
哎,在进入真正的 Jenkins 构建学习之前,我还是想多啰嗦几句话,因为有时候思路非常重要,如果没有思路,可能整个操作,都会变得没有方向,或者整个的配置都会让自己变成无头苍蝇,出了问题,也不知道该从哪里排查。
结合我日常工作经验,个人觉得,一个项目能够成型于 Jenkins 上,大概需要以下几种原料:
原料 | 说明 |
---|---|
Jenkins | 这不废话嘛! |
maven | 如果是 java 项目,那么 maven 作为编译工具,必不可少! |
jdk | 只要与 java 沾边,就少不了他! |
tomcat | 如果是常规项目,少不了 tomcat! |
nexus | 企业级私服王者,如果你还不了解他,可以先不用了解! |
node | 如果是前端的 node 项目,那么 node 不可少! |
Git | 代码集中营! |
基本上也就是如上这些组件了。
提示
一般情况下,一个项目的立项,在初期开会的时候,开发就会与运维沟通,当项目开发完成之后,注意,此时,基本上开发在他本地肯定已经测过基本上的大框架问题,所以,我们问开发要到项目地址(Git),然后先把项目从远端拉下来,在机器上跑一下,当手动可以跑通的时候,再将手动操作的这个流程往 Jenkins 上套,让 Jenkins 完成我们手动操作的这些工作即可。
Jenkins 的意义,便是如此。
那么接下来,就正式进入项目部署过程,我这里也是依照上边那段话进行的。
# 2,手动走一遍。
提前说明,从这里开始,需要准备三台环境干净的主机:
主机地址 | 功能说明 |
---|---|
192.168.112.167 | Jenkins 主机 |
192.168.112.182 | 模拟生产环境的中转机 |
192.168.112.237 | 远程跑应用的主机 |
巧妇难为无米之炊,而这项目地址就是米,是万事可行之源。
我这里选取一个开源的任务管理系统作为演示,大家也都可以很方便的拿这个项目进行构建体验体会琢磨。
# 1,拿到项目源码。
项目地址:https://github.com/xuxueli/xxl-job
进入项目之后,登陆自己的 github 账号,然后点击一下Fork
将代码Fork
到自己的空间,这样方便接下来的构建等操作。
# 2,先 copy 到服务器。
如下大部分操作如无特别说明,则都是在 Jenkins 主机之上操作。
[root@eryajf ~]$yum -y install git rsync
这个地方先将相应的命令安装好,因为这个地方也会坑到人,如果你没有注意的话,比如在你直接将 Jenkins 安装好了之后,兴致冲冲的去配置项目,结果发现项目源码那里怎么配置都会报出红色错误,原因有可能就是因为 Jenkins 服务器没有安装 git 以及 rsync 命令。
现在任意来到一个目录,clone 一下代码。
[root@eryajf opt]$git clone https://github.com/eryajf/xxl-job.git
Cloning into 'xxl-job'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 16031 (delta 4), reused 3 (delta 1), pack-reused 16022
Receiving objects: 100% (16031/16031), 27.43 MiB | 1.15 MiB/s, done.
Resolving deltas: 100% (6249/6249), done.
[root@eryajf opt]$ls
xxl-job
2
3
4
5
6
7
8
9
10
11
# 3,进行手动编译。
接下来可以先手动编译一下,不过编译之前,有两个工具需要准备。其实是一个,就是 maven 打包工具,只不过 maven 工具依赖 jdk 环境,所以先来解决这两个工具的安装。
这两个的安装就不细说了,快速的过一下。
- 1,安装 jdk。
首先从官网下载 jdk。
下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
注意这里只能通过浏览器点击下载,而不能通过服务器上 wget 或者复制链接到迅雷下载,因为下载的时候需要选中一下接受许可协议,然后找到对应版本进行下载。
安装步骤是:解压—-移动到对应目录下—-写入环境变量—–加载一下—-验证。
[root@eryajf src]$tar xf jdk-8u191-linux-x64.tar.gz -C /usr/local/
[root@eryajf src]$cd ..
[root@eryajf local]$ls
bin etc games include jdk1.8.0_191 lib lib64 libexec sbin share src
[root@eryajf local]$echo 'JAVA_HOME=/usr/local/jdk1.8.0_191' >> /etc/profile
[root@eryajf local]$echo 'PATH=$PATH:$JAVA_HOME/bin' >> /etc/profile
[root@eryajf local]$echo 'export PATH' >> /etc/profile
[root@eryajf local]$source /etc/profile
[root@eryajf local]$java -version
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
2
3
4
5
6
7
8
9
10
11
12
- 2,安装 maven。
下载地址:https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.3.9/
这个不管是 wget 还是通过迅雷下载都可以,总之哪个快选择哪个,不过好在文件不是特别大。
[root@eryajf local]$wget https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.tar.gz
下载完成之后,接下来开始安装:
[root@eryajf src]$tar xf apache-maven-3.3.9-bin.tar.gz -C ../
[root@eryajf src]$cd ..
[root@eryajf local]$ls
apache-maven-3.3.9 bin etc games include jdk1.8.0_191 lib lib64 libexec sbin share src
[root@eryajf local]$mv apache-maven-3.3.9/ maven
[root@eryajf local]$echo 'MAVEN_HOME=/usr/local/maven' >> /etc/profile
[root@eryajf local]$echo 'PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin' >> /etc/profile
[root@eryajf local]$source /etc/profile
[root@eryajf local]$mvn -v
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00)
Maven home: /usr/local/maven
Java version: 1.8.0_191, vendor: Oracle Corporation
Java home: /usr/local/jdk1.8.0_191/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-514.el7.x86_64", arch: "amd64", family: "unix"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
如此安装完成之后,就可以去刚才的项目目录当中进行构建了。
# 4,手动构建。
[root@eryajf xxl-job]$mvn clean install -DskipTests=true
这个过程可能需要一段时间,因为一个新项目在机器上第一次开始编译,有很多项目依赖的包都需要从远程下载,因此只需耐心等待即可。
如果编译过程中有报错,只要不是找不到 mvn 这条命令,那么大可直接去找开发同学,或者直接把报错的地方截图发给他,让他解决,当然,如果自己有能力解决的,也可以自行解决。
因为这个项目依赖都在远程,没有特别偏僻的依赖包,所以基本上都是可以编译通过的。只要是环境配置没有问题的话。
当这个地方编译完成之后,基本上就可以去 Jenkins 上进行操作了,因为剩下的事情无非就是将包传到远程服务器,然后看服务启动的问题而已了!
# 3,套入 Jenkins。
# 1,安装。
- Jenkins 官方网站:http://jenkins-ci.org/。
- 最新稳定版下载地址:http://mirrors.jenkins.io/war-stable/latest/jenkins.war。
这里 tomcat 的下载安装就省略了。
[root@eryajf tomcat]$mv jenkins.war /usr/local/tomcat/webapps/ROOT.war
[root@eryajf tomcat]$./bin/startup.sh
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/local/jdk1.8.0_191
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.
2
3
4
5
6
7
8
9
然后监听一下日志,稍候会看到 admin 的密码出来。
Oct 25, 2018 9:52:02 PM jenkins.install.SetupWizard init
INFO:
*************************************************************
*************************************************************
*************************************************************
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
e282c05e3bb54106929bc82e7f5d9b4d
This may also be found at: /root/.jenkins/secrets/initialAdminPassword
*************************************************************
*************************************************************
*************************************************************
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
然后到浏览器访问 Jenkins。 将刚开看到的密码复制进去。
[![
安装系统推荐的插件。如果主机网络不好,也可能会导致安装失败,可以重试一下。
[![
使用 admin 继续配置。
[![
一路往前,Jenkins 就已经安装好了,就可以正式进入到我们的项目构建当中了。
# 2,新建项目。
新建一个项目。
这里随便定义一个名称,然后选择构建一个自由风格的项目。
[![
点击确定之后,进入到正式的配置环节,注意,这个地方,一定要做到心无旁骛,其他的再花哨的功能,再丰富的操作,都先放在一边,跟随我的步伐,先把刚刚手动操作过的项目,套入到 Jenkins 上来。
参数化构建:添加两条参数。
- branch:默认 master 分支。通过这条参数实现发布代码的不同分支。
- mode:有两个选项 deploy/rollback。通过这条参数传递下去,实现部署以及回滚的功能。
配置 Git 源码:将自己刚刚 clone 项目的地址复制过来。这个地方不会报错,如果使用公司内部的 gitlab,可能会报错,此时将 Jenkins 主机秘钥添加到 gitlab 即可。
执行 shell:添加 Jenkins 要做的事情,其实是我们手动做的事情,然后交由 Jenkins 来做。
完整截图如下:
[![
注意
注意,这个地方的执行 shell 其实不是最终完整的样子,我故意把下边的拿掉,是因为,当你对 Jenkins 以及脚本已经有足够的熟悉之后,你就可以利用 Jenkins 来调试了,这就是其中一种方法。其中的代码意思就是,仅仅编译一下项目。
第一次拉取代码,因为是从远程 GitHub 上拉取,会比较慢,这个时候,可以先去服务器上拉取一下,然后再来构建,当然,当 Git 地址配成公司内部的之后,这种情况就不会有了。
到服务器上拉取可有如下操作:
[root@eryajf ~]$cd /root/.jenkins/workspace
[root@eryajf workspace]$git clone https://github.com/eryajf/xxl-job.git test-xxl
因为我们刚刚已经拉取过,所以把刚才拉取成功的拷贝过来即可:
[root@eryajf ~]$cd /root/.jenkins/workspace
[root@eryajf workspace]$mv /opt/xxl-job/ ./test-xxl
2
3
4
5
6
然后再出来构建一下,因为刚刚拷贝的是已经构建过的,依赖也都已经缓存了下来,所以编译就比较快,也比较顺利。
[![
既然编译已经成功了,那么我们就可以开始各种脚本的操作了。如果这个地方编译失败,那么看看是否是自己哪些地方配置错了,否则这个结果应该是与那会儿手动编译效果是一样的。
接着完善一下 Jenkins 执行 shell 处的脚本:
#!/bin/bash
source /etc/profile
project="xxl"
remote_user="root"
remote_host="192.168.112.182"
remote_port="22"
remote_dir=/home/zhongzhuan/$project
script_dir=/home/zhongzhuan/scripts
cd $WORKSPACE && mvn clean install -DskipTests=true
cd $WORKSPACE/xxl-job-admin/target && mv xxl-job-admin-2.0.0-SNAPSHOT.war ROOT.war
if [ $mode == "deploy" ];then
ssh -p ${remote_port} ${remote_user}@${remote_host} "[ ! -d ${remote_dir} ] && mkdir -p ${remote_dir}"
ssh -p ${remote_port} ${remote_user}@${remote_host} "[ -f ${remote_dir}/ROOT.war.bak ] && rm -f ${remote_dir}/ROOT.war.bak"
ssh -p ${remote_port} ${remote_user}@${remote_host} "[ -f ${remote_dir}/ROOT.war ] && mv ${remote_dir}/ROOT.war ${remote_dir}/ROOT.war.bak"
scp -P ${remote_port} $WORKSPACE/xxl-job-admin/target/ROOT.war ${remote_user}@${remote_host}:${remote_dir}/ROOT.war && echo "success scp $project"
sleep 2
echo "调用远程脚本开始部署!"
ssh -p ${remote_port} ${remote_user}@${remote_host} "/bin/bash ${script_dir}/deploy.sh $mode $project"
else
ssh -p ${remote_port} ${remote_user}@${remote_host} "/bin/bash ${script_dir}/deploy.sh $mode $project"
fi
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
说明一二:
其实这个地方我故意绕了一下,不过这么绕有我的道理。因为为了更贴合生产环境当中的实际情况。
先说说这个脚本,其实脚本一点都不复杂,我不喜欢写那种特别复杂,复杂的别人都看不懂的脚本。
顺着脚本来看的话,如果是部署,那么先进行编译,然后备份中转机上的包,接着把新包传过去,然后调用中转主机上的部署脚本。如果是回滚,那么直接调用中转主机上的脚本,通过参数实现。
这里说到了一个中转机,很多时候我们为了方便统一管理,会将某台主机定义为中转机,这样既保证安全,也方便管理了。
不过要注意一个问题:Jenkins 主机—>可以免密码—>中转机—>可以免密码—>应用服务器。
这个链路一定要打通,否则脚本进行不下去的。
- 接着是中转处的脚本:
此脚本需放置在中转机(192.168.112.182)上,以实现承接的作用。
注意,脚本放置的位置,要与上边 Jenkins 主机当中调用的位置一致,也就是/home/zhongzhuan/scripts
下命名为deploy.sh
。
这都是一些小细节,其实熟悉了之后会发现,Jenkins 并不复杂,但需要细心,有许多前后调用的小细节,如果不注意,那么整个链路就会发生故障,自然构建也就无法成功!
#!/bin/bash
source /etc/profile
mode=$1
project=$2
remote_port="10036"
remote_user="root"
remote_host="192.168.112.237"
APPwar=/home/zhongzhuan/${project}/ROOT.war
BAKwar=/home/zhongzhuan/${project}/ROOT.war.bak
remote_appdir=/usr/local/${project}_tomcat/WAR
if [ $mode == "deploy" ];then
ssh -p ${remote_port} ${remote_user}@${remote_host} "[ -f ${remote_appdir}/ROOT.war ] && rm -f ${remote_appdir}/ROOT.war"
echo "正在将${project}的包从中转服务器传到目标服务器!"
scp -P ${remote_port} $APPwar ${remote_user}@${remote_host}:${remote_appdir}/ROOT.war
echo "正在调用应用服务器脚本开始部署!"
ssh -p ${remote_port} ${remote_user}@${remote_host} "/bin/bash ${remote_appdir}/deploy.sh ${project}"
else
echo "正在将备份的${project}的包从中转服务器传到目标服务器!"
scp -P ${remote_port} $BAKwar ${remote_user}@${remote_host}:${remote_appdir}/ROOT.war
echo "正在调用应用服务器脚本开始回滚!"
ssh -p ${remote_port} ${remote_user}@${remote_host} "/bin/bash ${remote_appdir}/deploy.sh ${project}"
fi
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
此处所做的事儿就是一个中转的活儿,暂存 Jenkins 传过来的 war 包,然后承接好 Jenkins 传过来的参数,通过参数,判断是将新构建的包传到远程服务器,还是将备份的 war 包传到远程以回滚。
最后来看远程应用服务器上的脚本是怎么承接的:
注意这个脚本是放置在最后的应用服务器上的(192.168.112.237),同样要注意,脚本的放置位置,应该在/usr/local/${project}_tomcat/WAR/deploy.sh
。
#!/bin/bash
project=$1
source /etc/profile
APPwar=/usr/local/${project}_tomcat/WAR/ROOT.war
deploy(){
webdir=/usr/local/${project}_tomcat/webapps
tpid=`ps aux | grep ${project}_tomcat | grep java | grep -v grep | awk '{print $2}'`
[ ! -z $tpid ] && kill -9 $tpid
rm -rf ${webdir}/*
mv $APPwar $webdir
sleep 2
/usr/local/${project}_tomcat/bin/startup.sh
timeout 30 tail -fn 100 /usr/local/${project}_tomcat/logs/catalina.out
sleep 1
echo "部署完成!"
}
deploy
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
现在,我们分别将脚本放置到对应的位置,来看看效果如何。
如果各个环节都没问题,部署应该也是没有问题的了。完成之后,访问一下:
[![
首页访问没有问题,可能登陆之后失败,是因为数据库什么的都没有配置,不过这些都不重要啦,因为项目已经就此部署起来了。以后,也可以套这个思路,进行一个项目的构建。
重要的是中间的三个脚本,希望各位好好琢磨琢磨,其实并不复杂,当你能够熟练运用并写出来,那么用熟 Jenkins,就不是问题了!