Автоматически запускать команды через SSH на многих серверах

46

В файле .txt есть список IP-адресов, например:

1.1.1.1
2.2.2.2
3.3.3.3

За каждым IP-адресом находится сервер, и на каждом сервере есть sshd, работающий на порте 22. Не каждый сервер находится в known_hostsсписке (на моем компьютере Ubuntu 10.04 LTS / bash).

Как я могу запускать команды на этих серверах и собирать вывод?

В идеале я хотел бы запускать команды параллельно на всех серверах.

Я буду использовать аутентификацию с открытым ключом на всех серверах.

Вот некоторые потенциальные подводные камни:

  • SSH побуждает меня поместить данный SSH ключ сервера в мой known_hostsфайл.
  • Данные команды могут возвращать ненулевой код выхода, что указывает на то, что вывод потенциально недействителен. Мне нужно это признать.
  • Возможно, не удалось установить соединение с данным сервером, например, из-за сетевой ошибки.
  • Должен быть тайм-аут в случае, если команда выполняется дольше, чем ожидалось, или сервер не работает во время выполнения команды.

Серверы AIX / ksh (но я думаю, что это не имеет значения.

LanceBaynes
источник
1
Я думаю, что это не дубликат, потому что ссылка, которую вы упоминаете, даже не содержит SSH.
LanceBaynes
4
Если вы этого не сделали, вы должны настроить ssh-серверы на всех компьютерах, создать пару секретный / открытый ключ на машине, с которой вы работаете, и скопировать открытый ключ в учетные записи на сервере, чтобы избежать дальнейших проблем с паролями. Это относится и к моему ответу, и к @ demure's.
Энтон

Ответы:

14

Предполагая, что вы не можете установить pssh или другие программы, вы можете сделать что-то похожее на:

tmpdir=${TMPDIR:-/tmp}/pssh.$$
mkdir -p $tmpdir
count=0
while IFS= read -r userhost; do
    ssh -n -o BatchMode=yes ${userhost} 'uname -a' > ${tmpdir}/${userhost} 2>&1 &
    count=`expr $count + 1`
done < userhost.lst
while [ $count -gt 0 ]; do
    wait $pids
    count=`expr $count - 1`
done
echo "Output for hosts are in $tmpdir"
Arcege
источник
1
что именно ждет делать в этом сценарии ?? ти!
LanceBaynes
что произойдет, если ключ сервера отсутствует в моем файле know_hosts?
LanceBaynes
5
помещение сценариев в фоновый режим создает дочерние процессы. Когда дочерний процесс завершается, процессный слот и ресурсы остаются в системе до тех пор, пока не завершится родительский процесс или родительский процесс не ожидает дочернего процесса. Эти «завершенные все еще присутствующими» процессы называются «процессами зомби». Это хорошее поведение, чтобы убирать после того, как ребенок продолжает и восстанавливает ресурсы.
Arcege
1
Если не известно, то это может облажаться, но вы можете добавить, -o StrictHostKeyChecking=noчтобы избежать этого. Однако лучше сначала сканировать все серверы из командной строки, чтобы можно было добавить ключи хоста.
Arcege
1
Как я уже упоминал, после того, как программа ssh переведена в фоновый режим и после ее выхода ресурсы остаются. Команда waitвосстанавливает эти ресурсы, включая код возврата процесса (как вышли процессы). Затем, если позже в программе вы поместите другой процесс, скажем, сжатие, в фоновом режиме и должны ждать его, то без этого цикла ожидание вернет одну из завершенных программ ssh, а не сжатие, которое может бегать Вы получите статус возврата на неправильный дочерний процесс. Хорошо убирать за собой.
Arcege
61

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

Калеб
источник
1
Возможно, вы захотите добавить pdsh в список.
Риккардо Мурри
1
Я нашел clusterssh довольно интуитивно понятным в использовании. Просто мои 2 цента ...
josinalvo
1
Я часто использую pssh. Это работает очень хорошо, хотя я хотел бы сказать, что некоторые удаленные команды будут иметь ненулевой код выхода, и это не означает ошибку. Это чисто косметика, хотя.
Энтони Кларк
1
@AnthonyClark вы можете добавить что-то вроде «|| true» к этим командам.
Exic
16

Если вы занимаетесь написанием скриптов на Python больше, чем bashнаписанием скриптов, то Fabric может стать для вас инструментом.

С домашней страницы Fabric :

Fabric - это библиотека Python (2.5 или выше) и инструмент командной строки для оптимизации использования SSH для развертывания приложений или задач системного администрирования.

Он предоставляет базовый набор операций для выполнения локальных или удаленных команд оболочки (обычно или через sudo) и загрузки / выгрузки файлов, а также вспомогательные функции, такие как запрос работающего пользователя на ввод или прерывание выполнения.

Типичное использование включает создание модуля Python, содержащего одну или несколько функций, а затем выполнение их с помощью инструмента командной строки fab.

Риккардо Мурри
источник
Ткань v1 была потрясающей. К сожалению, Fabric v2 удалил большинство функций, которые сделали его полезным для этого варианта использования - в настоящее время не рекомендуется (июнь 2018 г.).
Meekohi
11

Я использую для этого параллельный GNU , в частности, вы можете использовать этот рецепт:

parallel --tag --nonall --slf your.txt command

Имея your.txtфайл с IP-адресом / именами сервера.

Энтон
источник
нет ли другого способа использовать только ssh? Поскольку я использую серверы своей компании, я не хочу устанавливать дополнительные пакеты
Özzesh
Конечно, раньше я делал это и раньше ssh, но вам нужен какой-то способ входа на другие компьютеры, и эти способы раньше были менее безопасными (например rsh). Вы не описываете, что вы используете сейчас, чтобы перейти от машины к машине ( telnet?, rsh?).
Энтон
1
@ Özzesh да только на контроллере
Anthon
1
@ Özzesh Посмотрите, описана ли ваша причина не установки GNU Parallel на oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html
Оле
1
@OleTange Только что понял, кто прокомментировал мой ответ% -). Спасибо за это отличное программное обеспечение.
Энтон
8

