Wykonuj polecenia zdalne, całkowicie odłączając się od połączenia ssh

48

Mam 2 komputery localpci remoteserver.

Muszę localpcwykonać kilka poleceń remoteserver. Jedną z rzeczy, które musi zrobić, jest uruchomienie skryptu kopii zapasowej, który będzie działał przez kilka godzin. Chciałbym, aby polecenie localpc„strzelało”, a następnie działało całkowicie niezależnie remoteserver, jak localpcnigdy wcześniej.

Oto co dotychczas zrobiłem:

remoteserver zawiera skrypt:

/root/backup.sh

localpc zaplanowano uruchomienie tego:

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

Czy robię to we właściwy sposób? Czy jest na to lepszy sposób? Czy napotkam jakieś problemy w ten sposób?

LVLAaron
źródło
stackoverflow.com/questions/19996089/... i stackoverflow.com/questions/29142/... zapewniają szereg użytecznych podejść do tego problemu bez korzystania z screen / tmux itp.
Paul

Odpowiedzi:

47

Prawdopodobnie powinieneś użyć screenna zdalnym hoście, aby mieć prawdziwe odłączone polecenie:

ssh root@remoteserver screen -d -m ./script
enzotib
źródło
Podoba mi się ten pomysł. Po zakończeniu skryptu ekran będzie nadal działał ... i musiałbym jakoś ponownie się z nim połączyć następnym razem, gdy chciałbym go uruchomić, prawda?
LVLAaron
@AaronJAnderson: nie, biorąc pod uwagę, że polecenie nie jest powłoką, gdy kończy się, sesja screen również się kończy.
enzotib
52

Blisko, ale nie do końca.

Niezależnie od dowolnego terminala

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

Musisz zamknąć wszystkie deskryptory plików, które są podłączone do gniazda ssh, ponieważ sesja ssh nie zostanie zamknięta, dopóki jakiś zdalny proces ma otwarte gniazdo. Jeśli nie interesuje Cię wyjście skryptu (przypuszczalnie dlatego, że sam skrypt zajmuje się zapisywaniem do pliku dziennika), przekieruj go na /dev/null(ale pamiętaj, że to ukryje błędy, takie jak niemożność uruchomienia skryptu).

Używanie nohupnie ma tutaj żadnego użytecznego efektu. nohuporganizuje, że program działa tak, aby nie odbierać sygnału HUP, jeśli terminal kontrolny programu zniknie, ale tutaj nie ma terminala, więc nic nie wyśle ​​SIGHUP do procesu nieoczekiwanie. Ponadto nohupprzekierowuje standardowe wyjście i standardowy błąd (ale nie standardowe wejście) do pliku, ale tylko wtedy, gdy są one podłączone do terminala, co też nie jest.

Odłączanie od terminala

 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$ 

Służy nohupdo odłączania skryptu od terminala sterującego, aby nie otrzymywał POWIĘKSZENIA, gdy terminal zniknie. nohupprzekierowuje również standardowe wyjście skryptu i standardowy błąd do pliku wywoływanego, nohup.outjeśli jest on podłączony do terminala; musisz sam zadbać o standardowe wejście.

Prowadzenie zdalnego terminala

Jeśli chcesz, aby polecenie działało w zdalnym terminalu, ale nie było dołączone do sesji SSH, uruchom je w multiplekserze terminali, takim jak Screen lub Tmux .

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

Możesz później ponownie połączyć się z terminalem, na którym działa skrypt, wywołując screen -S backup -rdjako root na tym komputerze.

Automatyzacja jednego zdalnego polecenia

Dla nieco lepszego bezpieczeństwa nie otwieraj zbyt często bezpośrednich zdalnych loginów root. Utwórz parę kluczy specjalnego przeznaczenia i wprowadź do niej wymuszone polecenie /root/.ssh/authorized_keys. Zawartość pliku klucza publicznego to AAAA…== [email protected]; dodaj listę opcji oddzieloną przecinkami, w tym command="…"która określa, że ​​klucza można użyć tylko do wykonania tego konkretnego polecenia. Pamiętaj, aby zachować wszystkie opcje i klucz w jednym wierszu.

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…== [email protected]
Gilles „SO- przestań być zły”
źródło
Próbowałem pierwszego polecenia, które wymieniłeś. Nie stanowi tła dla pola, które wykonało polecenie. Kursor po prostu tam siedzi i czeka na zakończenie ... może to błąd?
LVLAaron
Może być konieczne przekierowanie standardowego wejścia do / dev / null w systemie zdalnym. Być może dlatego ssh nie wychodzi.
KeithB
Dodałbym -fopcję, aby uzyskać ssh do „tła” (tj. Zakończyć, zamknąć połączenia) po stronie lokalnej. Będzie to działać w połączeniu z &. nohupjest w tym przypadku opcjonalny, ale możesz rozważyć użycie setsidzamiast niego.
Alexios
@KeithB Przekierowywanie stdin jest częścią tego, ale muszę też przekierować stdout i stderr: nic nie zrobi tego tutaj, ponieważ nie są to terminale, a tak naprawdę nic nie jest tu przydatne.
Gilles „SO- przestań być zły”
1
@erikbwork Należy pamiętać, że absolutnie nie mam pojęcia o tych rzeczach, ale po dyskusji i komentarzach: Gilles nie używa opcji -t w swoich poleceniach, więc nie zostanie ustanowiony pseudo terminal, ani na kliencie, ani na serwerze bok. Dlatego nie zostanie wysłany żaden HUP.
Binarus
12

