通过 SSH 远程执行脚本并断开与正在运行的进程的连接

通过 SSH 远程执行脚本并断开与正在运行的进程的连接

尽管这里有几个类似的问题,但我还是没能找到能够满足我需求的问题。

因此我需要运行一个脚本,将我的应用程序部署到远程服务器上。因此,当我的 CI 成功运行所有测试时,它应该运行部署脚本。

所以我显然希望我的 CI 在远程机器上运行该脚本。

我发现有几种方法可以让我的 CI 在远程服务器上运行脚本:

ssh user@remote_server 'SOME_ENV_VARS=staging_vars bash -s' < deploy.sh

这几乎完美地完成了工作。

我的部署脚本是这样的:

cd project
killall node;
bash start.sh -s & <- THIS IS IMPORTANT
exit;

我也尝试过:

nohup ./start.sh -s < /dev/null >/dev/null 2>&1 &
exit;

screen -dmS important_server bash start.sh -s 

start.sh 脚本是一个永无止境的进程(它启动服务器)。它工作正常,但从不断开与 ssh 的连接,所以我的 CI 无法完成构建。

我实际上能做到的最好的就是 Gaurav 的建议。在终止 ssh 连接后,该进程确实仍在后台。但我仍然需要手动终止它,因为我的 CI 工作挂起了 :(

我肯定做错了什么事。

答案1

要在后台执行程序并退出,请使用 nohup。nohup 将确保程序在 ssh 会话终止后仍在运行。

nohup ./start.sh < /dev/null >/dev/null 2>&1 & 

如果您的程序需要任何输入或打印输出到控制台,从 /dev/null 接收和发送输入/输出将会有所帮助。

答案2

所以基本上经过 40 个小时左右的尝试和失败后我终于找到了解决方案。Shadowcoder 和 Gaurav 的答案确实很有帮助,但无济于事。

所以基本上我不知道为什么这个答案会起作用,但它确实有效。问题在于我通过 SSH 在另一台机器上运行一台机器上的 bash 脚本。该脚本正在调用另一个脚本,并且必须退出 SSH 而让远程脚本继续运行。这听起来很复杂,但实际上在我看来是合理的。至少在我开始写它的时候听起来很合理。

让我们进一步解释一下事情(当我写这个问题时似乎并不重要)。

我的 CI/CD 软件在检测到推送到主分支时正在运行构建。构建成功后,它应该deploy.sh自动调用脚本以将更改发布到暂存服务器。相当标准。该脚本告诉远程服务器提取更改,停止服务器并重新启动它。显然,可以使用名为的单个脚本以 3 种模式(暂存、生产和开发)启动服务器start.sh

因此,部署脚本的主要目标是停止服务器、提取更改并重新启动启动脚本。

因此一开始我尝试使用 nohup。

我的 deploy.sh 脚本是这样的

cd project
killall node;
nohup ./start.sh -s < /dev/null >/dev/null 2>&1 &
exit;

查看我的 CI 日志,我发现无论我做什么,服务器实际上都运行顺利,我可以在暂存服务器上看到我的更改,但是这个脚本永远不会结束!SSH 连接永远保持打开状态。现在发生了奇怪的事情。在 CI 中手动关闭它时,服务器保持活动状态,这是所需的行为 - 但我不想在触发构建时手动干预。查看我的 CI 日志时,我确实注意到一件奇怪的事情。好像脚本在退出后正在等待另一个命令。所以在绝望中我又添加了一个退出。我的脚本现在

cd project
killall node;
nohup ./start.sh -s < /dev/null >/dev/null 2>&1 &
exit;
exit; 

确实,这个方法奏效了,但由于某种原因,start.sh当 SSH 退出时,进程被终止了。又回到原点。

几个小时后(大概十个小时)。我注意到 Shadowcoder 提出的屏幕解决方案(虽然在开始时不起作用)可能是可行的方法。

我的start.sh脚本正在启动我的服务器。其中包括数据库迁移、初始数据播种、构建 UI、设置内存缓存,tmpfs最后调用node index.js。由于我尝试重现该问题但失败了,因此我可以更新问题以获取 Shadowcoder 的信息,我尝试screen仅执行最后一个命令 (node index.js)。

这就是我想出解决方案的方法。

deploy.sh 脚本如下所示

./start.sh -s;

exit;
exit; #I have no idea why the hell I need 2 exits but it works

start.sh 脚本看起来很糟糕,但重要的是

screen -dmS server_name node index.js &

请注意,我仍然必须以它来结束命令,如果&没有它,它就无法工作,根本不知道为什么。

因此,这个解决方案看起来有点儿老套,我仍然确信我错过了什么,事情不必这样,但这确实有效。不确定为什么它有效或者为什么以前不起作用,但如果这可以节省别人的时间 - 解决方案就在这里。我也想知道这种行为的解释。

答案3

屏幕

使用apt install screen或从地点

连接到 SSH 服务器后:

# screen -q
...
# bash ./start.sh -s
...

您可以使用 Ctrl+A+D 与屏幕分离

或者,为了获得尽可能接近原始解决方案,请编辑 deploy.sh 以使用屏幕:

cd project
killall node;
screen -dmS important_server bash start.sh -s # No need to put screen in the background.
exit;

您正在使用的 ssh 命令应该可以与它兼容。

ssh user@remote_server 'SOME_ENV_VARS=staging_vars bash -s' < deploy.sh

相关内容