Опыт использования Fabric для удаленного управления серверами

Представим себе ситуацию, когда при тестировании или администрировании нужно выполнить однотипные действия на нескольких удаленных серверах. Можно использовать для этого shell команду вида:

for hostDN in host1 host2 host3; do ssh "root@$hostDN" 'ls -l /home'; done

Но это не самое удачное решение хотя бы потому, что выполнение команды для разных серверов происходит последовательно. Для асинхронного выполнения можно использовать команду pee, но это тоже не совсем красиво. Я решил попробовать для этих целей Fabric (fabfile.org).

В этой статье я расскажу про возможности Fabric и свой опыт использования этого инструмента.

Основные преимущества:

  • Простая классификация хостов и управление хостами в заданиях
  • Большинство заданий можно вызвать изменив переменную в командной строке
  • Ускорение выполнения заданий и небольшой отчет после выполнения
  • Масштабируемость и простота поддержки

Установка

Для работы Fabric не требует какого-либо установленного приложения на подконтрольных серверах, нужен только запущенный SSH. На системе, которая будет управляющей, рекомендуется установить Fabric с помощью pip (Cross-platform Python package management system) или easy_install. Вы также можете использовать ActivePython’s package manager PyPM под Windows. Информация о зависимостях и шагах установки тут: official page

При установке на RedHat 6.4 сначала нужно удалить старую версию библиотеки PyCrypto:

$ yum remove pycrypto

Только после этого получится установить Fabric с помощью pip, который ставит свежие версии python-crypto и python-paramiko. Со старой версией библиотеки установочный файл fab валится с ошибкой.

Первое знакомство

После установки не нужно дополнительное конфигурирование и сразу можно отсылать задания подконтрольным серверам.

Сервера указываются с помощью аргумента -H/—host, если логин или порт не дефолтные, то можно указать их явно:

$ fab -H host1,root@host2:555,host3 -- ls -l /home

Пароль можно указать с помощью параметра -p/—password , но будьте готовы к тому, что он попадет в историю shell.

По умолчанию задания выполняются последовательно, если вы хотите изменить это поведение, то воспользуйтесь ключом -P/—parallel. Однако все задания выполнять параллельно не получится, для этого нужна библиотека для многопоточности. К счастью, она включена в стандартную установку Python версии 2.6 и старше.

Помощь по программе можно получить с помощью ключа -h.

Далее мы рассмотрим возможности использования Fabric в скриптах.

Модульный файл (module file) для Fabric

При запуске можно указать модуль с помощью ключа -f, к примеру -f my.py. Но это пригодится только в случае совсем простых заданий, а для более сложных есть другая возможность. По умолчанию Fabric ищет в текущей директории или уровнем выше файл с названием fabfile.py и именно его надо использовать для навороченных задач. В этих терминах задача — это функция Python, которую можно вызвать по имени. К примеру, если есть 2 функции ы файле по умолчанию: host_core and host_secondary. Вызвать их можно так:

$ fab host_core host_secondary

Запоминать все функции не требуется, есть ключ —list:

$ fab --list

У каждой папки (придумайте для нее говорящее имя) свой fabfile, это можно использовать для структурированного хранения скриптов.

Для специфических заданий в файле модуля понядобятся некоторые предопределенные функции (файл fabric.api). Импортировать их надо так:

from fabric.api import settings, run, env

или все скопом:

from fabric.api import *

Полный список API вызовов /usr/lib/python2.6/site-packages/fabric/api.py

Работа с переменными окружения

Fabric поддерживает обработку более 50 переменных окружения, полный список тут http://docs.fabfile.org/en/1.9/usage/env.html. Некоторые из них заданы, остальные пользователь может определить сам, если это потребуется. Переменная окружения может быть определена или переопределена в командной строке, в fabfile или файле .fabricrc.

У разных способов определения разный приоритет и может зависеть от самой переменной. Например, пароль, задаваемый в командной строке, имеет приоритет выше, чем пароль в fabricrc (который считывается первым) и в fabfile (его перекрывает fabricrc). Это обычное поведение. Но список подконтрольных хостов обрабатывается наоборот. В окружении скрипта переменные могут быть глобальными и локальными в каком-то блоке. К примеру, переменные user / password позволяют сформировать учетную запись для доступа на сервер:

$ vim ~/.fabricrc
user = 'root'
password = 'P@ssw0rd'

В fabfile можно определить переменную окружения двумя способами. Если нужна глобальная переменная, то используется env.[parameter]:

$ vim fabfile
env.user = 'root'
env.password = 'P@ssw0rd)'
env.parallel = 'True'
env.cwd = '/spare/user'
env.warn_only = 'True'

Если переменная окружения нужна временно (для одиночного задания), то пишем так:

def task(…): with settings(warn_only=True): some code

или используем декоратор:

@with_settings(warn_only=True)

Пользовательские параметры

Пользователь может задать свои собственные параметры командной строки.

def hello(name=world): print(«Hello %s!» % name)

$ fab hello
Hello world!

Можно переопределять значения:

$ fab hello:name=me
Hello me!

Если есть несколько аргументов, то они перечисляются через запятую. В этом случае задаем так: name=me. Если нужно задать значение для конкретной функции: hello:name=me_again. Можно комбинировать:

$ fab hello hello:me
Hello world!
Hello me!

Подконтрольные сервера

Если не задан хост для задания, то оно будет выполнено один раз для текущего хоста. Основная задача программы — распараллеливание задач на хостах, поэтому задать эти самые хосты можно несколькими способами. Один из них — глобальное определение, с помощью ключа -H для команды fab.

Список всех хостов можно задать в переменной окружения env.hosts:

$ vim fabfile.py
env.hosts = ['host1', 'root@host2:555', 'host3']
def task_hostname():
    run('hostname -f')
def status():
    run('uptime')
    run('cat /proc/loadavg')
    run('free -m')
    run('df -h')

После запуска «fab task_hostname status» все команды будут вызваны в указанном порядке на трех хостах.

Из-за того, что параметр командной строки, задающий хосты, читается раньше fabfile глобальные переменные окружения в fabfile перегружают (override) их. Если нужно добавить хосты из командной строки, нужно использовать env.hosts.extend вместо env.hosts. В этом случае задания будут выполнены и на хостах, указанных в командной строке.
Исключить хосты можно с помощью ключа —exclude-hosts/-x

$ fab task_hostname status -x host1

Если вам нужно определить список хостов для конкретного задания, то нужно использовать декоратор Python-а:

@hosts(‘host1’, ‘root@host2:555’)

или:

test_hosts=(‘host1’, ‘root@host2:555’)
@hosts(test_hosts)
или

def test() env.hosts = [‘host1’, ‘root@host2:555’]

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

Fabric позволяет сгруппировать хосты по ролям:

env.roledefs = {
‘be’ : [‘host1’],
‘fe’ : [‘host2’, ‘host3’],
‘db’ : [‘host4’, ‘host5’]
}

После задания ролей мы можем использовать их в декораторах:

@roles(‘be’)
def be():

@roles(‘fe’)
def check_status():

Декоратор @parallel позволяет выполнять задания на нескольких хостах одновременно.

@parallel
@roles(‘fe’)
def clear_cache():

Теперь после выполнения команды:

$ fab clear_cache

Кеш будет очищен на всех фронт-эндах. Если количество хостов больше, то могут быть тормоза в работе. Для таких случаев пригодится ключ pool_size

@parallel(pool_size=5)

или -z в командной строке.

Декоратор @serial мы используем в случае, когда нужно выполнить задания последовательно. Он игнорирует параметры командной строки и значение env.parallel.

Часто используемые команды

  • get — скачивание файла с удаленного хоста
  • put — закачивание файла на хост
  • run — выполнение команды от лица текущего пользователя
  • sudo — выполнение команды от лица суперпользователя
  • local — выполнение команды на локальном хосте
  • open_shell — запуск полностью интерактивной оболоски shell на удаленном хосте
  • warn and puts — вывод сообщений
  • prompt – выводит текст и запрашивает ввод значения. Вводимое значение можно хранить в локальной или глобальной переменной. Есть возможность проверки по регулярному выражению.

Альтернативы

Puppet
CFEngine
Chef


You can leave a response, or trackback from your own site.

Leave a Reply