Статьи

Как использовать JRuby для Rails-приложений в Cloud Foundry

Содержание этой статьи было первоначально размещено Томасом Рисбергом в блоге Cloud Foundry.

Приложения JRuby Rails могут быть развернуты на CloudFoundry.com сегодня с простыми изменениями конфигурации. Приложения JRuby обычно развертываются в контейнеры сервлетов, создавая файл .war, содержащий приложение Rails. Мы сделаем то же самое для Cloud Foundry с некоторыми изменениями в конфигурации базы данных, поэтому приложение также может получить доступ к службе базы данных на CloudFoundry.com.

Изменения, необходимые для развертывания JRuby on Rails Applications в Cloud Foundry

Для запуска приложения JRuby на CloudFoundry.com необходимо выполнить две задачи. Сначала нам нужно настроить приложение для подключения к службе базы данных на CloudFoundry.com, изменив файл database.yml в каталоге конфигурации. Нам также нужно запустить эквивалент rake db: migrate при развертывании приложения для создания таблиц базы данных. Мы можем сделать это, добавив инициализатор в каталог config / initializers.

Информация, необходимая для настройки соединения с базой данных, доступна в переменной среды VCAP_SERVICES. Мы могли бы либо проанализировать эту переменную программно, либо использовать удобный гем времени исполнения Cloud Foundry (см. Использование блога Cloud Foundry Services с Ruby: Часть 2. Поддержка времени исполнения для приложений Ruby), что мы и сделаем здесь. Чтобы использовать этот драгоценный камень, нам нужно включить его в наш Gemfile:

...
gem  'cf-runtime'
...

Теперь, когда мы добавили этот гем, мы можем добавить некоторые фрагменты кода в файл database.yml для доступа к информации службы баз данных для производственной среды. Ниже приведена производственная часть из файла database.yml, где мы используем базу данных MySQL:

конфиг / database.yml

production:
  adapter: mysql
  <% require 'cfruntime/properties' %>
  <% db_svc = CFRuntime::CloudApp.service_props('mysql') %>
  database: <%= db_svc[:database] rescue 'bookshelf_production' %>
  username: <%= db_svc[:username] rescue 'root' %>
  password: <%= db_svc[:password] rescue '' %>
  host: <%= db_svc[:host] rescue 'localhost' %>
  port: <%= db_svc[:port] rescue '3306' %>

Как видите, мы добавили оператор require для cfruntime / properties, а затем мы получаем хеш свойств службы, вызывая метод service_props, передавая тип используемого нами сервиса. Если к приложению привязана только одна служба такого типа, указывать фактическое имя службы не нужно. Вам нужно будет указать фактическое имя службы, если вы привязываете несколько приложений одного типа к своему приложению. Хэш свойств службы хранится в переменной с именем db_svc, и код извлекает соответствующие значения, которые будут использоваться для базы данных, имени пользователя, пароля, хоста и порта. У каждого из этих операторов есть пункт спасения, в котором содержатся значения, которые можно использовать, если мы не работаем в среде Cloud Foundry, и в этом случае db_svc будет равен нулю.

В качестве альтернативы производственная часть файла database.yml будет выглядеть так для PostgreSQL:

production:
  adapter: postgresql
  encoding: unicode
  <% require 'cfruntime/properties' %>
  <% db_svc = CFRuntime::CloudApp.service_props('postgresql') %>
  database: <%= db_svc[:database] rescue 'bookshelf_production' %>
  username: <%= db_svc[:username] rescue 'bookshelf' %>
  password: <%= db_svc[:password] rescue '' %>
  host: <%= db_svc[:host] rescue 'localhost' %>
  port: <%= db_svc[:port] rescue '5432' %>

Далее мы обратим наше внимание на создание таблиц, которые нам нужны для нашего приложения. Чтобы это произошло, нам нужно добавить следующий инициализатор в каталог config / initializers при развертывании приложения. Я назвал этот инициализатор cf_db_migrate.rb:

конфиг / Инициализаторы / cf_db_migrate.rb

require 'cfruntime/properties'
 
# Run the equivalent of rake db:migrate on startup
if CFRuntime::CloudApp.running_in_cloud?
  migrations = Rails.root.join('db','migrate')
  if migrations.directory?
    ActiveRecord::Migrator.migrate(migrations)
  end
end

Мы снова используем cfruntime / properties и проверяем, что мы работаем в облаке. Затем мы проверяем, существует ли каталог db / migrate, и запускаем ли миграцию базы данных, используя файлы миграции в каталоге (ActiveRecord :: Migrator.migrate (migrations)).

Еще одно изменение, которое мы должны сделать, — это конфигурация warble. По умолчанию он не включает каталог db / migrate в сгенерированный файл war, поэтому нам нужно добавить его в конфигурацию, указав config.include = FileList [«db / migrate / *»]. Вот соответствующее содержимое файла config / warble.rb:

конфиг / warble.rb

# Warbler web application assembly configuration file
Warbler::Config.new do |config|
 
  # Application directories to be included in the webapp.
  config.dirs = %w(app config lib log vendor tmp)
 
  # Additional files/directories to include, above those in config.dirs
  config.includes = FileList["db/migrate/*"]
 
end

Полный пример

Это предполагает, что у вас есть рабочая среда JRuby с уже установленными гемами Rails, Warbler и MySQL.

Выше мы видели, какие изменения необходимы, поэтому давайте быстро сгенерируем приложение Rails, внесем необходимые изменения и развернем приложение на CloudFoundry.com. Если вы еще не установили JRuby, лучше всего начать с JRuby .