Очень базовая настройка:

for host in $(cat hosts.txt); do ssh "$host" "$command" >"output.$host"; done

Аутентификация с именем / паролем действительно не очень хорошая идея. Вы должны установить закрытый ключ для этого:

ssh-keygen && for host in $(cat hosts.txt); do ssh-copy-id $host; done
Михась
источник
1
это то, что я искал !!!!! Спасибо Михас
Оззеш
приведенный выше сценарий хорошо работает для меня, но после выполнения на 10 серверах сценарий не отвечает. Как я могу выйти с сервера SSH, к которому я подключен?
Оззеш
Вам не нужно явно выходить из системы. Этот «скрипт» будет просто запускаться ssh $host $commandдля каждого хоста. Попробуйте запустить эти команды вручную, чтобы узнать, что происходит.
Михас
4

Я предлагаю Ansible.cc . Это менеджер конфигурации и диспетчер команд.

Том
источник
2

Я думаю, что вы ищете pssh и связанные с ним параллельные версии обычного scp, rsync и т. Д.

unclejamil
источник
Это один голос от удаления, но этот более поздний ответ на +10. Имеет смысл
Майкл Мрозек
@MichaelMrozek Это хуже, чем ты думаешь. Второй из двух VTD - мой по счастливой случайности. Я открывал эту вкладку в течение пары дней, намереваясь пометить или проверить связь с вами, чтобы вернуть мой VTD, если он был удален. Может быть, вы могли бы просто перевернуть его сейчас, чтобы очистить голоса.
Калеб
@Caleb Исправил это
Майкл Мрозек
2

Я создал инструмент с открытым исходным кодом под названием Overcast, чтобы упростить эту задачу.

Сначала вы определяете свои серверы:

overcast import vm.01 --ip 1.1.1.1 --ssh-key /path/to/key
overcast import vm.02 --ip 2.2.2.2 --ssh-key /path/to/key

Затем вы можете запустить несколько команд и файлов сценариев для них, последовательно или параллельно, например так:

