分享

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

 bananarlily 2014-04-15

项目要实施持续集成,一天可能发生几次集成,不可能靠人工一遍遍地操作,自然使用自动部署。我们选择的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、部署单个
  1. @echo off  
  2. set jboss_path=E:\gxpt-jboss-1.0  
  3. set project_name=%WORKSPACE%\target\%JOB_NAME%-%1.%2  
  4.  if exist %project_name% (  
  5.     echo %BUILD_ID% -- 正在部署%project_name%  
  6.     copy /y %project_name% %jboss_path%\server\default\deploy\  
  7.  ) else (  
  8.     echo %BUILD_ID% -- 未找到%project_name%  
  9.  )  


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

2、部署多个

  1. @echo off & setlocal EnableDelayedExpansion  
  2. set jboss_path=E:\gxpt-jboss-1.0  
  3. set project_sn=%1  
  4. set project_default=%jboss_path%\server\default_%project_sn%\deploy\  
  5. set project_home=%JENKINS_HOME%  
  6. set project_tmp=%project_home%\tmp_%project_sn%  
  7. set workspace=%project_home%\workspace  
  8. if not exist %project_tmp% md %project_tmp%  
  9. echo [%BUILD_ID%] 正在检索所有jar包和war包到%project_tmp%临时目录  
  10. for /r "%workspace%" %%i in (gxpt_common_*.jar) do (  
  11.   echo 正在复制%%i到%project_tmp%\  
  12.   copy /y "%%i" %project_tmp%\  
  13. )  
  14. for /r "%workspace%" %%i in (gxpt_*_%project_sn%*.?ar) do (  
  15.   echo 正在复制%%i到%project_tmp%\  
  16.   copy /y "%%i" %project_tmp%\  
  17. )  
  18. echo [%BUILD_ID%] 完成复制。  
  19. echo ------------------------------------------------  
  20. echo -------------------------------  
  21. echo 开始自动部署……  
  22. echo ------------------------------------------------  
  23. echo -------------------------------  
  24. echo [%BUILD_ID%]正在部署%project_sn%实体jar  
  25. for /r %project_tmp% %%i in (gxpt_entity_%project_sn%.jar) do (  
  26. echo 正在部署%%i 到 %project_default%  
  27. copy /y "%%i" "%project_default%"  
  28. )  
  29. echo ------------------------------------------------  
  30. echo -------------------------------  
  31. echo [%BUILD_ID%]正在部署commontool的jar  
  32. for /r %project_tmp% %%i in (gxpt_common_tool.jar) do (  
  33. echo 正在部署%%i 到 %project_default%  
  34. copy /y "%%i" "%project_default%"  
  35. )  
  36. echo ------------------------------------------------  
  37. echo -------------------------------  
  38. echo [%BUILD_ID%] 正在部署commonEao接口jar  
  39. for /r %project_tmp% %%i in (gxpt_common_eao.jar) do (  
  40. echo 正在部署%%i 到 %project_default%  
  41. copy /y "%%i" "%project_default%"  
  42. )  
  43. echo ------------------------------------------------  
  44. echo -------------------------------  
  45. echo [%BUILD_ID%] 正在部署commonEao实现jar  
  46. for /r %project_tmp% %%i in (gxpt_common_eao_impl.jar) do (  
  47. echo 正在部署%%i 到 %project_default%  
  48. copy /y "%%i" "%project_default%"  
  49. )  
  50. echo ------------------------------------------------  
  51. echo -------------------------------  
  52. echo [%BUILD_ID%] 正在部署%project_sn%的mgr层接口jar  
  53. if exist interface.txt del interface.txt  
  54. for /r %project_tmp% %%i in (gxpt_mgr_%project_sn%_*.jar) do (  
  55.  echo "%%i"|find "impl" /I>interface.txt  
  56.  set "zer=%%i"  
  57.  for /f "delims=." %%j in (interface.txt) do (  
  58.   set "zer=null"  
  59.  )  
  60.  if not "!zer!"=="null" (  
  61.   echo 正在部署%%i 到 %project_default%  
  62.   copy /y "%%i" "%project_default%"  
  63.  )  
  64. )  
  65. if exist interface.txt del interface.txt  
  66. echo ------------------------------------------------  
  67. echo -------------------------------  
  68. echo [%BUILD_ID%] 正在部署%project_sn%的mgr层实现jar  
  69. for /r %project_tmp% %%i in (gxpt_mgr_%project_sn%_*_impl.jar) do (  
  70. echo 正在部署%%i 到 %project_default%  
  71. copy /y "%%i" "%project_default%"  
  72. )  
  73. echo ------------------------------------------------  
  74. echo -------------------------------  
  75. echo [%BUILD_ID%] 正在部署%project_sn%的war  
  76. for /r %project_tmp% %%i in (gxpt_web_%project_sn%_*.war) do (  
  77. echo 正在部署%%i 到 %project_default%  
  78. copy /y "%%i" "%project_default%"  
  79. )  
  80. echo ------------------------------------------------  
  81. echo -------------------------------  
  82. 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
……省略

配合脚本:
  1. @echo off & setlocal EnableDelayedExpansion  
  2. set jboss_path=Y:  
  3. set project_sn=%1  
  4. set project_default=%jboss_path%\default-%project_sn%\deploy\  
  5. set project_home=D:\Jenkins  
  6. set project_tmp=%project_home%\tmp_%project_sn%  
  7. set project_workspace=%project_home%\workspace  
  8. set workspace=%project_workspace%\gxpt_%project_sn%_main  
  9.   
  10. if not exist %project_tmp% md %project_tmp%  
  11. echo [%BUILD_ID%] 正在检索所有jar包和war包到%project_tmp%临时目录  
  12. echo -------------------------------  
  13. echo ---------------------  
  14. for /f %%i in (%WORKSPACE%\%project_sn%_deploy_sequence.txt) do (  
  15. if exist "%project_workspace%\%%i\target\%%i.jar" (  
  16.   echo 正在复制%%i到%project_tmp%\  
  17.   copy /y "%project_workspace%\%%i\target\%%i.jar" %project_tmp%\  
  18. )  
  19. )  
  20. for /f %%i in (%WORKSPACE%\%project_sn%_deploy_sequence.txt) do (  
  21. if exist "%project_workspace%\%%i\target\%%i.war" (  
  22.   echo 正在复制%%i到%project_tmp%\  
  23.   copy /y "%project_workspace%\%%i\target\%%i.war" %project_tmp%\  
  24. )  
  25. )  
  26. echo -------------------------------  
  27. echo ---------------------  
  28. echo [%BUILD_ID%] 完成复制。  
  29. echo ------------------------------------------------  
  30. echo -------------------------------  
  31. echo 开始自动部署……  
  32. echo ------------------------------------------------  
  33. echo -------------------------------  
  34. for /f %%i in (%WORKSPACE%\%project_sn%_deploy_sequence.txt) do (  
  35.  if exist "%project_tmp%\%%i.jar" (  
  36.    echo 正在部署%%i 到 %project_default%  
  37.    copy /y "%project_tmp%\%%i.jar" "%project_default%"  
  38.  )  
  39. )  
  40. for /f %%i in (%WORKSPACE%\%project_sn%_deploy_sequence.txt) do (  
  41.  if exist "%project_tmp%\%%i.war" (  
  42.    echo 正在部署%%i 到 %project_default%  
  43.    copy /y "%project_tmp%\%%i.war" "%project_default%"  
  44.  )  
  45. )  
  46. echo ------------------------------------------------  
  47. echo -------------------------------  
  48. 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$.


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


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



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多