Standardowy przepis na uruchomienie polecenia zdalnego ze zdalnego logowania, takiego jak SSH, jest następujący:

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

Jeśli commandjest skryptem powłoki, który zajmuje się logowaniem do samego pliku, możesz zmienić command.logna /dev/null. Po uruchomieniu wyloguj się od razu.

Potrzebujesz wszystkiego na tej linii.

nohup mówi powłoce, aby nie zakłócała ​​procesu, jeśli sesja logowania zostanie rozłączona.

</dev/null mówi, aby nigdy nie czekać na dane wejściowe

>command.log każe mu wysyłać wiadomości do tego nazwanego pliku dziennika

2>&1nakazuje mu wysyłanie komunikatów stderr do tego samego pliku dziennika. W niektórych przypadkach lepiej jest mieć dwa pliki, drugi do zbierania komunikatów o błędach, a pierwszy do zbierania normalnych komunikatów o aktywności. To może ułatwić sprawdzenie, czy wszystko działało poprawnie.

& każe mu odłączyć ten proces i uruchomić go w tle jako proces demona.

Michael Dillon
źródło
10

Ten wątek był bardzo pomocny, ale moje rozwiązanie musiało być nieco inne.

Nie podoba mi się rozwiązanie ekranowe, ponieważ pozostawia uruchomiony proces ekranowy, którego nie potrzebuję. Użyte przekierowania i nohups:

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

NIE działały dla mnie, gdy były używane z poleceniem ssh.

Utworzyłem skrypt opakowania na zdalnej maszynie, która uruchamia właściwy skrypt. Skrypt opakowania ustawia przekierowanie i nohup. Coś takiego:

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

Następnie uruchamiam na komputerze klienckim (zauważ, że nie ma przekierowań):

# ssh remotemachine "backupwrapper.sh"
#

Polecenie ssh natychmiast zwraca, połączenie zostaje zakończone, a skrypt pozostaje uruchomiony.

rui
źródło
6

Jak mówi Nils , zezwolenie rootowi na zalogowanie się przez ssh jest zagrożeniem bezpieczeństwa. I odradzam wykonywanie jakiejkolwiek znaczącej pracy na maszynie bez dziennika. Jeśli coś pójdzie nie tak, zechcesz mieć jakieś komunikaty o rozwiązywaniu problemów. Istnieją inne odpowiedzi pokazujące, jak to zrobić. Ale oto, w jaki sposób zalecam osiągnięcie tego, o co prosiłeś. Wszystko jest wbudowane w sh (1). Nie potrzeba ekranu GNU (choć myślę, że to sprytne rozwiązanie). Dołącz ten ciąg do polecenia: >&- 2>&- <&- &. >&-oznacza zamknij standardowe wyjście. 2>&-oznacza bliski stderr. <&-oznacza ścisłe standardowe. &oznacza bieg w tle, np

$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$
tbc0
źródło
0

Powinieneś w tle włączyć zdalne polecenie remoteserver. Sposób, w jaki to zrobisz, spowoduje włączenie polecenia ssh w tle localpc.

Poza tym złym pomysłem jest zezwolenie na root-ssh.

Więc skonfiguruj remoteserver: Linia sudoers, która będzie uruchamiana /root/backup.shprzez użytkownika jako root backup.

Możesz utworzyć tego użytkownika bez „dobrego” hasła.

Umieść polecenie sudo /root/backup.sh &jako polecenie w ~backup/.ssh/authorized_keys- razem z kluczem publicznym od localpc(kto uruchamia ten skrypt).

Nils
źródło
-1
#screen -d -m -S BACKUP ssh root@remoteserver /root/backup.sh
Killinks
źródło
2
To nie jest bardzo przydatne: jeśli połączenie SSH umrze, stdout i stderr skryptu zostaną zamknięte, co może powodować problemy. Screen powinien być uruchomiony na zdalnej maszynie (jak w odpowiedzi enzotibu ).
Gilles „SO- przestań być zły”