September 19, 2011
SinatraとDataMapperで作ったWebアプリをHerokuに移行した時のメモ。
この記事では以下のような作業について書いています。
小規模であれば無料で使えて、かつロックインされないからです。特にロックインされないという点は非常に重要で、先日Google App Engineの料金体系が変更された際に終了に追い込まれてしまったサービスが幾つかありましたが、Herokuでは同じようなことがあっても他の環境に逃げればいいだけなので安心です。
Bundler : gemの管理はBundlerで行います。
git : デプロイはgitで行うので、アプリケーションのファイルはgitで管理しておく必要があります。
Herokuの操作はほぼすべてgemをインストールしてherokuコマンドで行います。
$ gem install heroku
heroku createコマンドでアプリケーションを作成します。初回はメールアドレスとパスワードの入力、および公開鍵の送信を行いますが、指示に従って進めればOKです。
この時、ローカルのgitリポジトリのremoteにherokuが追加されます。
$ heroku create myapp
デプロイはリモートのリポジトリにpushするだけです。push後に自動的に依存関係の解決が行われ、アプリケーションが動作するようになります。
$ git push heroku master
Herokuでは無料の範囲だとRDBMSにPostgreSQLを使うことになります。私はこれまでSQLiteを利用していましたが、RDBMSの違いはDataMapperが吸収してくれるので接続先のURLを変更するだけで移行できました。
Herokuでの接続先はDATABASE_URLという環境変数で渡されます。以下のようにすると、Heroku上ではPostgreSQL、ローカルではこれまでどおりSQLiteで作業できます。
DataMapper.setup :default, ENV['DATABASE_URL'] || 'sqlite3://db/database.sqlite3'
データベースのマイグレーション・アップグレードはrakeで行います。すでに利用している場合は問題ありませんが、そうでなければGemfileにrakeを追加し、Rakefileを作成する必要があります。
# -*- coding: utf-8 -*-
require 'dm-migrations'
$:.push "#{File.dirname(__FILE__)}"
require 'models/...'
namespace :db do
task :migrate do
DataMapper.auto_migrate!
end
task :upgrade do
DataMapper.auto_upgrade!
end
end
作成したタスクはheroku rakeコマンドで実行します。
heroku rake db:migrate
これまでのデータを移行するにはtapsというgemを利用します。インストールしてheroku db:pushコマンドでデータを送信します。元のデータベースは、SQLiteであれば”sqlite://データベースへの相対パス”、PostgreSQLであれば”postgres://user:password@host:port/database_name”のように指定してください。
$ gem install taps
$ heroku db:push sqlite://db/database.sqlite3 --app myapp
ソースコード内に書き込みたくない情報は、設定ファイルに分離してリポジトリには含めないようにすると思いますが、Herokuでのデプロイはgit pushで行うため、リポジトリにないファイルをリモートに置くことができません。そこで、Herokuでは設定のやり取りに環境変数を利用します。
以下のコマンドで設定を行うことができます。設定を追加するとアプリケーションは自動的に再起動して設定が反映されます。
$ heroku config:add KEY=VALUE SESSION_COOKIE_SECRET=XXXXXXXX ...
接続先のときと同様に、Ruby側ではENVで参照できます。
configure do
use Rack::Session::Cookie, :secret => ENV['SESSION_COOKIE_SECRET']
end
Herokuではデフォルトの構成ですでにVarnishが挟まっていて、Cache-Controlヘッダを設定するだけで適切にキャッシュしてくれます。
get '/' do
...
cache_control :public, :max_age => 3600
...
end
custom_domainsというアドオンの追加とDNSの設定が必要です。
$ heroku addons:add custom_domains
$ heroku domains:add www.example.com
DNSの設定では、以下の3つのIPアドレスのaレコードを追加します。
以下はバリュードメインでの設定例。
a www 75.101.163.44
a www 75.101.145.87
a www 174.129.212.2
Herokuはgitのsubmoduleに対応していません。根本的な解決方法はないので、おとなしくファイルを自分のリポジトリに追加しましょう。
いくつか作業は必要でしたが、割とあっさりRackアプリが動いてしまったのは驚きでした。他の環境で動作する状態が崩れていないのがすばらしいですね。
GAEのイメージでこの手のサービスは独自のルールがあって面倒なのではないかと思っていたのですが、Herokuではそんなことはまったくなく、もっと早く手を出していればよかった、というのが率直な感想です。