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

Posted

技术标签:

【中文标题】如何使用 Jenkins 部署 Spring Boot Maven 应用程序?【英文标题】:How to deploy SpringBoot Maven application with Jenkins ? 【发布时间】:2015-04-14 12:32:24 【问题描述】:

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

每当我将代码推送到 BitBucket/Github 时,都会运行一个挂钩并触发 Jenkins 作业(在 Amazon EC2 上运行)以部署应用程序。

Jenkins 作业有一个后期构建操作:mvn spring-boot:run,问题是该作业在后期生成操作完成后挂起。

应该有另一种方法来做到这一点。任何帮助将不胜感激。

【问题讨论】:

如果这就是你运行的全部,那么它就会挂起。听起来您只需要使用nohup 将其作为后台进程运行即可。 为什么你通过 Maven 从源代码运行你的应用程序,而不是 java -jarring 打包的工件? @kryger 我会尽快更改运行方法。通过这种方式,应该删除旧进程(嵌入式 Tomcat 实例)以部署新进程。我应该以更优雅的方式来做。 嗨,阿齐兹。你是怎么解决你的问题的?你的问题的答案对我来说不够清楚。我有类似的情况,我在配置页面的构建部分下的“我的目标和选项”中使用“spring-boot:run”。应用程序已成功构建和部署,但作业并未停止。 @akcasoy 问题在接受的答案中得到了解释。如果您想了解实际问题是什么,可以查看here。 | at now + 1 minutes 做到这一点。 【参考方案1】:

问题是詹金斯doesn't handle spawning child process from builds very well。 @Steve 在评论 (nohuping) 中建议的解决方法并没有改变我的行为,但一个简单的解决方法是使用at unix 命令安排应用程序的启动:

> echo "mvn spring-boot:run" | at now + 1 minutes

这样 Jenkins 就可以成功完成工作而不会超时。


如果您最终通过java -jar app.jar.jar 文件运行您的应用程序,请注意Boot breaks if the .jar file is overwritten,您需要确保在复制工件之前停止应用程序。如果您使用的是ApplicationPidListener,您可以通过添加以下命令的执行来验证应用程序是否正在运行(如果是,则停止它):

> test -f application.pid && xargs kill < application.pid || echo 'App was not running, nothing to stop'

【讨论】:

echo "mvn spring-boot:run" | at now(没有 1 分钟的延迟)在我的情况下也很有效。 @Abdull 这可能取决于 unix 的版本;在 Ubuntu 上 now 将安排在当前分钟的 00 秒(即甚至可能在过去)。我刚刚在 Mac 上尝试了at now + 1 minutes,它抱怨说“pluralization is wrong”:-| 你必须安装在 (es. sudo apt-get install at) 如果一个应用程序有两个环境怎么办? DEV 环境和 PROD 环境。当一个运行(即使另一个端口)另一个停止。我认为这是 Jenkins 仅使用一个 shell 的情况,当一个环境开始运行时它会被阻塞。这种情况下该如何处理?【参考方案2】:

我发现首先将工件复制到服务器上的指定区域以跟踪已部署的工件而不是从 jenkins 工作文件夹启动应用程序非常有用。然后在那里创建一个服务器日志文件并开始在 jenkins 窗口上监听它,直到服务器启动。

为此,我开发了一个小 shell 脚本,你可以找到 here

您还会在 jenkins 上找到一篇解释如何配置项目的小文章。

如果对您有用,请告诉我。谢谢

【讨论】:

【参考方案3】:

nohupat now + 1 minutes 对我不起作用。 由于 Jenkins 正在杀死在后台运行的进程,因此我通过为该 Jenkins 任务设置一个虚假的 BUILD_ID 来确保该进程不会被杀死。这是 Jenkins Execute shell 任务的样子:

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

正如here所讨论的那样。

【讨论】:

【参考方案4】:

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

    以 root 身份登录服务器。 运行sudo visudo 在末尾添加“jenkins ALL=(ALL) NOPASSWD:ALL”(jenkins=您的 Jenkins 用户) 在 Jenkins 中登录并选择您的工作并点击配置 在“构建后步骤”中选择“执行 Shell” 复制并粘贴此内容:
   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??。这是潜在的危险,因为您正在为 jenkins 用户提供在服务器上执行任何命令的完全权限。如果 jenkins 安装以某种方式受到损害,黑客将完全控制系统。对于更严格的访问限制,您可以将其更改为:jenkins ALL=(ALL) NOPASSWD:comma_seperated_commands。由于这里有几个命令,所以上面的整个代码可以放在一个脚本中,比如myapp_service.sh,然后将 sudo 命令更新为jenkins ALL=(root) NOPASSWD:/full_path_to/myapp_service.sh【参考方案5】:

这在 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

【讨论】:

以上是关于如何使用 Jenkins 部署 Spring Boot Maven 应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

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

springboot(十六):使用Jenkins部署Spring Boot

在 Jenkins 上部署 Spring Boot 应用程序

使用Jenkins + Gitlab自动构建Spring Boot项目,并部署到远程服务器上

使用Jenkins + docker 自动化部署Spring boot 微服务 详尽操作流程

Jenkins部署Spring boot项目失败