Вы создали отличное приложение. Вы должны получить это там. Посмотрим правде в глаза, развертывания должны быть легкими, повторяемыми, и если это не сработает, вы сможете вернуться к последнему известному исправному состоянию.
Если вы используете рабочий процесс Git вручную (доступны другие SCM) или gawd запрещают FTP, то я слышу, как вы кричите «Проповедуй!». Я был там, наблюдая за загрузкой всех этих файлов через FileZilla, перенося базу данных, перезагружая сервер (ы). Если вы когда-либо автоматизировали свои развертывания, хотя бы один раз, вы будете испорчены. Все остальное — боль.
Скорее всего, вы слышали о Capistrano . Это самоуверенный инструмент развертывания, написанный на Ruby. Capistrano предлагает пользовательские задачи с помощью элегантного DSL для быстрого развертывания вашего последнего веб-приложения.
Сегодня мы пройдемся по нескольким основам, рассмотрим возможные настройки веб-сервера и рассмотрим настройку некоторых пользовательских задач развертывания.
Мнения Материя
Помните, я говорил, что Капистрано самоуверен? Эти мнения представлены в виде нескольких предположений, которые делает Capistrano относительно вашего заявления:
- Вы будете использовать контроль источников
- У вас будет каталог «config» на верхнем уровне вашего приложения
- Вы будете использовать SSH для доступа к ящику, на котором мы развертываем
Настройка вашего сервера
Нам нужно поговорить о настройке вашего сервера. Такие сервисы, как Heroku и EngineYard, избавляют от необходимости настраивать MySQL, Apache и так далее. Тем не менее, если мы посмотрим в Интернете, то найдется множество дешевых VPS, которые точно так же удовлетворят ваши потребности. Конечно, нам потребуется выполнить некоторую начальную работу, чтобы настроить сервер, но это разовая сделка, и мы можем автоматизировать ее, немного научившись.
Мой VPS использует пользователей в качестве учетных записей хостинга. Если у меня есть приложение с именем «capdemo», у меня также будет пользователь на коробке с именем «capdemo», с домашним каталогом, выступающим в качестве части пирога хостинга.
Я также использую сервер Apache , главным образом потому, что я очень хорошо с ним знаком. NGINX — это альтернатива, которая хорошо написана. Пока я придерживаюсь Apache. Оба сервера хорошо согласуются со следующим предположением этой статьи: мы будем использовать Passenger .
Пассажир дает нам основной процесс развертывания. Там нет специальной конфигурации сервера или управления портами. Новая версия — это всего лишь случай загрузки файлов и перезапуска сервера приложений (Mongrel, Unicorn и т. Д.).
Просто короткая заметка о перезапуске этих серверов. Пассажир ищет файл с именем tmp/restart.txt
в tmp/restart.txt
вашего приложения, чтобы сообщить ему, когда нужно перезапустить сервер приложений. Ручной перезапуск будет touch tmp/restart.txt
.
Готовим с Капистрано
В эти дни я очень голоден, разговаривая с девопами. Когда я создаю сценарий Capistrano, я разрабатываю рецепт, рассказывающий Capistrano, как бы я подготовил свое веб-приложение (может быть, довольно редко). Там нет брызг в дополнительной Sriracha для тепла. Рецепт сопровождается письмом. Если он не может завершить развертывание, Capistrano сообщит вам и уберет посуду.
Capistrano прекрасно работает с приложениями Rails, но может использоваться практически с любым приложением. Приложение даже не должно быть на основе Ruby. В этом случае, однако, мы будем использовать приложение Rails, чтобы получить готовку.
Как обычно, добавьте gem capistrano
в ваш Gemfile и запустите пакетную bundle install
. Теперь мы можем «записать» наш проект, запустив capify .
, Это создает Capfile и сценарий развертывания в каталоге config нашего приложения.
Он находится в файле config/deploy.rb
где мы создадим наш рецепт развертывания. Глядя на файл deploy.rb
, мы видим, что Capistrano был достаточно хорош, чтобы начать нас.
set :application, "set your application name here" set :repository, "set your repository location here" set :scm, :subversion # Or: `accurev`, `bzr`, `cvs`, `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're still using the script/reaper helper you will need # these http://github.com/rails/irs_process_scripts # If you are using Passenger mod_rails uncomment this: # 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
Ваш сгенерированный файл deploy.rb
должен выглядеть так, как указано выше (на момент написания последней стабильной версии Capustrano было 2.9.0). Это дает нам некоторое преимущество для нашего рецепта.
Итак, давайте изменим это на что-то более домашнее. Во-первых, нам нужно настроить некоторую конфигурацию SSH, информацию о приложении, сведения о том, где оно должно быть развернуто, и некоторые сведения о SCM.
ssh_options[:forward_agent] = true require 'json' set :user_details, JSON.parse(IO.read('dna.json')) set :domain, "capdemo.bangline.co.uk" set :application, domain set :user, user_details['name'] set :password, user_details['password'] set :deploy_to, "/home/#{user}" set :use_sudo, false set :repository, "[email protected]:bangline/capdemo.git" set :scm, :git set :branch, "master" set :deploy_via, :remote_cache role :app, domain role :web, domain role :db, domain, :primary => true # If you are using Passenger mod_rails uncomment this: # 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
ssh_options[:forward_agent]
гарантирует, что мы используем ключи на нашей локальной машине, а не на сервере. Я использую это, так как обычно не помещаю ключи на сервер для доступа к GitHub, но это вполне возможно (удалите эту строку, если вы это делаете).
Затем я анализирую файл с именем dna.json
для учетных данных пользователя. Я не только могу опустить этот чувствительный файл из публичного репозитория git, но и сделать его более пригодным для повторного использования. Например, мы могли бы также настроить все детали SCM в файле днк. Содержимое файла dna.json выглядит следующим образом:
{ "name":"chuck_norris", "password":"dont_need_one_as_the_server_knows_and_fears_me" }
Следующие несколько строк объясняют себя довольно хорошо. Мы устанавливаем имя приложения, учетные данные пользователя на сервере, нашу конфигурацию git и, наконец, место, где должно быть развернуто приложение.
Я должен отметить, что я не использую ключи для доступа по SSH. Если пароль пользователя установлен, Capistrano будет использовать его на протяжении всего развертывания. Это нормально для этого сценария, но если бы мы развертывали на нескольких серверах, Capistrano предполагал, что пароль был одинаковым для всех серверов. Другими словами, для развертывания на нескольких серверах используйте ключи SSH. Это не самый безопасный метод, но довольно гибкий. Просто убедитесь, что ваш пароль выглядит так, будто кошка вздремнула на клавиатуре.
Я также установил :deploy_via
в :remote_cache
. Это создает git-репо на самом сервере, предотвращая полное клонирование приложения при каждом развертывании.
Определения role
описывают уровни нашего приложения. Уровень :app
— это то, к чему мы больше всего привыкли при разработке, уровень :web
— это то, куда отправляются все запросы, и :db
— то, куда мы хотим запускать миграции. Этот стиль конфигурации может выглядеть глупо, так как мы используем только один блок (ключевое слово server
решает эту проблему), но если нам когда-либо понадобится масштабировать и разделять базу данных и т. Д., Этот стиль более удобен в обслуживании.
На этом этапе можно сделать пару проверок. Если вы запустите команду cap -T
в своем терминале, вы увидите, о каких задачах Capistrano уже знает. В настоящее время мы хотим настроить каталог приложений и проверить правильность разрешений.
cap deploy:setup cap deploy:check
Макет Капистрано
Прежде чем идти дальше, мы можем изучить, какой макет ожидать на нашем сервере. Если мы подключим SSH к коробке и проверим путь к приложению, то увидим:
- текущий
- релизы
- общий
Текущий просто символическая ссылка на последние в папке релизов. Имея эту константу, мы можем установить наш конфигурационный файл apache vhost на следующий
<VirtualHost *:80> # Admin email, Server Name (domain name) and any aliases ServerName capdemo.bangline.co.uk # Index file and Document Root (where the public files are located) DocumentRoot /home/capdemo/current/public <Directory /home/capdemo/current/public> Options -MultiViews AllowOverride All </Directory> </VirtualHost>
Каталог релизов содержит все выпуски, которые мы делаем с помощью Capistrano. Текущая символическая ссылка указывает на последний каталог здесь. Каталог выпусков будет содержать все предыдущие выпуски. Мы можем ограничить количество выпусков в нашем рецепте развертывания с помощью set :keep_releases, 5
или использовать set :keep_releases, 5
cap deploy:cleanup
.
Общий каталог сохраняется во всех развертываниях, поэтому поместите в этот каталог такие элементы, как загруженные пользователем ресурсы или базы данных sqlite.
Написание рецепта
Пока что все, что мы сделали, — это проверили все на месте для нашего первого развертывания. Вывод cap deploy:check
должен был сказать нам, что все выглядит хорошо. Если нет, вам, вероятно, придется проверить правильность прав доступа пользователя. Помните, я говорил вам очистить файл deploy.rb
? Что ж, правда в том, что использовать Capistrano с Passenger так просто, это почти ожидаемо. Мы оставили закомментированный код в deploy.rb
и он нам нужен сейчас.
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
Это первые задачи по развертыванию, которые мы добавляем. Мы перезаписываем tasks to be specific for our setup. The
умолчанию ,
останавливаем and
перезапускаем, tasks to be specific for our setup. The
tasks to be specific for our setup. The
перезапуска task can be called using
cap deploy: restart, and you can see it touches the
файла tmp / restart.txt`. Что более важно, так это определение задачи.
У нас есть пространство имен, deploy
и некоторые подзадачи. Когда мы вызываем cap deploy:restart
единственная выполняемая задача — это restart
. Вызов cap deploy
в терминале запустит все задачи, которые мы видим в пространстве имен, и несколько других, которые мы не видим. Под капотом задача cap deploy
имеет набор сохраненных / стандартных задач. Детали которого были хорошо проиллюстрированы здесь . Биты, которые нас интересуют, в порядке их вызова:
- deploy: update_code — извлекает код из репозитория git.
- deploy: symlink — связывает самый последний выпуск с текущим
- deploy: restart — мы переопределили это, чтобы просто коснуться файла restart.txt
Еще одно соображение — мы разрабатываем приложение на Rails 3.1. Мы хотим использовать bundler для управления нашими гем-зависимостями (зачем нам что-то еще?) К счастью, bundler имеет задачу развертывания для capistrano.
require "bundler/capistrano"
Простое добавление этой строки в наш deploy.rb
все наши драгоценные камни при развертывании. Это также делает эту задачу умным способом. Все драгоценные камни упакованы в каталог shared/bundle
. Это современный день, эквивалентный заморозке наших драгоценных камней. С этим на месте мы почти готовы к развертыванию.
Так как это будет наше первое развертывание, нам нужно выполнить пару дополнительных задач из командной строки. Во-первых, нам нужно перенести базу данных. Не нарушая авторских прав «Для этого есть задача». Итак, давайте получим некоторый код на сервере, используя cap deploy:update_code
затем запустите cap deploy:migrate
. На данный момент у нас есть код на сервере, база данных с самой последней схемой и наши зависимости гемов были выполнены.
Бросать в дополнительные ингредиенты
Как я упоминал ранее, мы будем развертывать приложение Rails 3.1. Наряду с конвейером активов появилась возможность предварительной компиляции наших активов. Это дает нам идеальное оправдание для создания нашей собственной задачи развертывания.
namespace :assets do task :compile, :roles => :web, :except => { :no_release => true } do run "cd #{current_path}; rm -rf public/assets/*" run "cd #{current_path}; bundle exec rake assets:precompile RAILS_ENV=production" end end before "deploy:restart", "assets:compile"
Эта задача просто удаляет все существующие ресурсы и запускает команду rake для их компиляции. Более интересная часть — крючок, который я поместил внизу. Вы, наверное, знаете, что он делает уже благодаря красноречивому DSL Capistrano, но в основном он подключается к задаче deploy
и запускает наши assets:compile
задача assets:compile
перед перезапуском сервера приложений. Кроме того, разделив его на собственное пространство имен, мы можем запустить его из командной строки в ресурсах изолированного cap assets:compile
.
Есть еще одна вещь, которую мы должны сделать перед развертыванием. Помните, когда мы говорили о том, что общий каталог является хорошим местом для хранения баз данных sqlite? Хорошо, текущая конфигурация в нашем файле database.yml
все еще использует db/production.sqlite3
. /home/capdemo/shared/production.sqlite3
исправить это — изменить /home/capdemo/shared/production.sqlite3
. Мы фиксируем это в нашем cap deploy:update_code
GitHub и запускаем cap deploy:update_code
и cap deploy:migrate
. Теперь, когда у нас есть база данных, сохраняемая во всех наших развертываниях, мы можем фактически развернуть приложение, просто:
cap deploy
Если вы проследите за выводом развертывания, вы увидите, что задача компиляции выполняется перед задачей перезапуска. По общему признанию, вывод действительно выглядит неправильно, но если вы потратите немного времени на его чтение, вы увидите, что он делает то, что мы ожидаем.
* executing `deploy:restart' triggering before callbacks for `deploy:restart' * executing `assets:compile'
Написание собственных заданий — отличный способ узнать, что происходит под капотом с Capistrano. Несколько вещей, которые нужно помнить о задачах, это то, что они написаны простым старым Ruby, так что у вас есть все обычные идиомы, доступные вам. Другое — Capistrano — предоставляет хороший набор переменных конфигурации, таких как current_path
, shared_path
. Полный список был составлен парнем Эриком Дэвисом .
Чтобы закрепить эти моменты, мы рассмотрим создание еще одной пользовательской задачи. Мне нравится просматривать историю развертывания, поэтому, используя наши знания общего каталога и процесса развертывания capistrano, мы можем создать файл журнала развертываний.
task :log_deploy do date = DateTime.now run "cd #{shared_path}; touch REVISION_HISTORY" run "cd #{shared_path};( echo '#{date.strftime("%m/%d/%Y - %I:%M%p")} : Vesrion #{latest_revision[0..6]} was deployed.' ; cat REVISION_HISTORY) > rev<em>tmp && mv rev_tmp REVISION_HISTORY" end task :history do run "tail #{shared_path}/REVISION_HISTORY" do | ch, stream, out | puts out end end after "deploy", "deploy:log_deploy"
С этого момента в простом плавании для развертываний. Мы просто используем cap deploy
или cap deploy:migrations
зависимости от того, нужно ли нам обновлять схему db для выпуска. Если мы хотим посмотреть историю развертывания, мы просто вызываем cap deploy:history
чтобы получить выходные данные о дате, времени и версии всех наших развертываний.
Наслаждаясь нашим развертыванием
Надеюсь, теперь у вас есть желание развернуть собственное развертывание с Capistrano. Я попытался сделать это прохождение как можно более подробным. Сначала я неохотно принимал участие в Capistrano, так как не был уверен в своих навыках снаряжения и боялся потерять контроль над людьми. Но это было просто глупо с моей стороны.
Я не только избавил себя от необходимости ручного развертывания, но также получил все дополнительные преимущества, которые дает вам Capistrano, такие как возможности отката, автоматическое отключение страницы и так далее. В Capistrano есть еще множество функций, которые входят в стандартную комплектацию, подробности которых можно найти в документации . Существует также множество рецептов для вас, чтобы заимствовать и развивать.
Да, нам нужно потратить немного больше времени на разработку нашего развертывания, чем использовать что-то вроде Heroku. Однако, после написания нескольких рецептов, это станет второй натурой и, возможно, дешевый VPS начнет выглядеть более привлекательным. Источник доступен на GitHub.