Выполнять удаленные команды, полностью отсоединяясь от ssh-соединения

48

У меня есть 2 компьютера, localpcи remoteserver.

Мне нужно localpcвыполнить несколько команд remoteserver. Одна из вещей, которую нужно сделать, - запустить скрипт резервного копирования, который выполняется в течение нескольких часов. Я хотел бы, чтобы команда включала localpc«огонь», а затем работала полностью независимо от того remoteserver, чего localpcникогда не было.

Это то, что я сделал до сих пор:

remoteserver Содержит имеет скрипт:

/root/backup.sh

localpc запланировано запустить это:

ssh root@remoteserver 'nohup /root/backup.sh' &

Я делаю это правильно? Есть лучший способ сделать это? Будут ли у меня проблемы с этим?

LVLAaron
источник
stackoverflow.com/questions/19996089/… и stackoverflow.com/questions/29142/… предоставляют ряд полезных подходов к этой проблеме, не использующих screen / tmux и т. д.
Пол

Ответы:

47

Вы, вероятно, должны использовать screenна удаленном хосте реальную отдельную команду:

ssh root@remoteserver screen -d -m ./script
enzotib
источник
Мне нравится эта идея. Когда сценарий завершится, экран все равно будет запущен ... и мне придется каким-то образом подключиться к нему в следующий раз, когда я захочу запустить его, верно?
LVLAaron
@AaronJAnderson: нет, учитывая, что команда не является оболочкой, когда она также завершается, сеанс экрана завершается.
энзотиб
52

Близко, но не совсем.

Независимо от любого терминала

ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'

Вам необходимо закрыть все файловые дескрипторы, которые подключены к сокету ssh, потому что сеанс ssh не закроется, пока какой-то удаленный процесс имеет открытый сокет. Если вас не интересует вывод скрипта (предположительно, потому что сам скрипт заботится о записи в файл журнала), перенаправьте его /dev/null(но учтите, что это скроет ошибки, такие как невозможность запуска скрипта).

Использование nohupздесь не имеет никакого полезного эффекта. nohupорганизует, чтобы программа, с которой она работает, не получала сигнал HUP, если управляющий терминал программы исчезает, но здесь, во-первых, нет терминала, так что ничто не собирается отправлять сигнал SIGHUP процессу на ровном месте. Кроме того, nohupперенаправляет стандартный вывод и стандартную ошибку (но не стандартный ввод) в файл, но только если они подключены к терминалу, чего, опять же, нет.