Создайте приложение JRuby Rails

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

jruby -S rails new bookshelf -d mysql
cd bookshelf
jruby -S rails generate scaffold Book title:string category:string published:integer price:decimal{10.2} isbn:string

Затем мы удаляем сгенерированный public / index.html и модифицируем config / rout.rb, чтобы использовать «books» в качестве корня:

rm public/index.html
vi config/routes.rb

Вот маршрут, который я добавил в config / rout.rb:

Bookshelf::Application.routes.draw do
  resources :books
 
  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to => 'welcome#index'
  root :to => 'books#index'
 
  # See how all your routes lay out with "rake routes"
 
end

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

jruby -S rake db:create
jruby -S rake db:migrate
jruby -S rails server

Пустой список Rails сущности Book показывает, что это действительно работает. Теперь я могу добавлять новые книги на мою книжную полку.

Изменить приложение JRuby Rails для развертывания CloudFoundry

Давайте начнем с внесения следующих изменений, которые мы упомянули выше:

  • добавить gem cf-runtime в Gemfile
  • измените раздел «production:» файла config / database.yml, как показано выше
  • добавьте файл с именем config / initializers / cf_db_migrate.rb с содержимым, показанным выше

Далее нам нужно сгенерировать конфигурационный файл Warbler, чтобы мы запустили:

jruby -S warble config

Теперь мы можем:

  • измените config / warble.rb, чтобы добавить каталог db / migrate, как показано выше

Это все необходимые изменения, и теперь мы готовы упаковать и развернуть это приложение.

Упакуйте и разверните приложение JRuby Rails в CloudFoundry

Мы будем использовать Warbler для упаковки приложения в войну и утилиту командной строки CloudFoundry vmc для его развертывания.

Процесс, который мы используем, чтобы упаковать приложение в файл war, прост: связать, предварительно скомпилировать ресурсы и запустить Warbler:

jruby -S bundle install
jruby -S rake assets:precompile
jruby -S warble

Это создает bookshelf.war в корневом каталоге нашего приложения Rails. На данный момент есть некоторые проблемы с запуском команды vmc с JRuby, но мы работаем над исправлением этого. Тем временем мы можем переместить файл war в другой каталог, чтобы мне было легче переключаться на использование обычного «C» Ruby. Я создам каталог ‘deploy’ и сконфигурирую его для использования Ruby 1.9.2-p290 (я использую rbenv, но вы также можете использовать RVM):

mkdir deploy
mv bookshelf.war deploy/.
cd deploy
rbenv local 1.9.2-p290
# (if you use RVM the command should be 'rvm ruby-1.9.2-p290')

Теперь мы готовы войти в CloudFoundry и развернуть наше приложение. Для этой части вам нужно установить vmc .

vmc target api.cloudfoundry.com
vmc login cloud@mycompany.com
Password: *****
Successfully logged into [http://api.cloudfoundry.com]
vmc push bookshelf
Would you like to deploy from the current directory? [Yn]: Y
Application Deployed URL [bookshelf.cloudfoundry.com]: mybookshelf.cloudfoundry.com
Detected a Java Web Application, is this correct? [Yn]: Y
Memory reservation (128M, 256M, 512M, 1G, 2G) [512M]: 512M
How many instances? [1]: 1
Bind existing services to 'bookshelf'? [yN]: N
Create services to bind to 'bookshelf'? [yN]: Y
1: mongodb
2: mysql
3: postgresql
4: rabbitmq
5: redis
What kind of service?: 2
Specify the name of the service [mysql-a4fd7]: mysql-books
Create another? [yN]: N
Would you like to save this configuration? [yN]: N
Creating Application: OK
Creating Service [mysql-books]: OK
Binding Service [mysql-books]: OK
Uploading Application:
  Checking for available resources: OK
  Processing resources: OK
  Packing application: OK
  Uploading (707K): OK
Push Status: OK
Staging Application 'bookshelf': OK
Starting Application 'bookshelf': OK

Команды vmc выделены выше. Большинство значений по умолчанию были приняты, за исключением URL-адреса и необходимости создания службы. Я использовал URL «mybookshelf.cloudfoundry.com» вместо стандартного, чтобы избежать конфликта с существующими приложениями на книжной полке. Я ответил «Y» на вопрос о создании нового сервиса, выбрал (2) mysql и назвал его «mysql-books».

Теперь мы должны увидеть запущенное приложение:

vmc apps

+-------------+----+---------+---------------------------------+---------------+
| Application | #  | Health  | URLS                            | Services      |
+-------------+----+---------+---------------------------------+---------------+
| bookshelf   | 1  | RUNNING | mybookshelf.cloudfoundry.com    | mysql-books   |
+-------------+----+---------+---------------------------------+---------------+

 

Теперь мы можем ввести «http://mybookshelf.cloudfoundry.com/» и увидеть, как приложение «Книжная полка» оживает и добавить несколько книг.

Вы можете просмотреть и загрузить весь источник, использованный для этого примера, на cloudfoundry-samples / jruby-rails-bookshelf или, если вы просто хотите увидеть изменения, необходимые для развертывания в Cloud Foundry, посмотреть на этот коммит .

Вывод

Мы показали, что можно развернуть простое приложение JRuby on Rails в cloudfoundry и использовать службу MySQL в качестве резервного хранилища данных. Все, что требуется, это некоторые изменения в конфигурации приложений базы данных.

В следующем посте мы рассмотрим аналогичные изменения, которые мы должны сделать для приложения JRuby Sinatra, которое использует DataMapper для сохранения.