Pull to refresh

Comments 26

Велосипеды разные нужны, велосипеды разные важны.
Я здесь вижу как минимум годный пример для изучения языка, во-вторых, кому-то ansible может не подойти по тем или иным причинам.
Ansible выглядит очень интересно, спасибо. Но, я думаю, для многих задач системы вроде chef, puppet, ansible слишком громоздки в настройке, если вам нужно всего-лишь, скажем, выполнить «svn up» на всех серверах :). Как мне кажется, системы вроде ansible предназначены больше для управления конфигурациями, а libpssh, GoSSHa подходят для, например, деплоя кода (у нас используется libpssh+uftp для деплоя кода, puppet для сишных сервисов и системных пакетов, а также самописный, в 300 строк впраппер над rsync для управления конфигурациями nginx и прочего).
Мы для деплоя использовали связку fabric + puppet, сейчас хотим заменить fabric на ansible, так как он умеет все то же и даже больше…
Из требований, что Ansible заявляет к управляемым хостам — только Python 2.4 (на деле — что-то около Python 2.6 + некоторые операции требуют дополнительные модули), но простые ssh-команды можно выполнять без дополнительной подготовки управляемых серверов.

Но за статью все равно спасибо.
Автору, спасибо за статью и интересный опыт!

С другой стороны я давно хотел попробовать Ansible из-за его «безагентности». Недавно разговаривал с ними на SCALE, очень открытые и общительные ребята.
Моя инфраструктура — это зоопарк из Windows и Linux, поэтому puppet как нельзя лучше подходит в качестве единого средства управления конфигурациями. Эх, как бы я хотел роскошь *nix only!
Все выше можно сделать спомошью xargs.
Можно. Но, например, с общим таймаутом на исполнение будет уже довольно тяжело :). А если у вас сотни или тысячи серверов, то держать постоянно запущенными тысячи процессов кажется довольно расточительным, как для CPU, так и по потреблению памяти ядра.
Общий — совсем просто, одинаковый — еще проще.
Помню, на старой работе писали скрипт на php, который выполнял команды на операторских компьютерах (~250 штук) по ssh (благо везде стоял одинаковый дистр и логин/пароль на админский аккаунт). Чуть позже всё это чудо мигрировало на самописную систему клиентов и сервера, написанных на python, через которую можно было управлять машинами, обновлять приложения операторов и т.п., а также иногда втихаря издеватся над этими ж операторами (zenity рулил).

Эх, было время…
На прошлой работе управлял зоопарком из примерно 100 линуксовых машин с помощью консольной утилиты dsh.
Простой как 3 копейки и довольно удобно и параллельно.

Но в среде более неблагоприятной, например разные конфигурации машин, наверное понадобится что-то другое.
Неплохо. По коду бросается в глаза, что background автора — динамические языки ruby/python… )

А что добавлено в расширенной версии для продашна?
Неужели все так плохо :)? В GoSSHa добавлен JSON-протокол для выполнения команд, поддержка зашифрованных ключей и ssh-agent, загрузка файлов.
Без явных объявлений переменных читать код сложно. Не всегда понятно какой тип возвращает функция… )
Интересное замечание… :). Никогда об этом не задумывался, всегда опирался на здравый смысл, когда речь идет о типе возвращаемого значения из функции, слава богу в Go есть определенные соглашения, делающие интуитивное понимание типов возможным :). Но типы же при этом никуда не деваются и компилятор их проверяет, поэтому зачем писать лишние буквы :)?
Типичный подход адепта языков с динамической типизацией… )) Не буду утверждать что этот подход плохой или хороший. У всего есть достоинства и недостатки…

Когда вам нужно будет поправить чужой код или добавить функционал здравого смысла вам не хватит. Вам придется лезть в документацию и/или прыгать по всему коду искать определения функций и типов…
В IDE есть поддержка перехода к описанию функции, т.е. далеко лазать/прыгать не придется — горячую клавишу нажать. В IntelliJ с golang плагином например хорошо работает.
Крупный провайдер. Сегментированная сеть с кучей цисок. И одна циска центральная.