overcast run vm.* uptime "free -m" /path/to/script --parallel
Эндрю Чайлдс
источник
2

В проекте Hypertable недавно был добавлен многостанционный ssh-инструмент. Этот инструмент построен на libssh и устанавливает соединения и выдает команды асинхронно и параллельно для максимального параллелизма. См. Multi-Host SSH Tool для полной документации. Чтобы запустить команду на множестве хостов, вы должны выполнить ее следующим образом:

$ ht ssh 1.1.1.1,2.2.2.2,3.3.3.3 uptime

Вы также можете указать имя хоста или шаблон IP, например:

$ ht ssh 1.1.1.[1-99] uptime
$ ht ssh host[00-99] uptime

Он также поддерживает --random-start-delay <millis>параметр, который будет задерживать запуск команды на каждом хосте на случайный интервал времени от 0 до <millis>миллисекунд. Эту опцию можно использовать, чтобы избежать громких проблем со стадом, когда выполняемая команда обращается к центральному ресурсу.

Дуг Джадд
источник
2

Я разработал Collectnode, очень простой и эффективный для выполнения задач на нескольких серверах (включая Windows)

Как использовать CollectNode:

  1. Создайте список серверов для работы с:

    # cat hosts.file
    server1
    server2
    server3
    server4
    server5
    
  2. Выполните CollectNode, передавая список обслуживаний:

    collectnode --file servers.txt --command='cat /etc/httpd/conf/httpd.conf |grep ^User'
    
  3. Опционально можно отфильтровать результаты, например, эта команда отображает только сервер, на котором выполняется условие.

    collectnode --file servers.txt --command='cat /etc/httpd/conf/httpd.conf |grep ^User' --where="command contain User"
    

https://collectnode.com/5-tasks-collectnode-can-help-managing-servers/

fvidalmolina
источник
1
Кажется, вы разработчик CollectNode. В этом случае вы должны раскрыть это в ответе или это просто спам.
Муру
извините, это не было моим намерением, ответ был изменен, чтобы быть более конкретным.
Фвидальмолина
1

Просто HeadSup для действительно хорошего вопроса:

Лучшее решение, которое я нашел, это, что неудивительно, tmux.

Вы можете сделать Ctrl-B: setw synchronize-panes в tmux для потрясающего результата. Для этого у вас должны быть открыты все ваши ssh-соединения в разных панелях 1 окна Tmux.

Михаил Крутов
источник
0

Может быть, что-то вроде этого работает, чтобы запустить команду на нескольких хостах? Предположим, что все хосты настроены в .ssh / config для входа без пароля.

$ < hosts.txt xargs -I {} ssh {} command

Y0NG
источник
0

Создайте файл / etc / sxx / hosts

заселить вот так:

[grp_ips]
1.1.1.1
2.2.2.2
3.3.3.3

поделитесь ключом ssh на всех машинах.

Установите sxx из пакета:

https://github.com/ericcurtin/sxx/releases

Затем запустите команду так:

sxx username@grp_ips "whatever bash command"
ericcurtin
источник
Где записан вывод? Как обрабатываются ненулевые состояния выхода? Пожалуйста, не отвечайте в комментариях; отредактируйте свой ответ, чтобы сделать его более понятным и полным.
G-Man говорит: «Восстановите Монику»
0

Использование http://www.paramiko.org/ Paramiko и параллелизма на основе потоков https://docs.python.org/3/library/threading.html .below позволяет выполнять несколько команд на каждом сервере параллельно!

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.load_system_host_keys()
ssh.connect(hostname, port, username, password)
t = threading.Thread(target=tasks[index], args=(ssh, box_ip,))
t.start()

Примечание: повторите приведенные выше инструкции для каждого сервера.

Шарма
источник
0

Я думаю «ожидать» - это то, что вам нужно.
Многие люди даже не знают, что он существует. Это основанная на Tcl программа, которая будет задавать вопросы и возможные ответы от вашего имени. Загляните на https://wiki.tcl-lang.org/page/Expect

милостивый
источник