Отсоединение от терминала

 aaron@localpc$ ssh root@remoteserver
 root@remoteserver# nohup /root/backup.sh </dev/null &
 nohup: appending output to `nohup.out'
 [1] 12345
 root@remoteserver# exit
 aaron@localpc$ 

Используйте nohupдля отсоединения скрипта от его управляющего терминала, чтобы он не получал SIGHUP, когда терминал исчезает. nohupтакже перенаправляет стандартный вывод скрипта и стандартную ошибку в файл, который называется, nohup.outесли они подключены к терминалу; Вы должны позаботиться о стандартном вводе самостоятельно.

Ведение удаленного терминала

Если вы хотите, чтобы команда работала в удаленном терминале, но не была подключена к сеансу SSH, запустите ее в терминальном мультиплексоре, таком как Screen или Tmux .

ssh root@remoteserver 'screen -S backup -d -m /root/backup.sh'

Позже вы можете снова подключиться к терминалу, на котором запущен скрипт, вызвав screen -S backup -rdот имени пользователя root на этом компьютере.

Автоматизация одной удаленной команды

Для немного лучшей безопасности не открывайте прямые удаленные root-логины слишком широко. Создайте пару ключей специального назначения и дайте ей принудительную команду /root/.ssh/authorized_keys. Содержимое файла открытого ключа AAAA…== wibble@example.com: добавить разделенный запятыми список параметров, в том числе command="…"указывающий, что ключ может использоваться только для выполнения этой конкретной команды. Не забудьте сохранить параметры и ключ все в одной строке.

command="/root/backup.sh </dev/null >/dev/null 2>/dev/null &",no-port-forwarding,no-agent-forwarding,no-x11-forwarding,no-pty,no-user-rc AAAA…== wibble@example.com
Жиль "ТАК - перестань быть злым"
источник
Я попробовал первую команду, которую вы перечислили. Это не фон на поле, которое выполнило команду. Курсор просто сидит и ждет завершения ... возможно, это ошибка?
LVLAaron
Возможно, вам придется перенаправить стандартный ввод в / dev / null на удаленной системе. Может быть поэтому ssh не выходит.
KeithB
Я бы добавил -fопцию, чтобы получить ssh в 'background' (т.е. завершать, закрывать соединения) на локальной стороне. Это будет работать в сочетании с &. nohupв этом случае не является обязательным, но вы можете использовать setsidвместо этого.
Алексиос
@KeithB Перенаправление stdin является частью этого, но мне также нужно перенаправить stdout и stderr: nohup не будет делать это здесь, потому что они не терминалы, и фактически nohup здесь не полезен.
Жиль "ТАК - перестань быть злым"
1
@erikbwork Обратите внимание, что я абсолютно ничего не понимаю об этих вещах, но после обсуждения и комментариев: Жиль не использует опцию -t в своих командах, поэтому псевдотерминал не будет установлен ни на клиенте, ни на сервере. сторона. Следовательно, HUP не будет отправлен.
Бинар,
12

Стандартный рецепт для запуска удаленной команды из удаленного входа, такого как SSH, следующий:

nohup command </dev/null >command.log 2>&1 &

Если commandэто сценарий оболочки, который заботится о ведении журнала в сам файл, то вы можете изменить его command.logна /dev/null. Как только вы начнете это, выйдите из системы прямо сейчас.

Вам нужно все на этой линии.

nohup говорит оболочке не беспокоить процесс, если сеанс входа в систему отключен.

</dev/null говорит, что никогда не ждать ввода

>command.log говорит ему отправлять любые сообщения в этот именованный файл журнала

2>&1говорит ему отправлять любые сообщения stderr в один и тот же файл журнала. В некоторых случаях лучше иметь два файла, второй для сбора сообщений об ошибках и первый для сбора сообщений о нормальной активности. Это может упростить проверку того, что все работает правильно.

& говорит ему отключить этот процесс и запускать его в фоновом режиме как процесс демона.

Майкл Диллон
источник
10

Эта тема была очень полезной, но мое решение должно было быть немного другим.

Мне не нравится экранное решение, потому что оно оставляет запущенный экранный процесс, который мне не нужен. Перенаправления и nohups используются следующим образом:

ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'

не работали на меня при использовании с командой ssh.

Я создал скрипт-обертку на удаленной машине, который запускает сам скрипт. Скрипт-обёртка устанавливает перенаправление и nohup. Что-то вроде этого:

backupwrapper.sh:
nohup backup.sh > /dev/null 2>&1 &

Затем на моем клиентском компьютере я запускаю (не замечаю перенаправления):

# ssh remotemachine "backupwrapper.sh"
#

Команда ssh немедленно возвращается, соединение разрывается и скрипт остается запущенным.

Руи
источник
6

Как говорит Нильс , это проблема безопасности, позволяющая root войти в систему через ssh. И я советую не запускать какую-либо существенную работу на машине без журнала. Если что-то пойдет не так, вам хотелось бы, чтобы у вас были сообщения об устранении неполадок. Есть и другие ответы, показывающие, как это сделать. Но вот как я рекомендую выполнить то, что вы просили. Это все встроено в sh (1). Нет необходимости для экрана GNU (хотя я думаю, что это умное решение). Добавьте эту строку в вашу команду: >&- 2>&- <&- &. >&-означает закрыть стандартный вывод. 2>&-означает закрыть stderr. <&-означает закрыть стандартный &означает работать в фоновом режиме, например

$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$
tbc0
источник
0

Вы должны включить удаленную команду в фоновом режиме remoteserver. То, как вы это сделаете, создаст фоновую команду ssh localpc.

Кроме того, плохая идея разрешить root-ssh.

Так что настройте remoteserver: строку sudoers, которая будет запускаться /root/backup.shпользователем root backup.

Вы можете создать этого пользователя без «хорошего» пароля.

Поместите команду sudo /root/backup.sh &как команду в ~backup/.ssh/authorized_keys- вместе с открытым ключом от localpc(кто бы ни запускал этот скрипт).

Nils
источник
-1
#screen -d -m -S BACKUP ssh root@remoteserver /root/backup.sh
Killinks
источник
2
Это не очень полезно: если SSH-соединение прекратит работу, stdout и stderr скрипта будут закрыты, что может вызвать проблемы. Экран должен быть запущен на удаленной машине (как в ответе энзотиба ).
Жиль "ТАК - перестань быть злым"