我的jenkins自动部署方案演进史

来源:互联网 发布:xml与java 编辑:程序博客网 时间:2024/04/30 13:18

项目要实施持续集成,一天可能发生几次集成,不可能靠人工一遍遍地操作,自然使用自动部署。我们选择的jenkins。

一、使用插件

最开始我试着采用以下两个插件:
1、Deploy to container Plugin
This plugin allows you to deploy a war to a container after a successful build. 

2、Artifact Deployer Plug-in
This plug-in makes it possible to deploy artifacts from workspace to output directories.

发现它们一次只能部署单个jar/war/ear,而我们的项目中至少有上百个jar,未来还会持续增加,这样并不能满足我们的需求。


二、使用自定义脚本

因为所有的jar和war都遵循命名约定,所以我使用脚本可以检索到这些jar,然后根据需要按顺序自动部署,脚本如下:

1、部署单个
@echo offset jboss_path=E:\gxpt-jboss-1.0set project_name=%WORKSPACE%\target\%JOB_NAME%-%1.%2 if exist %project_name% (    echo %BUILD_ID% -- 正在部署%project_name%    copy /y %project_name% %jboss_path%\server\default\deploy\ ) else (    echo %BUILD_ID% -- 未找到%project_name% )


采用这种方式,和上述使用插件能达到同样的效果

2、部署多个

@echo off & setlocal EnableDelayedExpansionset jboss_path=E:\gxpt-jboss-1.0set project_sn=%1set project_default=%jboss_path%\server\default_%project_sn%\deploy\set project_home=%JENKINS_HOME%set project_tmp=%project_home%\tmp_%project_sn%set workspace=%project_home%\workspaceif not exist %project_tmp% md %project_tmp%echo [%BUILD_ID%] 正在检索所有jar包和war包到%project_tmp%临时目录for /r "%workspace%" %%i in (gxpt_common_*.jar) do (  echo 正在复制%%i到%project_tmp%\  copy /y "%%i" %project_tmp%\)for /r "%workspace%" %%i in (gxpt_*_%project_sn%*.?ar) do (  echo 正在复制%%i到%project_tmp%\  copy /y "%%i" %project_tmp%\)echo [%BUILD_ID%] 完成复制。echo ------------------------------------------------echo -------------------------------echo 开始自动部署……echo ------------------------------------------------echo -------------------------------echo [%BUILD_ID%]正在部署%project_sn%实体jarfor /r %project_tmp% %%i in (gxpt_entity_%project_sn%.jar) do (echo 正在部署%%i 到 %project_default%copy /y "%%i" "%project_default%")echo ------------------------------------------------echo -------------------------------echo [%BUILD_ID%]正在部署commontool的jarfor /r %project_tmp% %%i in (gxpt_common_tool.jar) do (echo 正在部署%%i 到 %project_default%copy /y "%%i" "%project_default%")echo ------------------------------------------------echo -------------------------------echo [%BUILD_ID%] 正在部署commonEao接口jarfor /r %project_tmp% %%i in (gxpt_common_eao.jar) do (echo 正在部署%%i 到 %project_default%copy /y "%%i" "%project_default%")echo ------------------------------------------------echo -------------------------------echo [%BUILD_ID%] 正在部署commonEao实现jarfor /r %project_tmp% %%i in (gxpt_common_eao_impl.jar) do (echo 正在部署%%i 到 %project_default%copy /y "%%i" "%project_default%")echo ------------------------------------------------echo -------------------------------echo [%BUILD_ID%] 正在部署%project_sn%的mgr层接口jarif exist interface.txt del interface.txtfor /r %project_tmp% %%i in (gxpt_mgr_%project_sn%_*.jar) do ( echo "%%i"|find "impl" /I>interface.txt set "zer=%%i" for /f "delims=." %%j in (interface.txt) do (  set "zer=null" ) if not "!zer!"=="null" (  echo 正在部署%%i 到 %project_default%  copy /y "%%i" "%project_default%" ))if exist interface.txt del interface.txtecho ------------------------------------------------echo -------------------------------echo [%BUILD_ID%] 正在部署%project_sn%的mgr层实现jarfor /r %project_tmp% %%i in (gxpt_mgr_%project_sn%_*_impl.jar) do (echo 正在部署%%i 到 %project_default%copy /y "%%i" "%project_default%")echo ------------------------------------------------echo -------------------------------echo [%BUILD_ID%] 正在部署%project_sn%的warfor /r %project_tmp% %%i in (gxpt_web_%project_sn%_*.war) do (echo 正在部署%%i 到 %project_default%copy /y "%%i" "%project_default%")echo ------------------------------------------------echo -------------------------------echo [%BUILD_ID%] %project_sn%项目部署完成。



可以发现,这段脚本依赖严格的命名约定,否则将没有意义。同时它也有很大局限性,如果是一些第三方包(没有按命名约定),那么这段脚本将会加入特殊的部分处理这些"异常"的包,将会是脚本越来越复杂,不容易维护和扩展,而且检索效率低下。

3、改进的脚本:通过增加一个sequence文件,来维护部署内容和顺序

