Веб-разработка

индекс
236,88

Capistrano: удалённое развёртывание приложений

В этой статье описывается пример использования инструмента Capistrano для удалённого развёртывания приложений. В качестве примера берётся приложение на PHP.

Capistrano — это инструмент, который может выполнять задачи на удалённой машине через ssh-доступ. Он разработан на языке руби и широко применяется для публикации приложений Ruby on Rails, Однако его легко можно использовать вместе с другими языками программирования, например, PHP.

Для более детального ознакомления и практического использования следует прочитать дополнительную документацию и попрактиковаться. Я же хочу просто продемонстрировать возможности капистрано.

Что нужно:


1. наличие ssh-доступа к хостингу, на который будет публиковаться приложение;
2. проект в какой-либо системе контроля версий; по умолчанию subversion;
3. локальная машина разработчика (т.е. с которой осуществляется удалённая публикация) должна работать под управлением Linux, Mac OS или BSD, Windows не подойдёт.

Что у нас есть


Приложение на PHP со структурой
myproject/
** lib/
** config/
** public/
**** index.php

Адрес в репозитории
svn://svnhost/trunk/myproject/
Пользователь репозитория: mysvnuser

Хостинг
1. хост: web1234
2. пользователь: myuser
3. директория проекта на хостинге: /home/myuser/myproject
4. корневая веб-директория сайта: /home/myuser/myproject/public_html

Подготовка



Для начала установим необходимый инструмент.

На локальной машине устанавливаем (для убунту):
1. руби: sudo apt-get install ruby rubygems
2. капистрано: sudo gem install capistrano,
3. клиент svn: sudo apt-get install subversion

Если я что забыл, то смотрите здесь.

На удалённом сервере создаём директорию /home/myuser/myproject/deploy, куда будет извлекаться из репозитория проект.

Поехали



Всё делаем на локальной машине.

Переходим в директорию с проектом
$ cd /var/www/myproject
$ ll
drwxr-xr-x 2 alex alex 4096 2009-01-14 20:56 config
drwxr-xr-x 2 alex alex 4096 2009-01-14 20:56 lib
drwxr-xr-x 2 alex alex 4096 2009-01-14 20:56 public


Запускаем команду «capify .»
$ capify .
[add] writing `./Capfile'
[add] writing `./config/deploy.rb'
[done] capified!


Команда capify создала 2 файла:
1. Capify, который необходим капистрано; его минимальная задача — загрузить config/deploy.rb;
2. config/deploy.rb — скрипт на руби, который хранит инструкции и настройки капистрано.

Файл Capify мы не трогаем, все изменения делаем в deploy.rb. Скопируйте приведённый ниже код в config/deploy.rb и измените его под свои нужды.

# Имя приложения
set :application, "myproject"
# Вызов функции set создаст переменную application и присвоит ей значение "myproject"

# В проекте мы используем только один сервер, выполняющий роль веб-сервиса.
role :web, "web1234" # хост удалённого сервера
set :user, 'myuser' # пользователь удалённого сервера
set :use_sudo, false # не запускать команды под sudo

# Директория приложения на удалённом хостинге
set :app_dir, "/home/#{user}/#{application}/" # /home/myuser/myproject/
# Запись "/home/#{user}/#{application}/" аналогична "/home/$user/$application/" в PHP

# Директория, куда будет делаться checkout из репозитория
set :deploy_to, "#{app_dir}/deploy" # /home/myuser/myproject/deploy

# Настройки репозитория
set :scm, :subversion # используем subversion
set :scm_user, 'mysvnuser' # имя пользователя репозитория
set :scm_url, "svn://svnhost/trunk/#{application}" # svn://svnhost/trunk/myproject/
# Формируем команду svn checkout --username mysvnuser svn://host/trunk/myproject
set :repository, Proc.new { "--username #{scm_user} #{scm_url}"}

task :after_symlink, :roles => :web do
run "ln -nfs #{release_path}/public #{app_dir}/public_html"
end


На локальной машине выполняем команду
$ cap deploy:setup

Капистрано соединяемся по ssh с сервером web1234, фактически ssh myuser@web1234:22, и создаёт необходимые ему директории в /home/myuser/myproject/deploy:
** releases,
** shared

Выполняем команду
$ cap deploy:update
Капистрано выполняет следующие команды на удалённом сервере:
1. создаёт новую директорию в /home/myuser/myproject/deploy/releases, например, releases/20090114102030
2. делает svn checkout svn://svnhost/trunk/myproject/ в эту директорию
3. создаёт симлинк /home/myuser/myproject/deploy/current на /home/myuser/myproject/deploy/releases/20090114102030
4. создаёт симлинк /home/myuser/myproject/public_html на /home/myuser/myproject/deploy/releases/20090114102030/public

Пункт 4 реализован в строках
task :after_symlink, :roles => :web do
run "ln -nfs #{release_path}/public #{app_dir}/public_html"
end

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

