尽管这里有几个类似的问题,但我还是没能找到能够满足我需求的问题。
因此我需要运行一个脚本,将我的应用程序部署到远程服务器上。因此,当我的 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