与其写复杂的语法,根据命名去检索,还不如通过一个文件来维护需要部署的包和包的顺序。

如下:
gxpt_entity_qx
gxpt_common_tool
……省略
gxpt_mgr_qx_organization
gxpt_mgr_qx_operation_impl
……省略
gxpt_web_qx_authorize
gxpt_web_qx_module
gxpt_web_qx_operation
……省略

配合脚本:
@echo off & setlocal EnableDelayedExpansionset jboss_path=Y:set project_sn=%1set project_default=%jboss_path%\default-%project_sn%\deploy\set project_home=D:\Jenkinsset project_tmp=%project_home%\tmp_%project_sn%set project_workspace=%project_home%\workspaceset workspace=%project_workspace%\gxpt_%project_sn%_mainif not exist %project_tmp% md %project_tmp%echo [%BUILD_ID%] 正在检索所有jar包和war包到%project_tmp%临时目录echo -------------------------------echo ---------------------for /f %%i in (%WORKSPACE%\%project_sn%_deploy_sequence.txt) do (if exist "%project_workspace%\%%i\target\%%i.jar" (  echo 正在复制%%i到%project_tmp%\  copy /y "%project_workspace%\%%i\target\%%i.jar" %project_tmp%\))for /f %%i in (%WORKSPACE%\%project_sn%_deploy_sequence.txt) do (if exist "%project_workspace%\%%i\target\%%i.war" (  echo 正在复制%%i到%project_tmp%\  copy /y "%project_workspace%\%%i\target\%%i.war" %project_tmp%\))echo -------------------------------echo ---------------------echo [%BUILD_ID%] 完成复制。echo ------------------------------------------------echo -------------------------------echo 开始自动部署……echo ------------------------------------------------echo -------------------------------for /f %%i in (%WORKSPACE%\%project_sn%_deploy_sequence.txt) do ( if exist "%project_tmp%\%%i.jar" (   echo 正在部署%%i 到 %project_default%   copy /y "%project_tmp%\%%i.jar" "%project_default%" ))for /f %%i in (%WORKSPACE%\%project_sn%_deploy_sequence.txt) do ( if exist "%project_tmp%\%%i.war" (   echo 正在部署%%i 到 %project_default%   copy /y "%project_tmp%\%%i.war" "%project_default%" ))echo ------------------------------------------------echo -------------------------------echo [%BUILD_ID%] %project_sn%项目部署完毕。


这样做的优势是,不需要维护复杂的脚本,增删包,改变部署顺序,只需要修改sequence文件即可,而且这个脚本是通用的,直接指向目标,也能达到不错的效率。


三、小插曲,为什么我们没有使用ear

我们考虑过把所有包都打到一起,放到一个ear中,它能带来一个优势,就是部署的时候,只需要部署一个ear包就可以了。看似很完美,但也有其局限性:

1、在开发环境下,我们的开发人员面下是单个包的开发,简单测试就需要打一个ear,比较麻烦。
2、我们需要修改所有web项目的spring文件,来保证它能找到ejb组件
3、损失了部署的灵活性,我们的ejb组件是要求可以灵活部署的,如果都在一个ear中,也就意味着只能在一台机器上。

项目上线后,生产环境下,我们可以采用ear的方式,然后配合jboss集群,但开发环境下,我们还是选择,暂时不打ear。

四、自定义脚本+磁盘映射

我们可以看到,使用脚本,我们只能完成本地部署。如果使用插件,或者使用cargo我们能完成远程部署,但一次又只能部署一个。
怎么办?

windows共享目录+磁盘映射。貌似很简单,但这又引发了另一个问题,在锁屏的情况下,磁盘映射时断开连接的。我们采用的是win8 Server,不可能一直保持用户连接,甚至后期可能连显示器都没有了。如果保持磁盘映射的连接不断开,成了棘手的问题。还好有google

Use this at your own risk. (I have tested it on XP and Server 2008 x64 R2)

For this hack you will need SysinternalsSuite by Mark Russinovich:

Step one: Open an elevated cmd.exe prompt (Run as administrator)

Step two: Elevate again to root using PSExec.exe: Navigate to the folder containing SysinternalsSuite and execute the following command psexec -i -s cmd.exe you are now inside of a prompt that is nt authority\system and you can prove this by typingwhoami. The -i is needed because drive mappings need to interact with the user

Step Three: Create the persistent mapped drive as the SYSTEM account with the following command net use z: \\servername\sharedfolder /persistent:yes

It's that easy!

WARNING: You can only remove this mapping the same way you created it, from the SYSTEM account. If you need to remove it, follow steps 1 and 2 but change the command on step 3 to net use z: /delete.

NOTE: The newly created mapped drive will now appear for ALL users of this system but they will see it displayed as "Disconnected Network Drive (Z:)". Do not let the name fool you. It may claim to be disconnected but it will work for everyone. That's how you can tell this hack is not supported by M$.


按上述步骤,我们解决了这个问题,实现了多个包的自动远程部署。


目前,我们采用的是方案四,能满足需求,如果你有更好的方案,欢迎指教。



3 1