项目要实施持续集成,一天可能发生几次集成,不可能靠人工一遍遍地操作,自然使用自动部署。我们选择的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 off
set jboss_path=E:\gxpt-jboss-1.0
set 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 EnableDelayedExpansion
set jboss_path=E:\gxpt-jboss-1.0
set project_sn=%1
set 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%\workspace
if 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%实体jar
for /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的jar
for /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接口jar
for /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实现jar
for /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层接口jar
if exist interface.txt del interface.txt
for /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.txt
echo ------------------------------------------------
echo -------------------------------
echo [%BUILD_ID%] 正在部署%project_sn%的mgr层实现jar
for /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%的war
for /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 EnableDelayedExpansion
set jboss_path=Y:
set project_sn=%1
set project_default=%jboss_path%\default-%project_sn%\deploy\
set project_home=D:\Jenkins
set project_tmp=%project_home%\tmp_%project_sn%
set project_workspace=%project_home%\workspace
set workspace=%project_workspace%\gxpt_%project_sn%_main

if 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$.


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


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



Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