Обычный день, ничто не предвещает беды. Вдруг падает вся сеть. Народ в панике ищет в чём проблема. Оборачивается один сисадмин и говорит: «Я дико извиняюсь. Программировал новую циску. Стёр конфиг старый, перегрузил… Оказалось, это был центральный маршрутизатор… Окошком ошибся»

(с)bash
sync/WaitGrope еще сейчас популярно в дизайне таких штук на Go
В badoo разрешили писать не на PHP/C++?
В свободное от работы время любой работник компании Badoo всегда имел полное право писать на тех ЯП, на которых ему вздумается :). А если вам посчастливилось работать, скажем, в C-отделе, то на том же Go можно писать и в рабочее время, если это согласовано с руководителем.
Написал, для сравнения, то-же самое на Erlang. Запускать не пробовал.
В стандартной библиотеке есть полная реализация SSH сервера, клиента и SFTP.
main([Cmd | Hosts]) ->
    Timeout = 5000,
    Master = self(),

    erlang:send_after(Timeout, self(), timeout), % запускаем таймер

    %% используем генератор списков для запуска параллельной задачи на каждый хост
    [spawn_link(fun() -> task(Host, Cmd, Master, Timeout) end) || Host <- Hosts],
    await(length(Hosts)).

task(Host, Cmd, Master, Timeout) ->
    %% использует $USER, $HOME/.ssh/id_rsa по умолчанию
    {ok, Conn} = ssh:connect(Host, 22, {}, Timeout), %тут timeout чисто номинально
    %% SSH поддерживает мультиплексирование
    {ok, Chan} = ssh_connection:session_channel(Conn, Timeout),
    success = ssh_connection:exec(Conn, Chan, Cmd, Timeout),
    Response = read_response(Conn, Chan, <<>>),
    %% отправляем результат выполнения мастеру
    Master ! {result, Host, Response}.
    

await(0) -> ok; % все результаты получены. Выходим.
await(N) ->
    receive
        {result, Host, Response} -> % пришло сообщение от одной из задач
            io:format("Host: ~s; Response: ~p~n", [Host, Response]),
            await(N - 1); % зацикливаемся
        timeout -> % пришло сообщение от таймера
            io:format("Timeout, but ~p tasks not ready!", [N])
    end.

read_response(Conn, Chan, Acc) ->
    %% рекурсивно читаем ответ команды
    receive
        {ssh_cm, Conn, {data, Chan, _, Data}} ->
            %% цикл, собираем результат выполнения команды в аккумулятор
            read_response(Conn, Chan, <<Acc/binary, Data/binary>>);
        {ssh_cm, Conn, {closed, Chan}} ->
            %% Команда отработала. Разрываем рекурсию.
            Acc
    end.

Экономия строчек на SSH-ключи, но больше места занимает вычитывание ответов.
Да, если серверов очень много, то по CPU намного дешевле один раз открыть соединения и посылать команды на исполнение. Как ни странно, GoSSHa в 500 строк на Go позволяет это делать :). Нет возможности проверить на 10 000 серверов, но на 500 серверах latency тоже получается в районе 0,5 сек на команду.
Ну а что, conn.NewSession() на каждую команду вроде ничего сложного. Но это не так часто нужно. Обычно нужно подключиться и выполнить одну-две команды.
Но в докладе не об этом. Там именно распределённая сеть какая то используется в стиле «клиентский ПК подключается к 50 аггрегаторам, каждый из которых подключается к другим 50 аггрегаторам, каждый из которых подключен к N конечных серверов». И при этом ответы выдаются не как есть а тоже аггрегируются, мерджатся и т.п. Деталей сейчас уже не помню.
Sign up to leave a comment.

Articles