You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现SSH远程多Bash脚本并行执行及结果获取问询

PHP通过SSH并行执行远程Bash脚本并获取执行结果

一、前置准备:配置SSH免密登录

要实现无交互的远程执行,首先得搞定主从节点的SSH密钥信任:

  • 在主节点(部署PHP的服务器)生成专用SSH密钥对:
    ssh-keygen -t ed25519 -N "" -f ~/.ssh/php_remote_exec
    
    这里-N ""设置空密码,-f指定密钥文件名,方便和其他密钥区分
  • 将公钥复制到所有从节点(执行脚本的服务器):
    ssh-copy-id -i ~/.ssh/php_remote_exec.pub user@remote-node-ip
    
    替换user和remote-node-ip为从节点的实际用户名和IP地址
  • 验证免密登录是否生效:
    ssh -i ~/.ssh/php_remote_exec user@remote-node-ip "echo 'Success'"
    
    直接输出Success就说明配置没问题了

二、核心实现代码

1. 单个远程脚本执行的完整示例(补全你提供的代码片段)

先把你中断的代码补全,同时加上关键的退出码和错误输出获取逻辑:

<?php
// 连接远程节点
$conn = ssh2_connect('remote-node-ip', 22);
// 使用密钥登录(避免密码交互)
ssh2_auth_pubkey_file($conn, 'user', 
    '/home/your-user/.ssh/php_remote_exec.pub', 
    '/home/your-user/.ssh/php_remote_exec');

// 执行目标远程脚本(替换为你的脚本路径)
$command = '/opt/scripts/your_task.sh';
$stream = ssh2_exec($conn, $command);
// 设置流为阻塞模式,确保能获取完整输出
stream_set_blocking($stream, true);

// 获取标准输出(stdout)
$stdout = stream_get_contents($stream);
// 获取标准错误输出(stderr)
$stderrStream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
stream_set_blocking($stderrStream, true);
$stderr = stream_get_contents($stderrStream);

// 获取命令执行的退出码(exit code)
$exitCode = ssh2_get_exit_status($stream);

// 清理资源
fclose($stream);
fclose($stderrStream);
ssh2_disconnect($conn);

// 输出结果
echo "退出码: {$exitCode}\n";
echo "标准输出:\n{$stdout}\n";
echo "错误输出:\n{$stderr}\n";
?>

这里重点补充了ssh2_fetch_stream获取错误输出、ssh2_get_exit_status获取退出码这两个你之前缺失的关键步骤。

2. 并行执行多个远程脚本的实现

因为PHP的ssh2_exec默认是阻塞的,要并行执行可以用pcntl_fork创建子进程,每个子进程处理一个远程节点的任务:

<?php
// 定义所有需要执行的远程节点和脚本信息
$remoteNodes = [
    ['ip' => 'node1.example.com', 'user' => 'admin', 'script' => '/opt/scripts/task1.sh'],
    ['ip' => 'node2.example.com', 'user' => 'admin', 'script' => '/opt/scripts/task2.sh'],
    ['ip' => 'node3.example.com', 'user' => 'admin', 'script' => '/opt/scripts/task3.sh'],
];

$keyPath = '/home/your-user/.ssh/php_remote_exec';
$pubKeyPath = '/home/your-user/.ssh/php_remote_exec.pub';

// 存储子进程ID与对应节点的映射
$childProcesses = [];

foreach ($remoteNodes as $node) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        die("无法创建子进程,系统资源不足");
    } elseif ($pid == 0) {
        // 子进程:单独处理一个远程节点的执行
        $conn = ssh2_connect($node['ip'], 22);
        ssh2_auth_pubkey_file($conn, $node['user'], $pubKeyPath, $keyPath);
        
        $stream = ssh2_exec($conn, $node['script']);
        stream_set_blocking($stream, true);
        $stdout = stream_get_contents($stream);
        $stderrStream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
        stream_set_blocking($stderrStream, true);
        $stderr = stream_get_contents($stderrStream);
        $exitCode = ssh2_get_exit_status($stream);
        
        // 将结果写入临时文件,供父进程读取
        $resultFile = "/tmp/remote_result_{$node['ip']}";
        file_put_contents($resultFile, json_encode([
            'node' => $node['ip'],
            'exitCode' => $exitCode,
            'stdout' => $stdout,
            'stderr' => $stderr
        ]));
        
        // 子进程执行完毕退出
        exit(0);
    } else {
        // 父进程:记录子进程ID
        $childProcesses[$pid] = $node['ip'];
    }
}

// 父进程等待所有子进程完成,然后收集结果
foreach ($childProcesses as $pid => $nodeIp) {
    pcntl_waitpid($pid, $status);
    // 读取子进程写入的结果
    $resultFile = "/tmp/remote_result_{$nodeIp}";
    $result = json_decode(file_get_contents($resultFile), true);
    echo "=== 节点 {$result['node']} 执行结果 ===\n";
    echo "退出码: {$result['exitCode']}\n";
    echo "标准输出:\n{$result['stdout']}\n";
    echo "错误输出:\n{$result['stderr']}\n\n";
    // 清理临时文件
    unlink($resultFile);
}
?>

这个方案通过子进程实现并行,每个节点的执行互不阻塞,能大幅提升多节点任务的处理效率。

三、关键注意事项

  • 确保PHP安装了ssh2扩展:可以用php -m | grep ssh2检查,没装的话可以通过pecl install ssh2(需要先安装libssh2依赖)或者系统包管理器安装(比如apt install php-ssh2或yum install php-ssh2)
  • 必须设置流为阻塞模式:否则可能只获取到部分输出内容
  • 远程脚本要加可执行权限:在从节点执行chmod +x /path/to/your_script.sh
  • 如果节点数量很多,建议限制子进程数量,避免耗尽系统资源,可以通过分批fork来实现

内容的提问来源于stack exchange,提问作者user3347598

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:29:56