Измените немного код приложения (например, в index.php), закоммитьте изменения и повторите команду
$ cap deploy:update
Капистрано создаст новую директорию releases/20090114203040и сделает в неё svn checkout из репозитория. Потом установит симлинк deploy/current на deploy/releases/20090114203040/, а publick_html на deploy/releases/20090114203040/public.

У вас уже будет такая структура директорий:
deploy/
** releases
**** 20090114102030
******** lib/
******** config/
******** public/
************ index.php
**** 20090114203040
******** lib/
******** config/
******** public/
************ index.php
** current -> releases/20090114203040
** shared
public_html -> deploy/releases/20090114203040/public

Следует заметить, что задачу deploy:update капистрано выполняет в транзакции.

Этот тот минимум, который нужен для удалённой публикации приложения. В этом примере не надо перезапускать веб-сервер (или несколько серверов), делать изменения в базе данных и т.п. Для реальных проектов вам придётся самостоятельно изучить капистрано.
+19
14 января 2009, 22:49
59

комментарии (22)

0
sotakone #
Да вы что, Хаксор-стайл инсталлер на PHP гораздо круче.
0
sherbacov #
Хаксор-стайл инсталлер для конечного пользователя. Capistrano больше для разработчика все еще разрабатываемого проекта. Жалко что для Windows нету. Посоветуйте аналоги для Windows под Subversion…
+1
develop7 #
мм… ровным счётом ничего не мешает запускать это хозяйство из-под виндов. по крайней мере, гемы у меня на ура ставились. вы только пути к нужным утилками (кажется, это будут ssh и svn) в %PATH% сложите — и жизнь снова будет прекрасна и удивительна :)
0
micktu #
Если Вам нужен сервер, то VisualSVN — хорошая обертка.
+2
develop7 #
А <irony> вырезал хабрапарсер.
0
bubuh #
Может кому-то и важна красивая картинка во время публикации проекта, но здесь как минимум достаточно гибкий и контролируемый подход к публикации, который легко можно откатить. Уверен, что возможностей намного больше чем в этом примере и скорее всего уже отработанные сценарии правильной публикации. Особенно ценны такие решения на значимых проектах.
Спасибо за пример. Всё время не хватало посмотреть, что за капистрано, но теперь есть смысл в этом покапаться ;)
0
preprocessor #
никакой связи между ними вообще нет. вы бы попытались вникнуть в суть.
0
preprocessor #
кажется вы все же так пошутили. ближе к народу шутить надо.
0
alex_anokhin #
Единственный неудобный момент для Php-разработчика из примера — необходимость «отвлекаться» на Ruby в сценариях сборки ;)… Наверное поэтому начали появляться подобные порты. Мы (совсем-совсем давно) подобный капистрано функционал реализовали целиком на Pake (облегченный порт Rake — рекомендую). А в целом, действительно, очень удобный подход к реализации развертывания вне зависимости от языка.
–13
skylix #
> разработан на языке руби
руби, коли, воруй, убивай
–6
skylix #
предсказуемо :)
привет кармадрочерам, сладенькие.
я указал на то, что надо написать по-английски, а то фигня выходит.
–2
skylix #
FUCK YEAH!
0
wpm1 #
А там и учить то нечего. Он простой как пять копеек, смущает отсутствие хорошей документации. Мы его используем чтобы деплоить Django приложения и Ror приложение
0
geshido #
Подскажите, как в Capistrano собирать STDOUT вызванной на хосте утилиты?

Делая так, собирается вывод со всех хостов, а надо разделить по разным:

def collect_output(cmd)
  buf = ''
  run cmd do |ch, stream, o|
    buf += o
  end
  buf
end

task :date_on_servers do
  msg = collect_output "date"
  puts msg
end
0
geshido #
Сам разобрался, надо же :)

def collect_output(cmd)
  buf = {}
  run cmd do |ch, stream, o|
    buf[ch.properties[:host]] ||= ''
    buf[ch.properties[:host]] += o
  end
  buf
end
+1
micktu #
Давно собирался использовать эту штуку для деплоймента Django-проектов. Как ни парадоксально, пора учить руби (:
0
afi #
Мне показалось более удобным использовать phing (смотреть здесь) для подобных целей.
+1
BlackTheMad #
Поддерживаю. Работаю со связкой Phing + rsync и радуюсь жизни =)
Phing отлично умеет вытащить код из subversion, почистить код от всяких девелоперских файлов заминифаить (новояз =) *.js и записать всё в лог. А дальше начинается работа rsync.
Единственная проблема с накатом БД. Пока приходится изворачиваться самописными скриптами. Т.к. славный DB Deploy нельзя поселить на shared-хостинге =/
0
lexxscorp #
Phing может выполнять операции на удалённом сервере?
+1
afi #
Тут немного не так. Задача стоит в написании скрипта (причем на любом языке, установленном у вас), который будет выполняться на локальной машине, запуская сценарий phing находящийся на удаленном сервере. Сложностей никаких. 10 строк кода на php, к примеру
0
lexxscorp #
Спасибо.
0
z0r1k #
а все эти системы деплоя умеют брать разницу из системы контроля версий?
вот например не все checkout-ить, а взять только измененные файлы между ревизией 123 и 130?

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