Автоматично запускати команди через 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 (але я думаю, це насправді не має значення.



1
Я думаю, що це не дублікат, тому що згадуване вами посилання навіть не містить SSH.
LanceBaynes

4
Якщо ви цього не зробили, вам слід налаштувати ssh-сервери на всіх машинах, зробити пару приватних / відкритих ключів на машині, з якої ви працюєте, і скопіювати відкритий ключ до облікових записів на сервері, щоб запобігти надалі проблем з паролем. Це стосується моєї відповіді, а також для @ demure.
Антон

Відповіді:


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"

1
що саме чекати в цьому сценарії ?? ти!
LanceBaynes

що станеться, якщо ключ сервера відсутній у моєму файлі знань_хостів?
LanceBaynes

5
розміщення сценаріїв на задньому плані створює дочірні процеси. Коли дочірній процес закінчується, процес 'слот' і ресурси залишаються в системі до тих пір, поки не завершиться батьківський процес або батьківський процес не чекає дитини. Ці "завершені ще присутніми" процеси називаються "зомбі" процесами. Гарне поведінка - це прибирання після переробки дитини та повернення ресурсів.
Арседж

1
Якщо невідомо, то це може зіпсувати це, але ви можете додати, -o StrictHostKeyChecking=noщоб цього уникнути. Однак краще спочатку сканувати всі сервери з командного рядка, щоб можна було додати хост-ключі.
Арседж

1
Як я вже згадував, після того, як програма ssh буде відтворена на другий план і після її завершення, ресурси все ще зберігаються. waitКоманда вивільняє ці ресурси, в тому числі код процесу повернення (як processs збудженому). Потім, якщо пізніше в програмі ви поставите інший процес, скажімо, стиснення, на задньому плані і його потрібно дочекатися, то без цього циклу очікування поверне одну із завершених програм ssh, а не стиснення - що може все-таки бігати. Ви отримаєте статус повернення за неправильним процесом дитини. Добре прибирати за собою.
Арседж

61

Існує декілька інструментів, які дозволяють входити та виконувати ряд команд на кількох машинах одночасно. Ось пара:


1
Ви можете додати pdsh до списку.
Ріккардо Муррі

1
Я знайшов clusterssh досить інтуїтивно зрозумілим у використанні. Тільки мої 2 копійки ...
josinalvo

1
Я часто використовую pssh. Це працює дуже добре, хоча я б хотів сказати, що певні віддалені команди матимуть ненульовий код виходу, і це не означає помилку. Це суто косметично.
Ентоні Кларк

1
@AnthonyClark ви могли додати до цих команд щось на зразок "|| true".
exic

16

Якщо ви використовуєте сценарії Python більше, ніж bashсценарії, то 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 так тільки на контролері
Антон

1
@ Özzesh Подивіться, чи висвітлено ваші причини не встановлення GNU Parallel на oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html
Ole Tange

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
це я шукав !!!!! Спасибі michas
Özzesh

вищевказаний скрипт працює для мене добре, але після виконання на 10 серверах сценарій не відповідає. Як я можу вийти з сервера ssh, до якого я підключений?
Özzesh

Вам не потрібно буде чітко виходити з системи. Цей "скрипт" буде просто працювати ssh $host $commandдля кожного хоста. Спробуйте запустити ці команди вручну, щоб дізнатися, що відбувається.
michas


2

Я думаю, ви шукаєте pssh та пов'язані з ними паралельні версії звичайних scp, rsync тощо.


Це один голос від видалення, але ця відповідь пізніше - +10. Має ідеальний сенс
Майкл Мрозек

@MichaelMrozek Це гірше, ніж ви знаєте. Другий з двох ВТД - це моя аварія. Я відкрив цю вкладку протягом декількох днів, маючи намір подати прапор або пінг вам повернути мій 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 та встановлює зв’язки та видає команди асинхронно та паралельно для максимального паралелізму. Для отримання повної документації див. Інструмент SSH Multi-Host . Щоб виконати команду на наборі хостів, виконайте її так:

$ 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

Я розробив collectionnode Дуже простий і ефективний для виконання завдань, виконаних на декількох серверах (вікна включені)

Як користуватися 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/


1
Здається, ви розробник CollectNode. У такому випадку ви повинні розкрити, що у відповіді це просто спам.
muru

Вибачте, це був не мій намір, відповідь модифікований, щоб бути більш конкретним.
fvidalmolina

1

Просто голова на справді приємне запитання:

Найкраще рішення, яке я знайшов, - не надто дивно, tmux.

Ви можете зробити Ctrl-B: встановити панелі синхронізації в tmux для дивовижної зміни. Для цього у вас повинні бути відкриті всі ваші ssh-з'єднання на різних областях 1 вікна Tmux.


0

Можливо, щось подібне працює, щоб запустити команду на декількох хостах? припустимо, всі хости встановлюються в .ssh / config для входу без пароля.

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


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"

Де записаний вихід? Як обробляються ненульові статуси виходу? Будь ласка, не відповідайте на коментарі; відредагуйте свою відповідь, щоб зробити її більш зрозумілою та повною.
G-Man каже: "Відновіть Моніку"

0

Використовуйте параміко http://www.paramiko.org/ і паралелізм на основі нитки https://docs.python.org/3/library/threading.html .низуючий код дозволяє паралельно виконувати кілька команд на кожному сервері!

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.