弊社(FJORD, LLC)がEngine Yardとパートナーシップ(的なもの)を結んで怖話Engine Yard Cloud(以後EYC)に移行しました。

(飽くまで”的なもの”で、ちゃんとしたパートナーシップはこういうの

トライアルで検討する

トライアルで試した件については以前こちらに書きました。

Engine Yard Cloudを試す - komagata

本契約前に

貧乏会社なので複数台サーバーなんていくら掛かるのか怖い。料金シュミレーターで予め見積もっときました。

さくらVPSから移行したのは複数台構成のためなので、ちょっと奮発してappサーバー2台+dbサーバー1台の構成にしてみました。高けー!

デプロイ

手順はトライアルの時と同じです。ただ、本契約の場合は東京リージョンが選べます。

アクセスしてみる

appサーバー2台あるけど、どのIPにアクセスしたらいいの?と思いましたが、Application Masterの方のSSHのリンクをクリックする時に出るURLにIPがハイフン区切りで出てるのでそこにアクセスします。(この場合は54.249.225.67)

dbの方もそれで直接dbのインスタンスにsshできます。ユーザー名はdeployでした。

アプリをEYCに合わせる

EYCに載せるに当ってアプリを修正しないといけない点が2点ありました。

rubyを1.9.3系にする

EYCはまだruby2.0.0に対応してないので1.9.3系に変更しました。あんまり変わらないだろうと思ってましたが、encodingのmagic commentが無くていくつかエラーが。泣く泣く追加しました。

ユーザーのアップロード画像をS3に移行

これはEYCだからではなく、appサーバーが複数台になるのでユーザーがアップする画像をローカルに保存してたら迷子になります。幸いpaperclipの画像保存先をS3にするのは簡単で1日あれば対応できました。

データベースの移行

$ ssh bodom "mysqldump -udeployer -pXXXXXXX kowabana_production" | ssh db.kowabana.jp "mysql -uroot kowabana" 

これはコマンド1行でOK。sshで入れるとこういうところが楽ですね。EYCのdb名はアプリ名と同じになるようです。mysqldumpは全テーブルロックするのでデータ量の大きなサイトではこういう雑な移行はオススメできません・・・。

railsアプリのdatabase.ymlの接続先は変えなきゃいけないんじゃないの?と思いましたが、EYCのdeployのレシピで良い感じにdatabase.ymlを生成してくれるそうです。便利。

サポートチャット

トライアルの時もお世話になったサポートチャットですが、グローバルの方は平日の8AM PST - 6PM PST(日本では1時から13時)がサポート時間です。

これは豆ですが、Engine Yardの日本法人のトップページのチャットから発信すれば日本人が日本時間で対応してくれます。

感想

まだ移行したばっかりなのでどうなるかわかりませんが、移行作業自体は思ったより早く簡単にできたなと思います。最近セキュリティ周りがキナ臭いのでその辺は安心感がありますね。(最近別の仕事でウィルスに感染したPHPのサイトの調査をやったばかりです。)

オープンネットワークラボにGithubのPJらが来た時のイベントで「初期のGithubはEngine Yardにサーバーを借りていた」という話を聞いてその後の懇親会でいきなり不躾にも「弊社にもサーバー貸してください!」と@yandoさんに無茶振りしたことから始まった話でしたが色々お手数をお掛けしつつ移行できてよかったです。ありがとうございます。

>> image.url
=> /system/foo/bar.jpg
>> app.root_url
=> http://example.com/
>> app.root_url[0...-1] + image.url
=> http://example.com/system/foo/bar.jpg

他にいいやり方無いかしら。

rake db:resetがherokuではできないので下記。

$ heroku pg:reset DATABASE_URL --confirm my-app

Rails Best PracticesのLaw of demeterを直してる時に結構出てくる。

class Award < ActiveRecord::Base
  belongs_to :story
  delegate :user, :user_name, to: :story, prefix: true
end

class Story < ActiveRecord::Base
  belongs_to :user
  delegate :name, to: :user, prefix: true
  
  has_many :awards
end

class User < ActiveRecord::Base
  has_many :stories
end
>> Award.find(1).story_user_name # => "komagata"

これは分かりやすくなってる!・・・のかな・・・。

RailsでDBのデータ変更はどこに書く? - komagataの続き。

コメント欄やFacebook、Twitterなどで色々教えていただきありがとうございます!

ちょっとFBの過去ログ見つからないんですが確か@kdmsnrさんが

「Rails Wayにseed.rbではdelete_allしろと書いてあった」

と仰ってました。

つまり、rake db:seedはproductionで毎回実行する。リエントラントに書くってことですな。

自分のプロジェクト(怖話)でも、今までInsertSeedMigrationみたいに書いてたのをrakeタスクとseedに移すように書きなおしてます。

どういう時に何が困ってたのかやっと自分の中でまとまってきたんですが、要は、

「最初の3人のユーザー」とか「最初の10件のPOST」とか「productionで後々増えていくデータの初期データ」をどうするのか?ってことでした。

User.delete_allしてUser.create!をseedに書くとproductionで他のUserが消えちゃうし。seedでif Rails.env.production?する?

怖話Andyというユーザー名で登録しようとするとエラー。

Mysql2::Error - Duplicate entry 'Andy' for key 'index_users_on_name'

多分小文字のandyとぶつかってるんだろうな。

validates :name, uniqueness: trueしてるのに何故だろう。mysqlのcollationが変なのになってるのかなと確認してみるも問題無し。

uniquenessを確認している部分のSQLクエリをみてみると・・・

SELECT 1 AS one FROM `users` WHERE `users`.`name` = BINARY 'Andy' LIMIT 1

BINARY・・・だと・・・!?

deviseの設定でcase_insensitive_keysを設定しないとBINARYで確認しにいくようです。

# config/initializers/devise.rb:
config.case_insensitive_keys = [ :email, :name ]

ここにnameも追加してOK。configのコメントぐらいちゃんと読んどけってことですな。

starseeker

「usefulなライブラリを求めてるのにstarseekerを使ってない?」

「ふざけるな!」

「本日より貴様をスノーボール二等兵と呼ぶ」

「いい名前だろ、気に入ったか?」

成人男性の98%が利用してるというstarseeker.soに関して、残念ながら残りの2%に該当してしまった人(もしいるとすれば)にご説明させて頂きます。

starseekerとは

githubで自分がfollowしている人がstarを付けたrepositoryを毎朝メールしてくれるサービスです。

ただ僕はRSSもTwitterも見ない人のものは全く見ない代わりに見ると決めた人はひとつも漏らさず見るスタイル(情報収集スタイルについて - komagata)なので、starseekerもRSSフィードで見てます。

例えば、

moroさんがstarしてるreposは何か実用的でちょこっと便利なやつなんだろうなーとか

junoさんがstarしたのは、俺が知らないなんかおしゃれなgemとかなんだろう、とか

kenchanさんはすごくエッジなライブラリを見つけててすごいな、とか

全く知らなかったclojureを始めた時も、clojureの有名な人をfollowしとけばそこから直ぐに良い人が見つかって広がりました。

ビジネスマンが日経読んでないと上司に怒られる・・・みたいな。これが無い生活は考えられません。

あと、starseeker.so自体もruby2.0.0-p0, rails4beta1, pumaでソースがとても綺麗で参考になりました。

まあ、控えめに言って 神サービス ・・・ ですよね。

#263 Client Side Validations - RailsCasts

modelに定義したvalidationルールを使ってclient sideでもjsでvalidateしてくれるclient_side_validationsは糞便利なんですが、hiddenな要素はvalidateできない。

例えば、user_idがhiddenであって、特定のユーザーをブロックしたい時にはhidden要素もclient_side_validationsでvalidateしたい。

jsを2行書けば済むことなんですが、今後もありそうなのでgemにしました。

komagata/client_side_validations-with_hidden · GitHub
# Gemfile:
gem 'client_side_validations-with_hidden'
// app/assets/javascripts/application.js:
//= require rails.validations
//= require rails.validations.with_hidden

productionのデータ変更処理をmigrationに書くとrails_best_practicesに怒られる。

Rails Best Practices | Isolating Seed Data

怖話のコードで言えば下記の様なもの。

# encoding: utf-8                                                                        
class InsertSeedToSound < ActiveRecord::Migration
  def up
    Sound.create!(id: 1, name: "鳥の鳴き声")
    Sound.create!(id: 2, name: "犬の鳴き声")
    Sound.create!(id: 3, name: "水滴")
    Sound.create!(id: 4, name: "カエルの鳴き声")
    Sound.create!(id: 5, name: "ラジオのチューニング")
  end
    
  def down
    Sound.delete_all
  end
end

僕はmigrationに書いちゃってるけどみんなさんはどうやってますか?

seed.rbに書けっていうけどrake db:seedってリエントラントに書くもの?最初の一回だけじゃないの?

それとも、productionの状態に合わせて過去のmigrationをまとめてseed.rbをそれに合わせて書きなおすみたいなことするのかな?

ちょっと周りのrubyist2名ぐらいに聞いた感じ結論が出なかったので「ふつうこうだよ」っていうのを知ってる方がいたら教えていただけるとありがたいです!(@komagata

Githubも使ってたというAWSベースのPaaSの老舗Engine Yard Cloudを試してみました。

Engine Yard CloudはAWSの東京リージョンもサポートし、最初の500時間無料とのことで今後複数台構成を考えている怖話の移行先として動くかどうかデプロイしてみます。

Application作成。githubのreposを直接入れることができるのは嬉しい。

deployのためのキーが発行されます。これをgithubや自分のgit repos serverに登録してやれば勝手に取ってきてdeployしてくれると。

怖話のgithub reposのDeploy Keysにさっきのキーを登録。

Environmentの作成。Application Serverが選べるのか。怖話はunicornなので選択。rubyもgemもデフォルトでOK。

無料お試し中は東京リージョンは選べないそうです。残念。MySQLのバージョンを選んで、へーDBバックアップやインスタンスのスナップショットもデフォルトで取ってくれるのか。

一番気になるインスタンス構成の選択画面。

Single Instance
1台でアプリもDBも賄う。
Staging Configuration
appサーバー2台とDBサーバー1台。
Production Configuration
appサーバー3台とDBサーバー2台(master and slave)
Custom Configuration
カスタム。(お試し中は派手にできないらしい)

appサーバーは良い感じにbalanceしてくれるらしい。しかしDBサーバーはどうなってるんだろう。やっぱりアプリ内で明示的にmaster, slave分けてアクセスするんだよね?

とりあえずStaging configurationで。

後はただ起動処理を眺めます。ログを見るとchefで色々ガーっとやってくれてるみたいです。

rake db:migrateのところをrake db:seedにして怖話のseedを実行。そして割り当てられた仮のドメインにアクセスしてみると。

おお、特に何もいじってないのに怖話のproductionが動いた!凄いぞEYC!

鬼サポート

実は初めてdeployした時は500番が出て動きませんでした。

右下にあるサポートチャットに、

"I deployed an app. But dosen't work."

とか物凄い抽象的な助けを求めたら、

「railsアプリにエラーがあるのかもしれない。ここからsshでログインできるから"/path-to/production.log"にあるログを見てみたらどうだい」

みたいなこと言われたので見てみたら、Engin Yard Cloudとか関係無く、普通に怖話のproduction(のseedのコード)がバグってただけでした。修正してアップし直したら動きました。

多分あっちは昼間なんだろうけど、夜の2時頃、お酒を飲みながら適当にインフラを弄ってた俺としては助けを求めた瞬間に的確に帰ってきたサポート体制に感動しました。(飲酒も手伝って)

logentriesのサポートチャットを使った時も同じような体験をしましたが、技術的にちゃんとわかってるサポートが瞬時に答えてくれるってのは今時のサービスでは当たり前なんでしょうか?ありがたすぎるぞ。

感想

VPSで動かしてた怖話のproductionが何の変更も無しに動いたのはびっくり。あと金額も俺の超概算だとAWS直に10〜20%ぐらい載っけるぐらいの思ってたより安い価格設定。

自分の用途としてはある程度規模のサービスで、しっかりした会社からの受託開発を受けたら本気で検討する価値ありだなと思いました。

なんだかんだ行っても複数台構成には色々と面倒がついてきますし(デプロイ、監視、ロギング、バックアップ等)、何よりもAWSで作りこんだら引き継ぎが超面倒そう。リアルに想像すると「EC2で作りこんであの会社に引き継いだら運用できるのかな・・・」って思う時がありますが、EYCなら引き継げそう。特に鬼サポートはちゃんとした会社にとってはありがたいと思います。ググレカスとか言われないですし。