通过SSH在Windows启动后台进程,断开后进程不终止的问题
解决Jenkins SSH执行PowerShell脚本后Java进程被终止的问题
问题根源
通过SSH远程执行PowerShell脚本时,SSH会话会创建专属进程组,原脚本中Start-Process启动的javaw进程默认隶属于该组。当脚本执行完毕、SSH会话关闭时,系统会终止该进程组下的所有子进程,导致Java应用被强制杀死。
解决方案
方法1:调整PowerShell的Start-Process参数
在原脚本中为Start-Process添加-CreateNoWindow、-WindowStyle Hidden和-NoNewWindow参数,让进程脱离SSH会话的控制台控制:
$SSL_KEYSTORE_PASSWORD = $args[0] Write-Output "Running war in the background" Start-Process javaw -ArgumentList "-jar", ` "e:\app\app.war", ` $("-Dserver.ssl.key-store-password=" + $SSL_KEYSTORE_PASSWORD), ` "-Dserver.tomcat.basedir=e:\app" ` -RedirectStandardOutput "e:\app\output\stdout.txt" ` -RedirectStandardError "e:\app\output\stderr.txt" ` -CreateNoWindow ` -WindowStyle Hidden ` -NoNewWindow Write-Output "Starting javaw instance"
方法2:通过CMD的start /b启动独立进程
利用Windows CMD的start /b命令启动javaw,让进程完全脱离当前SSH会话的进程组:
$SSL_KEYSTORE_PASSWORD = $args[0] Write-Output "Running war in the background" $arguments = @( "-jar", "e:\app\app.war", "-Dserver.ssl.key-store-password=$SSL_KEYSTORE_PASSWORD", "-Dserver.tomcat.basedir=e:\app" ) -join " " # 通过cmd启动独立进程,输出重定向到指定文件 cmd /c "start /b javaw $arguments > e:\app\output\stdout.txt 2> e:\app\output\stderr.txt" Write-Output "Starting javaw instance"
方法3:将Java应用注册为Windows服务(推荐长期稳定运行)
使用NSSM(Non-Sucking Service Manager)将Java应用注册为Windows服务,彻底脱离SSH会话依赖,还能实现开机自启:
- 下载NSSM到服务器
e:\app目录 - 修改PowerShell脚本添加服务管理逻辑:
$SSL_KEYSTORE_PASSWORD = $args[0] $serviceName = "MyJavaApp" $javawPath = (Get-Command javaw).Path $arguments = "-jar e:\app\app.war -Dserver.ssl.key-store-password=$SSL_KEYSTORE_PASSWORD -Dserver.tomcat.basedir=e:\app" $stdoutPath = "e:\app\output\stdout.txt" $stderrPath = "e:\app\output\stderr.txt" # 检查服务是否存在,不存在则注册 if (-not (Get-Service -Name $serviceName -ErrorAction SilentlyContinue)) { e:\app\nssm.exe install $serviceName $javawPath e:\app\nssm.exe set $serviceName AppParameters $arguments e:\app\nssm.exe set $serviceName AppStdout $stdoutPath e:\app\nssm.exe set $serviceName AppStderr $stderrPath e:\app\nssm.exe set $serviceName Start SERVICE_AUTO_START } # 停止运行中的服务 if ((Get-Service -Name $serviceName).Status -eq 'Running') { e:\app\nssm.exe stop $serviceName Start-Sleep -Seconds 5 } # 启动服务 e:\app\nssm.exe start $serviceName Write-Output "Started Java application service: $serviceName"
启动校验逻辑扩展
可以在PowerShell脚本中添加进程启动校验,避免Jenkinsfile臃肿:
# 校验进程是否启动成功 Start-Sleep -Seconds 10 $javawProcess = Get-Process javaw -ErrorAction SilentlyContinue if ($javawProcess) { Write-Output "Java application started successfully, PID: $($javawProcess.Id)" } else { Write-Error "Failed to start Java application" exit 1 }
内容的提问来源于stack exchange,提问作者Riggs Markham
相关产品推荐
相关产品推荐

