Capistrano и php

image Всем привет. Сегодня я хотел бы ещё раз поговорить о замечательном deploy-ере Capistrano.

Напомню, что Capistrano — это Open Source-ный инструмент для выполнения скриптов на нескольких серверах, который в основном используется для web приложений. Он позволяет автоматизировать процесс развертывания новой версии на одном или нескольких web серверах и включает поддержку таких задач, как например изменение базы данных.

Capistrano написан на Ruby и является «модулем» (или компонентном, не знаю как лучше) фреймворка Ruby on Rails.

Данный топик по большей части является переводом туториала со страницы проекта на github-е с некоторыми дополнениями, изменениями и сокращениями специфичными для php (или для «не RoR»). Здесь не будут рассматриваться вопросы работы с несколькими серверами и базой данных, это всего лишь небольшое пособие для начинающих.

Итак, допустим на нашем локальном компьютере в паке /path/deploy/from находится приложение написанное на языке php. У этого приложения есть git репозиторий находящийся по адресу example.net/project.git с актуальным кодом. Также у нас есть хостинг по адресу example.com с ssh доступом и папкой /path/deploy/to куда мы собираемся залить наши файлы. Мы не хотим постоянно возиться с ftp клиентом и решили потратить несколько часов для того, чтобы разобраться в деплойере capistrano. Давайте приступим.

Установка


Начнем с установки. открываем консоль и вводим:

    $ sudo apt-get install ruby rubygems
    $ sudo gem install capistrano

Поскольку в RoR файлы конфигурации находятся в папке config, capistrano предполагает что у нас она есть. Если её нет, то необходимо её создать:

    $ mkdir /path/deploy/from/config

Если директория в которой вы создаете каталог config, также является корневой директорией сервера, то не забудьте положить в неё файл .htaccess для apache, который запретит просмотр файлов этого каталога, или в конфигурации других web серверов запретить доступ к этому каталогу.

Капификация


Первое что мы должны сделать после установки capistrano это «capify-нуть» наше приложение. «Капификация» — это процесс конфигурации capistrano для развертывания приложения. Он достаточно прост: убедитесь что вы находитесь в корневой директории вашего проекта и введите:

  $ cd /path/deploy/from
  $ capify .

Эта команда создаст два файла:

Capfile — главный файл который нужен capistrano. Подобно тому, как «make» использует «Makefile», а «rake» — «rakefile», Capistrano по умолчанию ищет и загружает «Capfile». Изначально генерируемый Capfile очень прост: все что он делает — загружает «config/deploy.rb»…

config/deploy.rb — файл в котором содержатся «настройки» приложения.
Вообще говоря нам нужно оставить Capfile в покое и вплотную заняться файлом config/deploy.rb. Изначально он будет выглядеть следующим образом:

    set :application, "set your application name here"
    set :repository,  "set your repository location here"

    set :scm, :subversion
    # Or: `accurev`, `bzr`, `vcs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`

    role :web, "your web-server here"                          # Your HTTP server, Apache/etc
    role :app, "your app-server here"                          # This may be the same as your `Web` server
    role :db,  "your primary db-server here", :primary => true # This is where Rails migrations will run
    role :db,  "your slave db-server here"

    # If you are using Passenger mod_rails uncomment this:
    # if you're still using the script/reapear helper you will need
    # these http://github.com/rails/irs_process_scripts

    # namespace :deploy do
    #   task :start do ; end
    #   task :stop do ; end
    #   task :restart, :roles => :app, :except => { :no_release => true } do
    #     run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
    #   end
    # end

Нас данный конфиг не устраивает, поэтому мы его перепишем.

Конфигурация


Для начала приложению нужно дать имя. Назовем его «my php application»:

    set :application, "my php application"

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

    set :repository, "ssh://git@example.net/project.git"

В случае, если url для доступа к репозиторию с локальной машины и с сервера различаются (например снаружи ssh имеет другой порт), нужно указать оба адреса:

    set :repository, "ssh://git@example.com:22100/project.git"
    set :local_repository, "ssh://git@example:project.git"

Поскольку мы используем систему контроля версий отличную от Subversion, которая назначена по-умолчанию, необходимо ввести следующую строку:

    set :scm, :git

Теперь нужно указать Capistrano в какую папку на сервере мы хотим развернуть проект. Чтобы понять что это значит, нужно рассмотреть структуру директорий которую использует Capistrano для развертывания приложений.

