понедельник, 11 мая 2009 г.

Настройка окружения и развертка. Часть вторая — Fabric

В первой части, был описан процесс создания виртуального окружения для нашего django-проекта. В этой части я хотел бы рассмотреть Fabric (http://www.nongnu.org/fab/) — программу для удаленного деплоймента.
Для того, чтобы начать нам нужен сам Fabric, установим его скачав с сайта (http://ftp.twaren.net/Unix/NonGNU/fab/), либо воспользуемся easy_install


sudo easy_install fabric

Если все прошло хорошо, можно продолжать.

Наш первый fabfile


Fabric — это утилита, которая логинится на удаленные сервера по ssh, умеет скачивать и загружать файлы. Работа с ней состоит из двух частей. Первая часть — сама программа fab. Вторая — fabfile, который говорит Fabric о том, что мы хотим сделать.

Создадим наш первый fabfile, который выведет в консоль, знакомую всему миру приветственную фразу:
# ./fabfile
def hello():
""" Print hello world to localhost. """
local('echo "Hello world!"')

Мы только что описали функцию hello. Функции fabfile — это команды. Т.е. мы создали команду hello для Fabric. Запустим ее:
$ fab hello
Fabric v. 0.1.1.
Running hello...
[localhost] run: echo "Hello world!"
Hello world!
Done.

Все прошло отлично. Теперь поподробнее. Как я уже сказал, функции внутри fabfile это команды. Запуск команд производится как:

fab <имя_команды>

Функция local — используемая внутри нашей команды hello, запускает переданный ей аргумент на локальной системе. Т.е. практически это аналог os.system().

Справка о командах


Если мы введем команду fab list — мы увидим список всех доступных команд для fabfile в текущей директории. Если введем fab help:hello — увидим справку по команде hello. Все очень просто. Можете посмотреть вывод fab help и сориентируетесь сами.

Подключаемся


Теперь продолжим, и попробуем заставить Fabric выполнить команду на удаленном сервере. Пусть это будет тот же вывод приветственного сообщения.
Изменяем наш fabfile до такого состояния:
config.fab_hosts = ['127.0.0.1']

def hello():
""" Print hello world! """
local('echo "Hello world!"')

def hello_remote():
""" Print Hello world! on remote system. """
run('echo "Hello world! from $(fab_host) to $(fab_user)"')

Запускаем:
$ fab hello_remote
Fabric v. 0.1.1.
Running hello_remote...
Logging into the following hosts as n0uk:
127.0.0.1
Password for n0uk@127.0.0.1:
[127.0.0.1] run: echo "Hello world! from 127.0.0.1 to n0uk"
[127.0.0.1] out: Hello world! from 127.0.0.1 to n0uk
Done.

Краткое описание примера:

  • config.fab_hosts — список удаленных хостов, на которых нам нужно выполнить команду.

  • hello_remote — наша новая команда, выводит приветственное сообщение на удаленном сервере.

  • run — функция, запускающая команду на удаленном сервере (почти как local)

  • $(fab_host) и $(fab_user) — переменные Fabric. Вместо них соответственно будут выведены config.fab_host, и config.fab_user. В config мы можем определять также свои переменные. Альтернативный синтаксис для вывода переменных — это %(variable_name)s.


После запуска Fabric входит по SSH на удаленные сервера перечисленные в config.fab_hosts, и просит ввести Ваш пароль. После входа, выполняет необходимые нам команды. По умолчанию вход по SSH производится под логином текущего пользователя, чтобы изменить это поведение, необходимо определить перменную config.fab_user.

Кроме local, run есть еще команды put, sudo, и другие, полный список которых можно найти в документации к Fabric. Команда put — выполняет загрузку файлов на удаленный хост. Синтаксис put(source_filename, target_filename).

Практически у всех функций есть дополнительный ключевой аргумент fail. Он может быть равен одному из 'abort', 'ignore', 'warn', и говорит Fabric о том, что необходимо сделать, если выполнение команды завершилось неудачно.

Двигаемся дальше


Попробуем себе представить, что у нас есть два сервера. На первый разработчики выкладывают разрабатываемую версию продукта/приложения. А на втором крутится стабильная версия, так называемый production. Было бы неплохо используя Fabric, заставить его выполнять одни и те-же команды, на разных хостах, но не на всех сразу, а выборочно. Посмотрим как это реализуется, приводим наш fabfile к следующему виду ('localhost' — наш development сервер, а 'production' — соответственно рабочий):
def dev():
config.fab_hosts = ['localhost']

def production():
config.fab_hosts = ['production']

def deploy():
'Deploy the app to the target environment'
require('fab_hosts', provided_by = [dev, production])
run('echo "Deploy project on $(fab_host)"')
# make deployment

Обратите внимание, что теперь config.fab_hosts мы определяем не в глобальном пространстве, а его устанавливают команды dev и production. Это и есть основная идея того, что мы делаем. Т.е. теперь при запуске последовательно двух команд dev и deploy, мы запустим команду deploy на development сервере. Проверим это:
$ fab deploy
Fabric v. 0.1.1.
Running deploy...
The 'deploy' command requires a 'fab_hosts' variable.
Get the variable by running one of these commands:
dev
production
$ fab dev deploy
Fabric v. 0.1.1.
Running dev...
Running deploy...
Logging into the following hosts as n0uk:
localhost
Password for n0uk@localhost:
[localhost] run: echo "Deploy project on localhost"
[localhost] out: Deploy project on localhost
Done.
$ fab production deploy
Fabric v. 0.1.1.
Running production...
Running deploy...
Logging into the following hosts as n0uk:
production
Password for n0uk@production:
[127.0.0.2] run: echo "Deploy project on production"
[127.0.0.2] out: Deploy project on production
Done.

Как видите, выполняя сразу по две команды, мы можем "выбирать" на каком сервере выполнить необходимую команду. Обратили внимание на вывод программы при запуске без указания сервера для развертки? Самая первая. Так вот, в ней Fabric нам любезно указал, что переменная config.fab_hosts не определена, а очень нужна, и определяется в командах dev или production. Это поведение — результат работы функции require. В которой мы затребовали config.fab_hosts и сказали, где его искать.

Еще глубже


Как видим, Fabric — очень гибкий, и развивающийся инструмент. Использовать при развертке его можно как с самописными .sh скриптами, можно совместно с Maven, или чем-нибудь вроде Make. Вот тут находится похожий текст на английском — http://www.nongnu.org/fab/user_guide.html, а здесь — http://www.nongnu.org/fab/api.html, описание API.

Удачного деплоймента.

Комментариев нет:

Отправить комментарий