使用 SSH 进行远程同步然后异步执行

使用 SSH 进行远程同步然后异步执行

总结

我想远程执行一个脚本,该脚本以同步开始(这样,如果准备命令失败,本地 ssh 命令也会失败),然后异步执行,从而终止本地 ssh 命令。

细节

我在远程服务器上有一个脚本,它可以缓慢地下载一个几 GB 的文件。我想使用 ssh remote-server 'nohup /path/to/script 参数' 从本地服务器通过 SSH 启动此脚本,但当我知道该脚本已成功开始下载时,会终止 SSH 连接。一旦启动,SSH 连接就没有任何用处,在下载过程中系统性地失败,并阻止在本地服务器上执行。

我不能只做ssh -f或者ssh &因为如果远程脚本没有启动,下载之前的第一个命令失败,或者远程服务器无法访问,我需要命令在本地服务器上失败。

我尝试了各种nohup技巧screen。我最接近的是以下方法:

  • 由本地服务器启动:

    ssh -t me@remote-server 'screen -S long-download /path/to/download.sh'
    

    或者

    ssh -t me@remote-server 'nohup screen -S long-download /path/to/download.sh'
    
  • download.sh远程服务器上启动:

    preliminary-instructions
    # if anything fails so far then the local server's ssh command should fail synchronously
    download-command &
    some-more-checking
    screen -d long-download # we can now safely end the ssh session
    

但不知为何screen还是被杀了……

样本复现代码

  • 在远程服务器上,位于/path/to/test.sh

    #!/bin/bash
    # uncomment this line to validate synchronous failure
    sleep 10 && echo foo >/tmp/bar &
    screen -d long-download
    
  • 本地:

    ssh -t me@remote-server 'nohup screen -S long-download /path/to/test.sh'
    

答案1

查看 ssh 子系统。我做了类似的事情,但没有使用脚本(即我使用 a.out/elf 编译的程序)。但我刚刚用 bash 脚本测试了一下,它有效。

来自 ssh 手册页:

     -s      May be used to request invocation of a subsystem on the remote
         system.  Subsystems are a feature of the SSH2 protocol which
         facilitate the use of SSH as a secure transport for other appli-
         cations (eg. sftp(1)).  The subsystem is specified as the remote
         command.

在客户端上使用 -s(小写)指定子系统

在服务器上的 sshd_config 中添加另一个指向您的脚本的子系统条目。

    # override default of no subsystems
Subsystem       logger  /usr/local/libexec/my-logger.sh
Subsystem       sftp    /usr/libexec/sftp-server

您的脚本应该像任何其他具有执行权限的文件一样启动。我的示例:

#! /usr/local/bin/bash
logger "testing 1.2.3"
echo "return text from my-logger"
exec 0>&- # close stdin
exec 0<&- 
exec 1>&- # close stdout
exec 1<&- 
exec 2>&- # close stderr 
exec 2<&- 
logger "subsystem: nohup new script"
nohup /path/to/another/script/logger2.sh &  
logger "subsystem: the subsystem started script is now done"
exit 0  

您应该能够返回有用的成功或失败错误文本。ssh 连接(以及 stdin、stdout 和 stderr)在子系统结束它之前一直处于打开状态。子系统可以继续运行,也可以停止运行。

让其他脚本(上面的 logger2.sh)休眠 5-10 分钟,这样您就可以使用 netstat 查看 ssh 连接是否断开,ssh 客户端是否返回到 shell,例如 ps ax 显示脚本仍在后台运行。此脚本可能还需要关闭 fd 等。这只是一个简单的例子。祝你好运。

答案2

替代解决方案对 BostonDriver 的回答:screen -d -m

async-launcher.sh

#!/bin/bash
echo connected &&
#       preliminary-command &&
        screen -S index-fetch -d -m $(cd ${0%/*} && pwd -P)/long-download.sh

sleep 5    # ensure long-download.sh didn't immediately fail
if ((`screen -ls | grep index-fetch | wc -l`)); then
        echo ok
else
        echo ko
        exit 1
fi

并且long-download.sh可以包含所有的异步命令。

通过简单的 启动ssh me@remote-server /path/to/async-launcher.sh。还有一个额外的好处:屏幕可以稍后重新连接。

相关内容