Структура директорий Capistrano


Проект успешно развернутый с Capistrano будет иметь структуру похожую на приведенную ниже ( где [deploy_to] — это каталог куда мы хотим развернуть проект):

    [deploy_to]
    [deploy_to]/releases
    [deploy_to]/releases/20080819001122
    [deploy_to]/releases/...
    [deploy_to]/shared
    [deploy_to]/shared/log
    [deploy_to]/shared/pids
    [deploy_to]/shared/system
    [deploy_to]/current -> [deploy_to]/releases/20100819001122

Каждый раз когда вы будете разворачивать проект в папке «releases» будет создаваться новая директория, в которую будет копироваться его последняя версия. После этого символическая ссылка «current» обновиться и будет указывать на новую директорию. Если структура вашего приложения похожа на структуру приложения в RoR или другого приложения, где корневая директория проекта и web директория отличаются, необходимо убедиться, что сервер настроен именно на эту директорию (в RoR это [deploy_to]/current/public).

Вернемся к конфигурации


Итак нам нужно указать куда на сервере мы хотим развернуть приложение. По умочанию это папка "/u/apps/#{application}" (где #{application} это имя которое мы указали выше в переменной ":application"). Поскольку наша директория отличается от директории по умолчанию, укажем её явно:

    set :deploy_to "/path/deploy/to"

Теперь нужно указать где находятся наши сервера. Вообще говоря Capistrano по умолчанию использует три роли для развертывания Rails приложений: web, app и db. Подробное описание этих ролей можно найти в оригинальной статье. Поскольку у нас только один сервер и функциональность ролей нам не нужна, можно использовать следующий синтаксис:

    server "example.com"

Дополнительные настройки


Теперь посмотрим на некоторые дополнительные переменные, которые могут вам пригодиться.
  • set :user, "foo"
    Указывает имя пользователя для ssh или ftp доступа, если вы подключаетесь к серверу под именем отличным от имени под которым вы залогинены на ваш локальный компьютер.
  • set :password, "password"
    Устанавливает пароль для подключения к серверу. Не рекомендуется.
  • set :scm_username, "foo"
    Указывает имя пользователя, для доступа к репозиторию, если вы подключаетесь к нему под именем отличным от имени под которым вы залогинены на локальном компьютере. Не все vcs поддерживают этот параметр. Если ваша система контроля версий не поддерживает, то необходимо указать это имя в параметре ":repository" так как это сделано выше.
  • set :use_sudo, false
    Назначено по умолчанию. Если вы хотите дать Capistrano sudo доступ для выполнения каких-либо операций, поставьте true
  • set :via, "scp"
    Устанавливает протокол, по которому будут копироваться данные.
  • set :branch, "master"
    Указывает ветку проекта из которой будет браться код.
  • set :deploy_via, :remote_cache
    Сохраняет кэш последней версии на сервере и при новом deploy-е скачивает только обновления. Наверняка вы захотите установить этот параметр.

Команды Capistrano


После того, как мы написали свой рецепт, можно задать Capistrano несколько вопросов:
  • $ cap -h
    Выведет список возможных опций.
  • $ cap -H
    Выведет список всех опций с подробным описанием каждой из них.
  • $ cap -T
    Выведет список всех task-ов (или задач) с кратким описанием каждого из них.
  • $ cap -e deploy:web_disable
    Покажет подробную информацию о конкретной задаче.

Setup


Попробуем воспользоваться капистрано для взаимодействия с сервером. Для начала нам нужно создать базовую структуру дерикторий:

    $ cap deploy:setup

При запуске этой команды капистрано подключится к серверу и выполнит серию команд «mkdir». Заранее убедитесь, что у вас все в порядке с правами доступа на директорию в которую вы разворачиваете проект.

Проверка зависимостей


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

    $ cap deploy:check

Капистрано проверит локальный и удаленный сервера на наличие необходимых вещей. Если чего-то не хватает, вы получите сообщение об ошибке, например, что у вас нет прав на какую-либо операцию, что на сервере не установлен git и т.п.

Отправка кода на сервер


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

    $ cap deploy:update

Эта команда скачивает код из репозитория на сервер и обновляет симлинк «current».

Deploy


Наконец мы подобрались непосредственно к деплою. В действительности команда deploy всего лишь обертка, над несколькими другими командами, которая просто выполняет их последовательно. Как это происходит можно посмотреть на следующей схеме:

image

Поскольку команды deploy:update и deploy:finalize_update специфичны для приложений написаных на ruby on rails, нам нужно переопределить их. Помимо этих двух команд рекомендую переопределить команды deploy:start и deploy:stop, поскольку они тоже заточены для RoR и в случае их запуска могут привести к ошибке (на самом деле есть и другие специфичные команды, но мы переопределяем только самые основные):

  namespace :deploy do
    task :start do
    end
    task :stop do
    end
    task :restart do
    end
    task :finalize_update do
    end
  end

В принципе, теперь команда deploy ничем не отличается от команды deploy:update, но вы можете изменить это, прописав специфичные для вашего приложения действия в необходимых task-ах.

Теперь деплойер готов к работе. Для тех, кому описанных возможностей не достаточно, рекомендую ознакомиться с разделом DSL Documentation на страничке wiki проекта и внимательно почитать вывод команды «cap -e» для каждого стандартного task-а. Прочитав их вы без труда сможете писать конструкции например такого вида:

  after "deploy", "deploy:cleanup"

Если добавить такую строку в рецепт, то после каждого деплоя автоматически будет выполняться чистка директории /path/deploy/to/releases (по умолчанию удаляются все релизы, кроме 5 последних).

Multistage


У себя в разработке мы также используем расширение capistrano-ext, которое позволяет делать так называемый multistage. Предположим у вас есть тестовый и рабочий сервера. Вы можете написать отдельный конфиг для каждого из них и выполнять deploy только для нужного сервера.
Для установки расширения в командной строке наберите:

    $ gem install capistrano-ext

Далее в папке /path/deploy/from/config/ создаем новый каталог:

    $ mkdir /path/deploy/from/config/deploy

и помещаем в него свои рецепты: например production.rb и staging.rb. Всё что нам нужно для конфигурации — это написать в файл /path/deploy/from/config/deploy.rb две строки:

    set :stages, %w(staging production)
    require 'capistrano/ext/multistage'

Теперь вы можете выполнять деплой с помощью команд «cap production deploy» и «cap staging deploy». Если вам нужен ещё один конфиг, просто положите его в каталог deploy и добавьте его имя в переменную :stages:

    set :stages, %w(staging production develop)

Если вы попробуете просто выполнить команду «cap deploy», capistrano предупредит, что необходимо указать рецепт по которому нужно выполнять деплой и прервет работу. Для того, чтобы использовать какой-либо рецепт по-умочанию, можно определить переменную «default_stage»:

    set :stages, %w(staging production develop)
    set :default_stage, "develop"
    require 'capistrano/ext/multistage'

Теперь команда «cap deploy» будет эквивалентна команде «cap develop deploy».

На этом всё, спасибо за внимание.

P.S.: Назвать публикацию переводом язык не повернулся, потому что здесь меньше половины туториала. Много чего взято из других статей и из личного опыта.

оригинальный туториал
статья о multistage
help.github.com/capistrano
Поделиться публикацией

Комментарии 15

    0
    спасибо, попробую
      0
      Отличная статья, в хозяйстве пригодится
        +1
        Если вы кодер на CakePHP и еще не имели дело с Capistrano, советую, прежде чем читать данный пост, ознакомится с очень кратким вступлением (англ):
        github.com/jadb/capcake/wiki/Introduction-to-Capistrano
          0
          Спасибо, а то что-то я не сразу понял о чем речь.
          0
          > и включает поддержку таких задач, как например изменение базы данных.

          что то в статье про это больше нигде не написано, а интересно с какими ьазами работает и как
            0
            Для работы с базой есть встроенные task-и «deploy:migrate» и «deploy:migrations», но они реализованы под RoR. При желании их можно переписать для своего фреймворка, если он поддерживает миграции.
            0
            А опишите трудности, с которыми вы сталкивались при использовании именно этого деплоера. Или чего вам не хватает в нём, может быть
              0
              Сначала трудно было разобраться, как заставить его работать с php. В принципе для текущих задач его возможностей предостаточно. Если в Yii в будущем появятся миграции, было бы круто сделать что-нибудь наподобии capcace, например capyii.
              0
              Как-то не разобрался по статье и ссылки capcake выше собственно откуда и куда берутся файлы для деплоя: прямо копируются с /path/deploy/from/ в /path/deploy/to? Тогда непонятно зачем вообще репозиторий нужен. Удаленно на сервере выполняется получение рабочей копии в [deploy_to]/releases/…? Зачем доступ к локальному репозиторию тогда? Если с репозиториями работа идёт, то попадут ли в [deploy_to]/releases/… файлы VCS (и можно ли как-то ограничить список файлов, попадающих в релиз, то есть чтобы в репах были, а в релизе нет). Можно ли настроить работу только с локальным репозиторием или вообще без него (прямо из рабочей копии)?

              В общем есть локальный центральный репозиторий (извне не виден), есть рабочая копия — откуда запускать все эти команды или доступ к репозиторию с сервера мастхэв?

              Сейчас работает самописный скрипт для деплоя: запускается в рабочей копии (а вообще в любом каталоге, не обязательно под VCS), ставит на сервере заглушку (убирает симлинк из эвиабле_сайтс и рестартует nginx — дефолтный выводит «Упс, обновите страницу чуть позже» на любом урле), рекурсивно копирует (rsync) на сервер всё из каталога (кроме списка exclude), запускает миграции Доктрин, запускает сайт (восстанавливает симлинк, рестартует nginx), пишет «ОК» (или ошибки если не ОК, откатов всяких непредусмотрено, только для миграций в рамках транзакции). Собственно основной алгоритм стянут почти полностью с symfony, но скрипт «костыльный», многое (адреса, явки, пароли) захардкодено для разных проектов разные скрипты.

              Capistrano сможет делать всё то же самое без изучения ruby, написания своих плагинов и т. п., в общем малой кровью, скажем полдня чтения доков и полдня экспериментов?

              ЗЫ apt-get install ruby rubygems — за это отдельное спасибо, всё как-то не мог понять как ставить приложения, как-то этот момент не поясняется в разных how-to, мудрил с исходниками и как-то неудачно, теперь, может и с redmine разберусь.
                0
                *На вопрос «Capistrano сможет делать… малой кровью ...?» достаточно простого ответа: «Да, чуть-чуть мозгов и сможет» или «Нет, без 8 лет работы с руби столь тонкую настройку не сделать»
                  +2
                  Да, сможет.
                  Логики в конфигах capistrano почти нет, там по сути только задание переменных и описание задач.
                  О режимах деплоя в капистрано по-русски хорошо написано здесь. Если используется репозиторий, служебные файлы(.git, .svn и тп) в релиз не попадут.
                    0
                    Спасибо, за ссылку отдельное, даже про nginx есть :)

                    +1
                    А нет, соврал. По умолчанию используется стратегия :checkout, которая сохраняет служебные файлы и директории. Просто на RoR это как-то не особенно важно(до .git, лежащего в корне, никак не добраться. Все запросы роутятся обычно в контроллеры и в директорию public для статики).
                    0
                    На счет доступа к репозитрию и с локального компьютера и с сервера в туториале написано: «This is the repository address for your application, and by default it must be accessible both by your local machine (where you will be deploying from) and your production servers (where you will be deploying to)». То есть по умолчанию доступ должен быть. По поводу того, когда можно ограничиться доступом только с одной машины я ни чего не нашел. Фактически капистрано подключается к серверу, куда надо залить код и делает от туда checkout из репозитория. Перед тем как это сделать, он выполняет команду «git ls-remote :repository» с локальной машины. Для чего он это делает, мне не ясно, буду рад, если кто-нибудь объяснит.
                    Чтобы не копировать определенные файлы или каталоги, можно в рецепт добавить строку вида
                    set :copy_exclude, [".git", ".gitignore"]

                    На остальные вопросы, надеюсь вы нашли ответы в предыдущих комментариях.
                      0
                      Для работы только с локальным git репозиторием использую такой конфиг
                      deploy.rb


                      set :application, "app"
                      set :repository,  "file:///home/user/www/app"
                      set :scm, :git
                      role :web, "re.mo.te.ip"  
                      set :deploy_to, "/remote/path"
                      set :user, "toor"
                      set :password, "secret"
                      set :use_sudo, false
                      set :deploy_via, :copy         #checks out everything into a temporary directory, zips it up (tgz), and copies the entire thing
                      set :copy_exclude, [".git", ".gitignore"]
                      

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

                  Самое читаемое