[Системное администрирование] ossh: параллельное выполнение команд на многих серверах

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
15-Мар-2021 06:30

Иногда бывает нужно запустить патч Бармина какую-то команду на многих серверах и желательно не ждать слишком долго результатов выполнения. Для этого я написал ossh (One SSH to rule them all). Вот пример его работы:
$ wc -l /tmp/ossh.ips
21418 /tmp/ossh.ips
$ time ossh -n -h /tmp/ossh.ips -c uptime -p 1000 >/tmp/ossh.out
real    3m10.310s
user    0m30.970s
sys     0m19.282s
$ grep 'load average' /tmp/ossh.out | sort -n -k5 | tail -n1
10.23.91.97   [1]  13:37:55 up 828 days,  2:34,  0 users,  load average: 8.29, 4.45, 3.90
$

В данном примере в файле /tmp/ossh.ips находится 21418 ip адресов машин. -n означает, что не нужно делать реверс запросы, чтобы определить имя по адресу. -c uptime задает команду, которую я хочу выполнить. -p 1000 позволяет использовать до 1000 соединений одновременно. Как видно из вывода отработала команда достаточно быстро.
Что еще умеет ossh?
$ ossh -?
Usage: ossh [-?AinPv] [-c COMMAND] [-C COMMAND_FILE] [-H HOST_STRING] [-h HOST_FILE] [-I FILTER] [-k PRIVATE_KEY] [-l USER] [-o PORT] [-p PARALLELISM] [-T TIMEOUT] [-t TIMEOUT] [parameters ...]
-?, --help        Show help
-A, --askpass     Prompt for a password for ssh connects
-c, --command=COMMAND
                   Command to run
-C, --command-file=COMMAND_FILE
                   file with commands to run
-H, --host=HOST_STRING
                   Add the given HOST_STRING to the list of hosts
-h, --hosts=HOST_FILE
                   Read hosts from file
-i, --ignore-failures
                   Ignore connection failures in the preconnect mode
-I, --inventory=FILTER
                   Use FILTER expression to select hosts from inventory
-k, --key=PRIVATE_KEY
                   Use this private key
-l, --user=USER   Username for connections [$LOGNAME]
-n, --showip      In the output show ips instead of names
-o, --port=PORT   Port to connect to [22]
-p, --par=PARALLELISM
                   How many hosts to run simultaneously [512]
-P, --preconnect  Connect to all hosts before running command
-T, --connect-timeout=TIMEOUT
                   Connect timeout in seconds [60]
-t, --timeout=TIMEOUT
                   Run timeout in seconds
-v, --verbose     Verbose output
$

Список хостов можно задать либо прямо в командной строке через опцию -H (в случае нескольких хостов их надо перечислить через пробел, а весь список взять в кавычки как в примерах ниже) либо загрузить из файла при помощи опции -h. Строки в файле, начинающиеся с #, игнорируются. Адрес может содержать порт: my.host:2222. Можно использовать brace expansion: «host{1,3..5}.com» превратится в «host1.com host3.com host4.com host5.com». И -H и -h можно использовать многократно.
Для авторизации будут использованы
  • пароль, который ossh запросит при использовании опции -A
  • ssh ключ, заданный опцией -k
  • ssh-agent (в этом случае у вас должна быть определена переменная окружения SSH_AUTH_SOCK)

Именно в таком порядке.
Иногда бывает нужно убедиться, что вы можете залогиниться на все машины прежде чем выполнить команду. Для этого есть опция -P. По умолчанию если хоть одна машина будет недоступна ossh завершится с ошибкой. Если вы хотите игнорировать неудачные соединения используйте опцию -i.
Ossh может использовать вашу систему инвентаризации. Для этого в путях должна находится команда ossh-inventory, которой будут переданы параметры опции -I. Эта опция может быть использована многократно. Команда ossh-inventory должна выдавать на стандартный вывод строки в формате:
имя_машины адрес_машины

