如何使用Jenkins部署SpringBoot Maven应用程序?

25

我有一个运行在嵌入式Tomcat servlet容器上的Spring Boot应用程序mvn spring-boot:run。而且我不想将该项目部署为单独的war文件到独立的Tomcat中。

每当我向BitBucket/Github推送代码时,钩子运行并触发Jenkins作业(在Amazon EC2上运行)来部署应用程序。

Jenkins作业有一个后构建操作:mvn spring-boot:run,问题在于,当后构建操作完成后,作业会挂起。

应该有另一种方法来解决这个问题。任何帮助都将不胜感激。


如果你只运行这个程序,那么它会挂起。听起来你只需要使用nohup将其作为后台进程运行即可。 - Steve
你为什么要通过Maven从源代码运行应用程序,而不是使用java -jar命令运行打包好的构件? - kryger
@kryger 我会尽快更改运行方式。这样旧的进程(嵌入式Tomcat实例)应该被删除以部署新的进程。我应该用更优雅的方式来完成它。 - azizunsal
嗨,阿齐兹。你是怎么解决你的问题的?对于你的问题,答案对我来说不够清晰。我有一个类似的情况,在配置页面的构建部分下使用“spring-boot:run”在“我的目标和选项”中。应用程序已经成功构建和部署,但作业没有停止。 - akcasoy
@akcasoy,问题在被接受的答案中有解释。如果您想查看实际问题,可以在此处查看。| at now + 1 minutes就能解决问题。 - azizunsal
5个回答

22
问题在于Jenkins 无法很好地处理从构建中生成子进程的问题。@Steve在评论中提出的解决方法(使用nohup)在我的情况下没有改变行为,但一个简单的解决方法是使用at unix命令来调度应用程序的启动:
> echo "mvn spring-boot:run" | at now + 1 minutes

这样Jenkins就能成功完成工作,无需超时。
如果您通过java -jar app.jar.jar文件运行应用程序,请注意如果覆盖.ja​r文件,则引导会中断,在复制工件之前需要确保应用程序已停止。如果您正在使用ApplicationPidListener,则可以通过添加执行此命令来验证应用程序是否正在运行(并在运行时停止它):
> test -f application.pid && xargs kill < application.pid || echo 'App was not running, nothing to stop'

2
echo "mvn spring-boot:run" | at now(无需1分钟延迟)在我的情况下也能很好地工作。 - Abdull
@Abdull,这可能取决于Unix的版本;在Ubuntu上,“now”将在当前分钟的00秒进行调度(即甚至可能是过去的时间)。我刚在Mac上尝试了“at now + 1 minutes”,它抱怨“复数形式错误” :-| - kryger
你需要安装 (例如:sudo apt-get install at)。 - Flavio Troia
如果您有一个应用程序的两个环境,DEV环境和PROD环境,当其中一个运行时(即使在另一个端口),另一个就会停止。我认为这是Jenkins仅使用一个被阻塞的shell的情况,当一个环境开始运行时,它就会被阻塞。 在这种情况下该怎么办? - Turbut Alin

5
我发现先将工件复制到服务器上的指定区域非常有用,以便跟踪部署的工件,并且不从jenkins作业文件夹启动应用程序。然后在那里创建一个服务器日志文件并开始在jenkins窗口上监听它,直到服务器启动。
为此,我开发了一个小的shell脚本,您可以在这里找到。
您还会找到一篇小文章,解释如何在jenkins上配置项目。
请告诉我是否对您有帮助。谢谢。

3

nohupat now + 1 minutes 对我都不起作用。由于Jenkins会杀死后台运行的进程,所以我通过为该Jenkins任务设置一个虚假的BUILD_ID来确保该进程不被杀死。以下是Jenkins执行shell任务的示例:

BUILD_ID=do_not_kill_me
java -jar -Dserver.port=8053 /root/Deployments/my_application.war &
exit

如在这里讨论的那样。


2

我假设您在服务器上拥有Jenkins用户,并且该用户是Jenkins服务的所有者:

  1. 以root身份登录服务器。
  2. 运行sudo visudo
  3. 在末尾添加“jenkins ALL=(ALL) NOPASSWD:ALL”(jenkins=您的Jenkins用户)
  4. 登录Jenkins并选择您的作业,然后单击配置
  5. 在“构建后步骤”中选择“执行Shell”
  6. 复制并粘贴以下内容:
   service=myapp
   if ps ax | grep -v grep | grep -v $0 | grep $service > /dev/null
   then
       sudo service myapp stop
       sudo unlink /etc/init.d/myapp
       sudo chmod +x /path/to/your/myapp.jar
       sudo ln -s /path/to/your/myapp.jar /etc/init.d/myapp
       sudo service myapp start 
    else
       sudo chmod +x  /path/to/your/myapp.jar
       sudo ln -s  /path/to/your/myapp.jar /etc/init.d/myapp
       sudo service myapp start 
    fi

保存并运行您的作业,服务应该会自动启动。

jenkins ALL=(ALL) NOPASSWD:ALL??. That is potentially dangerous as you are giving full privileges for jenkins user to execute any command on the server. If the jenkins installation is compromised somehow, the hacker will get full control over the system. For a tighter access restriction, you may change it to: jenkins ALL=(ALL) NOPASSWD:comma_seperated_commands. Since there are several commands in here, the whole of the above code could be put in a script, say myapp_service.sh and then update the sudo command as jenkins ALL=(root) NOPASSWD:/full_path_to/myapp_service.sh - VanagaS

1

这对我在 Linux 机器上的 Jenkins 有效。

kill -9 $(lsof -t -i:8080) || echo "Process was not running."
mvn clean compile
echo "mvn spring-boot:run" | at now + 1 minutes

如果8080端口没有进程,它将打印该消息并继续执行。
确保您的Linux机器安装了at。您可以使用
sudo apt-get install at

安装 at

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接