Вопрос или проблема
У меня есть следующий код:
for i in $ipb $ipc $ipd; do
ssh -i ~/.ssh/'key' 'name'@${i} /bin/bash << EOF
nohup ${install_dir}/redis-stable/src/redis-server ${install_dir}/${port}/node.conf &
EOF
let "port++"
done
который должен запустить серверы Redis на всех трех IP-адресах.
Однако, в настоящее время выполняется только первая команда (на $ipb
).
Замечание: если команда nohup
вводится вручную,
когда сервер Redis запущен с помощью команды,
пользователь должен нажать Enter, чтобы можно было ввести другие команды.
Проблема не связана с Redis, а скорее связана с тем, как написан скрипт, так что для этого случая не нужно знание Redis.
Ssh также работает нормально.
Что я должен изменить, чтобы запускать все три команды (по одной на каждый IP-адрес)?
Объяснение
Вы указали команду (/bin/bash
) для ssh
без -t
, поэтому на удаленной стороне не выделяется tty. Затем происходят две вещи:
-
nohup
не перенаправляет стандартные потоки (это произошло бы, если бы был tty); -
SSH-сервер ждет eof перед отключением, локальный
ssh
продолжает работать.А eof происходит, когда нет файлового дескриптора, открытого каким-либо процессом на записи в конце канала, что обычно случается, когда все процессы, stdout которых не был перенаправлен в другое место, завершены.
Перенаправление стандартных потоков, как вы сделали в вашем ответе, заставляет SSH-сервер отключиться рано.
Нашел проблему, добавив это в конце строки nohup (прямо перед &)
> foo.out 2> foo.err < /dev/null
спасибо @berndbausch за указание правильного направления!
Ответ или решение
Для устранения проблемы, связанной с зависанием скрипта при запуске фоновой задачи на удалённом хосте через SSH, необходимо прежде всего понять, почему это происходит. Основная причина заключается в том, как именно работают ssh
и nohup
в данном контексте.
Проблема
При выполнении команды ssh
, когда не используется опция -t
, удалённая сторона не создает псевдотерминал. В результате этого возникают следующие проблемы:
-
Отсутствие перенаправления стандартных потоков с помощью
nohup
: Если бы псевдотерминал был доступен,nohup
автоматически перенаправил бы стандартные потоки; однако без него этого не происходит. -
Зависание SSH-сеанса: SSH сервер ожидает достижения конца файла (EOF) для разрыва соединения. Процесс SSH на локальной стороне продолжает работать до тех пор, пока есть открытые дескрипторы файлов для записи в поток, что зачастую случается, если выходной поток процесса не перенаправлён.
Решение
Решение вашей проблемы заключается в явном управлении стандартными потоками, что было замечено вами после внесения следующих изменений в код:
for i in $ipb $ipc $ipd; do
ssh -i ~/.ssh/'key' 'name'@${i} /bin/bash << EOF
nohup ${install_dir}/redis-stable/src/redis-server ${install_dir}/${port}/node.conf > foo.out 2> foo.err < /dev/null &
EOF
let "port++"
done
Добавление > foo.out 2> foo.err < /dev/null
перед &
позволяет:
- Перенаправить стандартный вывод в файл
foo.out
, сохраняя информацию о запуске сервера. - Перенаправить стандартный поток ошибок в файл
foo.err
, что помогает в случае диагностики. - Отключить стандартный ввод, используя
/dev/null
, чтобы избежать блокировки ввода и, соответственно, разрыва SSH-соединения по EOF.
Таким образом, перенаправление потоков гарантирует, что все связанные с этим процессы завершаются, и SSH-соединение разрывается корректно после запуска команд на всех указанных IP-адресах.
Заключение
Правильное управление потоками ввода-вывода является критически важным аспектом при удалённом выполнении команд через SSH, особенно когда речь идёт о запуске фоновых процессов. Корректная настройка перенаправления стандартных потоков позволит предотвратить потенциальные блокировки и обеспечить стабильную работу вашего сценария.
Если у вас появятся дополнительные вопросы, обращайтесь – я всегда готов помочь.