Где адрес_машины может быть как днс именем, так и ip адресом.
Команды для выполнения задаются опциями -C (читать из файла) или -c (брать из командной строки). Эти опции могут использоваться многократно. При наличии и -C и -c сперва выполнятся команды из файлов, потом из командной строки.
Помимо просто выполнения команд при помощи ossh можно стримить логи в реальном времени:
$ ossh -H "web05 web06" -c "tail -f -c 0 /var/log/nginx/access.log|grep --line-buffered Wget"
web05 192.168.1.23 - - [22/Jun/2016:12:24:02 -0700] "GET / HTTP/1.1" 200 1532 "-" "Wget/1.15 (linux-gnu)"
web05 192.168.1.49 - - [22/Jun/2016:12:24:07 -0700] "GET / HTTP/1.1" 200 1532 "-" "Wget/1.15 (linux-gnu)"
web06 192.168.1.117 - - [22/Jun/2016:12:24:23 -0700] "GET / HTTP/1.1" 200 1532 "-" "Wget/1.15 (linux-gnu)"
web05 192.168.1.29 - - [22/Jun/2016:12:24:30 -0700] "GET / HTTP/1.1" 200 1532 "-" "Wget/1.15 (linux-gnu)"
...

Вот симуляция rolling deployment:
$ ossh -p 1 -H "test0{1..3}" -c "sleep 10 && date"
test01 Wed Jun 22 12:38:24 PDT 2016
test02 Wed Jun 22 12:38:34 PDT 2016
test03 Wed Jun 22 12:38:44 PDT 2016
$

Видно, что команды выполняются на машинах последовательно. В каждый момент времени задействована только одна машина. Для настоящего деплоймента «sleep 10 && date» надо заменить на, к примеру, “apt-get install -y your_package”.
Именно для деплоймента была написана самая первая версия ossh. Кто-то спросит почему я не использовал какую-то общепринятую систему управления конфигурациями? Дело в том, что это было в далеком 2013-м году и мы использовали chef. Было ясно, что chef нас не устраивает в частности неопределенностью когда именно будут применены изменения (chef-client отрабатывал раз в 30 минут). Для того, чтобы согласованно выкатывать изменения на многих машинах некоторые разработчики применяли грязный хак: chef-client не работал постоянно, а однократно запускался (через ssh) только в тот момент, когда было нужно сделать деплоймент. Уже в тот момент шла работа по замене chef на salt, но переход был не простым и завершение его требовало дополнительного времени. Мы же разрабатывали новый сервис, который требовал частых деплойментов и раскатывался единственным дебиановским пакетом. Сперва мы использовали утилиту knife из состава chef. Эта утилита позволяла соединяться по ssh с нужными серверами и выполнять на них команды. В какой-то моент я понял, что chef в данном случае является лишним звеном и написал ossh.
Важно отметить, что ossh является инструментом для разрешения масштабных и нестандартных проблем. Если необходимость использовать ossh возникает часто это повод задуматься все ли у вас хорошо с инфраструктурой и управлением серверами. Вот некоторые ситуации, в которых ossh помог лично мне:
  • Однажды я наводил порядок в /root/.ssh/authorized_keys на большом количестве серверов (на тот момент их было около 7000). Разработчики прописали туда свои ключи, в частности для процессов обновления своих сервисов. Нужно было получить список всех ключей, использованных на всех машинах, и убедиться, что удаление этих ключей не приведет к катастрофическим последствиям.
  • Для безболезненного прохождения leap second
  • Когда мы боролись с TCP SACK PANIC правила для iptables выкатывались системой управления конфигураций. Чтобы убедиться, что все хорошо, я проверил наличие нужных правил при помощи ossh. И это было совсем не зря, обнаружились машины, на которых правила не применились.
  • Иногда мне приходится создавать тестовые среды состоящие из сотен (а иногда из тысяч) машин. Часто эти машины изолированы от production сети и не доступны для штатной системы управления конфигурациями. В подобных ситуациях конфигурирование машин можно проводить при помощи ossh.

Предвижу вопрос почему я не использовал готовое решение. Как я упомянул выше необходимость в прогонах команд на тысячах машин первый раз возникла у меня в 2013-м году. На тот момент мне удалось найти только parallel ssh, который не устроил меня следующим:
  • Мне не удалось поднять параллелизм выше 150, начали возникать ошибки при соединении с удаленными серверами
  • parallel ssh накапливал весь вывод и выдавал его по завершении команды. Стримить логи, к примеру, с его помощью было невозможно
  • Вывод parallel ssh был (лично для меня) неудобен для парсинга

Исходно ossh был написан на ruby, для увеличения производительности я задействовал event machine, а потом и fiber-ы. Относительно недавно я переписал ossh на go. Буду признателен если go-эксперты (я таковым на данный момент не являюсь) посмотрят на мой код и укажут на возможные способы улучшить его.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_sistemnoe_administrirovanie (Системное администрирование), #_ssh, #_linux, #_sistemnoe_administrirovanie (
Системное администрирование
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 07:28
Часовой пояс: UTC + 5