さくらのVPS上でNginx + Unicorn + MySQL + Railsな環境で動いていたAnosideを、Herokuに移動しました。この記事はそのレポート的なものになります。
Anosideってなに?
http://anoside.com Anoside | 匿名で、気にせず、つぶやこう。
匿名でつぶやきが投稿できるWebサービスです。2ちゃんねるとTwitterを足して2で割ったようなサービスです。僕が1人で細々と開発、運営をしています。
最近のソーシャルネットワークな世界は現実世界の人間関係に近づきすぎていて、自分の発言が自分を知る誰かに読まれることが日常的になっています。そのせいで、周りの人に見られると困るような発言がしづらいという雰囲気になっています(少なくとも僕の中では)。
そういう発言しづらい内容を、周りを気にせずつぶやいてみんなに見てもらえたら、それはとっても嬉しいなって思い、Anosideを作りました。よかったら使ってみてくださいー。
サーバ移行のモチベーション
サービス開発に集中したいので、サーバ周りに時間をかけたくない
Anosideをリリースするとき、サーバのセットアップをしました。僕がサーバ周りにあまり詳しくないということもあるのですが、結構時間がかかりました。データのバックアップやエラー検知、プロセスの監視などなど。「この作業時間をサービス開発に当てられたら、もっと良いプロダクトになるだろうなあ」と思いながら、AnsibleのPlaybooksを書いたりしてました。
例えAnsibleでサーバ設定を自動化したとしても、ソフトウェアのバージョンを上げる作業など、運用中にサーバ周りで時間をかけることはたくさんありそうです。僕はサービスを作るのが好きみたいで、いろいろと作りたいサービスがあるので、サーバ周りには極力時間をかけず、サービス開発に時間をかけるほうが有意義に思えました。
悲しいけど、Herokuでもサーバ費がそんなに高くならない
Anoside、残念ながらあまり人がいません。
アクセス数がほとんどないので、1X dynoを2台(webとworkerで1台ずつ)動かせば十分そうです。1X dynoは1台分無料になるので、実質もう1台分の料金だけで済みます。データベースもHobbyのBasic ($9/1 month)プランでしばらく問題なさそう。万が一アクセス数が急増したときは、泣きながら笑いたいと思います。泣きながら笑えたら良いなあ…。
サーバ移行時にやったこと
既存のRailsアプリケーションをHerokuで動くようにする
AnosideはRails 4で作られたアプリケーションなので、Getting Started with Rails 4.x on Herokuを参考にしました。
設定情報をFigaroで管理するようにする
今までアプリケーション内の設定情報をRailsConfigで管理していましたが、今回からHerokuの環境変数を利用した設定情報管理方法と相性の良いFigaroを利用することにしました。
SidekiqがHeroku上で動くようにする
メールの送信処理をバックグラウンドで実行するためにSidekiqを使用しているので、Herokuで動くようにします。SidekiqはRedisを使用するので、まずはRedisの設定から。
Redis Cloudを使う
Redis Cloud | Add-ons | Heroku
よく使われているのはRedis To Goみたいですが、Redis Cloudのほうが無料プランの容量が大きかったので、こちらを利用することにしました。
$ heroku addons:add rediscloud
ProcfileにSidekiqの起動コマンドを追加する
以下を Procfile
に追記して、Sidekiqの処理をWorker Dyno上で実行するようにします。
worker: bundle exec sidekiq
Herokuに環境変数 REDIS_PROVIDER
をセットする
下記コマンドで REDIS_PROVIDER
という環境変数をセットします。Sidekiqはこの環境変数に設定されたRedisサーバにキューを保存します。
$ heroku config:set REDIS_PROVIDER=REDISCLOUD_URL
Redis Cloudを使用すると、自動で REDISCLOUD_URL
という環境変数がHerokuに設定されます。この環境変数にサーバ情報が保存されているので、REDIS_PROVIDER
はこの環境変数を見るようにします。
メールサーバにMandrillを使用する
Mandrill by MailChimp | Add-ons | Heroku
さくらのVPSでAnosideを運用していた頃からMandrillを利用していたのですが、Herokuのアドオンとしても提供されていたので、こちらを使用することにしました。
$ heroku addons:add mandrill
環境変数として MANDRILL_APIKEY
と MANDRILL_USERNAME
が設定されるので、この情報をRailsが読めるようにします。
config.action_mailer.smtp_settings = {
address: ENV['SMTP_HOST'],
port: ENV['SMTP_PORT'],
user_name: ENV['MANDRILL_USERNAME'],
password: ENV['MANDRILL_APIKEY'],
authentication: :plain
}
$ heroku config:set SMTP_USERNAME=MANDRILL_USERNAME
とかすれば ENV['SMTP_USERNAME']
で MANDRILL_USERNAME
の値が見れるようになるかと思ったのですが、Net::SMTPAuthenticationError
という例外が発生してメールサーバの認証ができませんでした…。
ログの管理にLogentriesを使用する
Papertrailという選択肢もあってどちらにするか迷ったんですが、1日に保存できるログの量がLogentriesのほうが多いみたいなので、こちらを選びました。
$ heroku addons:add logentries
データベースのバックアップにPG Backupsを使用する
2014/02/01現在、3プランとも全て無料なので、一番高機能そうな「Auto - One Month Retention」プランを使用することにしました。
$ heroku addons:add pgbackups:auto-month
アプリケーションのエラー監視にSentryを使用する
他にもHoneybadgerやAirbrakeという聞いたことのあるプロダクトがあったんですが、無料プランがあるのがSentryだけだったので、とりあえずSentryを使うことにしました。
$ heroku addons:add sentry
アドオンのインストール後、Sentryの管理画面にアクセスし、プロジェクト詳細の設定ページで「Platform」を「Rails 4 (Ruby)」にしました。
その他サーバの監視にNew Relicを使用する
2014/02/01現在、無料プランが2種類あり、「Maximum monthly average dynos」によって受けられるサービスに差があるみたいです。Starkプランだと平均1.5 dynosなら全ての機能が使えるみたいなので、こちらを選択しました。どうせ平均1.5 dynosもいかないだろうし…。
$ heroku addons:add newrelic:stark
管理画面にアクセスし、タイムゾーンとPing URLの設定をしました。
さくらのVPS側の本番サーバをメンテナンスモードにする
Heroku側の設定がひと通り終わった気がするので、実際にサーバ移行作業に入りました。Nginxを使用していたので、ngx_http_rewrite_moduleでanoside.comへのリクエストをメンテナンス告知ページにリダイレクトして、データベースへのアクセスを一時的に遮断しました。
データベースのデータをHerokuに移す
MySQLのデータをPostgreSQLのデータにコンバートする
(今回の移行作業では、後述するtaps-tapsというツールを使用してデータをコンバートしたんですが、Herokuの公式ドキュメントにモダンそうな別の方法が紹介されているので、この方法を試したほうが良かったかも知れません。もう少し早くこのドキュメントを見つけていれば…。)
今までMySQLにデータを格納していたので、Herokuで使用するPostgreSQL向けにデータをコンバートする必要がありました。適当にググったら taps-taps というRubyのツールが見つかったので、これを使用しました。
(taps-tapsはtapsからフォークされたものです。本家のtapsは、Ruby 2.1で実行すると内部で使用している OkJson というgem周りでエラーが起こすバグがあるようで、使用できませんでした。)
$ gem install taps-taps
使い方は「Ruby - taps で簡単に MySQL から PostgreSQL へデータを移行する - Qiita [キータ]」を参考にしました。
以下は実際に実行したコマンドです。
$ taps server mysql://root@localhost/anoside_tmp httpuser httppass
$ taps pull postgres://bojovs@localhost/anoside_tmp http://httpuser:httppass@localhost:5000
taps server
コマンドでMySQLのデータベースを読むSinatraアプリを起動し、次の taps pull
コマンドでそのアプリケーションにアクセスして、データをPostgreSQLに移すという流れになります。
コンバートしたデータをダンプする
データをHerokuのデータベースにインポートするため、ローカルのPostgreSQLに格納されたコンバート済みのデータをダンプする必要があります。下記コマンドでダンプしました。
$ pg_dump -Fc --no-acl --no-owner -h localhost -U bojovs anoside_tmp > anoside_tmp.dump
ダンプデータをAmazon S3にアップロードする
Herokuにデータをインポートするために用意されている heroku pgbackups:restore
というコマンドは、HTTPでアクセスできる場所にダンプデータが無いと動作しないらしいので、今回はAmazon S3にアップロードしました。(なんでサーバに上げる必要があるんだろう…?)
データをインポートする
S3にアップロード後、下記コマンドを実行すると、Herokuのデータベースにダンプデータがインポートされます。
$ heroku pgbackups:restore DATABASE_URL https://s3-ap-northeast-1.amazonaws.com/path/to/anoside_tmp.dump
DATABASE_URL
はHerokuのPostgreSQLデータベースへのURLがセットされている環境変数になります。この環境変数は初めから設定されています。
anoside.com
がHerokuを向くようにする
最初に下記コマンドでドメインをHerokuに追加します。
$ heroku domains:add anoside.com
次にドメインのDNS設定に以下を追記します。
cname @ anoside.herokuapp.com.
今回はanoside.com
というルートドメインにCNAME
レコードを使用しましたが、例えばもし「info@anoside.com」のようなメールアドレスを作りたい場合は、ALIAS
やANAME
レコードを使用する必要があります。
最近だとAmazon Route 53がALIAS
レコードに対応しているので、こちらを利用すると良いかも知れません (未検証なのでうまくいかないかも…)。
このあとDNSの設定が反映されて、無事Herokuへの移行が完了しました。
we love herokuに登録する
Herokuを利用しているWebサービスをまとめている「we love heroku」というサービスがあったので、登録してみました。みんな結構Heroku上にサイトを作っているんだなあ。
作業完了
データベースの移行がちょっと面倒くさかったくらいで、他の作業はサクサクと終わりました。よーし、おじさんサービス開発に集中しちゃうぞー。
「このHerokuのアドオンがオススメだよ!」とか、「あの設定しなくていいの?」みたいなことがありましたら、ぜひ教えてもらえると嬉しいです。
あとしつこいですが、Anosideもよろしくお願いします! 目指せユーザ数100人!