Heroku + MongoHQ が素晴らしい

16th Nov, 2010 | heroku mongodb rails ruby

前から気になっていた Heroku + MongoHQ を試してみた。HerokuはRubyアプリケーションを走らせるホスティングサービスで、MongoHQはMongoDBのホスティングサービスだ。この二つを組み合わせることで、MongoDBを使ったRubyアプリケーションを一瞬で運用開始することができる。

あまりにも簡単に使えてあまり書くこともないんだけどメモ。

まず、両方とも最低限の環境は無料で使用できる(ただしHerokuからMongoHQを使うためにはクレジットカードの登録は必要っぽい)。

今回は Ruby on Rails 3 + Mongoid で作ったアプリを置いてみた。

手順

1. まず、普通に RoR + Mongoid のアプリケーションを作る

2. Herokuにアカウントを作りアプリケーションを登録する (http://docs.heroku.com/quickstart )

3. HerokuでMongoHQを有効にする (http://docs.heroku.com/mongohq )

$ heroku addons:add mongohq:free

4. Mongoidの接続情報であるconfig/mongoid.ymlのproduction環境のところを以下のように書き換える。

production:
  uri: <%= ENV['MONGOHQ_URL'] %>

追記: もしくは、 config/initializers/mongohq.rb のようなファイルを作り、 そこで指定する。

if ENV['MONGOHQ_URL']
  # For Heroku (See: http://docs.heroku.com/mongohq)
  Mongoid::Config.instance.from_hash({"uri"=> ENV['MONGOHQ_URL']})
end

5. 普通にHerokuへdeployする (具体的には、gitでHerokuにpushする)

これだけで、MongoHQのMongoDBを使うようになる。超簡単。

(ちなみに、ここ最近、RubyとMongoDB間のORMはMongoidしか使っていない。一時期、 MongoMapper を使っていたのだけど、Mongoid の使いやすさに負けた。機能的には大きく変わらないのだけど、ちょっとした細かいところとか、センスの良さが全然違う。)

気付いたところ

1. Heroku経由でMongoHQを使うとMongoHQにログインできない?

MongoHQにも管理画面的なのがあるっぽいのでこれはちょっと嫌だ。(何か方法ありそうだが)

2. ここ にあるように、MongoDBの接続情報を取得し、自分の環境からHerokuを通さずに直接接続も可能。

バックアップもmongodumpコマンドで普通に取れるし、 Mongoシェル でアクセスするのも問題ない。これは便利。

ただ、便利なのだけど、つまりMongoHQのMongoDBは全世界から接続可能なので、接続情報や、ID/パスワードの管理は慎重にする必要があるのがちょっと厳しい。例えば、Rubyアプリ側では、 ENV[“MONGOHQ_URL”] にID/パスワード含む接続情報がすべて入っているので、デバッグ目的などでENVを間違えて表示しちゃったりすると大惨事になりそう(これはHerokuのMySQLとかPostgreSQLとかも同じっぽいが)。

3. HerokuからMongoHQまでのlatencyは一桁ミリ秒だった。

なんとなく不安だったのだけど問題なさそう。

まとめ

RoRとMongoDB(Mongoid)のスキーマレスでの素早い開発と、簡単にデプロイできるHeroku+MongoHQの相性がとてもよい。ちょっとしたアプリケーションを作ったり、プロトタイプを作って色々な人に見せたい場合にとても向いていると感じた。もちろん、アクセス数やデータベース容量にあわせて、Heroku/MongoHQともに有料コースに切り替えて本番環境として使い続けるのも問題ないだろう。

また、「Heroku+MongoHQで動かす」と言っても、アプリケーション自体はもちろん普通のRuby(Rails)とMongoDBなので、Heroku/MongoHQが嫌になったら、他へ移ることも、自分で運用するのにも何の問題もない。「とりあえず作ってHeroku+MongoHQで動かしてある程度軌道に乗ったところ次を考える」というのが可能だ。これはかなり魅力的(今、世の中はロックインが流行ってるようだし!)。



Chefを最速で使いこなすためのいくつかのポイント

7th Sep, 2010 | chef sysadmin ruby

前回書いた さようならPuppet、こんにちはChef が、それなりに反響あったので調子に乗ってもうちょっと書いてみる。

前回、ChefはPuppetに比べて簡単!とか書いたが、実際には慣れるまでそれなりに戸惑うところがあった。

ドキュメント を読み、実際に触っただけでは一発で理解できなかった部分を、自分のメモを元に晒しておく。これだけ読んでもいまいちだと思うので、関連するドキュメントへのリンクも張っておくので合わせて読んでみると高速でChefを理解できるかも!

client vs node

ドキュメントを読んだりChefを触っていると client と node という二つのワードが出てくる。この二つは似ているけど別物。

client は文字通り Chef server の相手になるもの。 Chef server にアクセスするものはすべて client になる。例えば、管理ツールである knife (後述)や、管理用のWeb UIなども client になる。認証や通信はすべて client が Chef server と行う。

一方、 node というのは、Chefで管理するマシン/サーバ自体を指す。各 node は Chef server にアクセスし自分の設定を持ってくるのが、これは実際には node にある client 経由で行う。

そのため通常は node は client でもある。そして、 client数 >= node数 になる。

書いてしまうと簡単なのだけど、最初は両者がごちゃごちゃになってしまっていた。ここをしっかり理解しておくとトラブルシューティングもしやすくなる。

トラブルシューティングの例:

ある node (の client )で、サーバにアクセスするのに必要な秘密鍵を間違って消してしまい Chef server へのアクセスができなくなってしまった。この場合どうすればいいか?

対応策: 鍵情報は client に結びついているので、 client の鍵ペアを作り直せばいい(または、 client をサーバから削除して作り直す)。 どちらの場合も、 node の情報をいじる必要ない。

knife

Chefサーバ上にあるデータを触るためのコマンドラインツール。主に手作業でサーバの情報にアクセスしたいときに使う。管理者が使用するもの。上に書いたように knife 自体も client になる。管理者毎に別の client として登録する。

特に、 node の情報は、他の設定と違いサーバ上にしかないので、このコマンドをよく使う。

例1: node の情報(JSON形式)を $EDITOR で開き編集する

$ knife node edit hogehoge.example.com

例2: 指定した client を削除

$ knife client delete fugafuga.example.com

node と cookbook (recipe) と role

まず、 node は、上にも書いたように管理対象のサーバのこと。

cookbook は、実際にChefで行いたい設定の手順を記述したもので、基本的に環境に依存するのものは書かない。依存するものは role や node の attributes に書く(後述)。

recipe とは、設定を記述したrubyスクリプトのことを指す(ドキュメント等で cookbook のことを recipe と呼んでいるケースもあるので注意)。

一つの cookbook は複数の recipe を持つことができる。例えば, LDAP cookbookの中に、 LDAPクライアント用の recipe と、LDAPサーバ用の recipe を持つことができる。

role は、サーバの役割を記述したもの。 どの recipe を使うかということを主に書く。また、 node は、基本的に1つ以上の role を持つ。ただし、ちょっとややこしいが、 node は recipe を role を介さないで直接持つこともできる。

たとえば、 “hoge-system-app” role というのを考えてみる。これは “hoge-system” という Webシステムのアプリケーションサーバを想定する。

ここで、

  • hoge-system-app1.example.com
  • hoge-system-app2.example.com
  • hoge-system-app3.example.com

という3つの node があったとする。3つとも、"hoge-system-app" role を持つ。ただし “hoge-syste-app1.example.com” だけは、特別に、"git" クライアントも入れたい。こういう場合には、gitの recipe を直接指定することもできる。

  • hoge-system-app1.example.com
    • hoge-system-app role
    • git recipe
  • hoge-system-app2.example.com
    • hoge-system-app role
  • hoge-system-app3.example.com
    • hoge-system-app role

もちろん、gitの recipe を持つような、 developer role みたいのを作り、それにgitを持たせ、 node にセットすることもできる。

基本的には、 role 経由で管理したほうがいいが、本当に例外の場合はわざわざ role を作らなくてもいいかもしれない。これは設計次第。

attributes

attributes は、実際に設定したい値(パラメータ)のこと。上述したように、 cookbook / recipe には、サイト固有の情報を持たせないのが原則なので、そういうものはすべて attributes にして外出しにする。

attributes は recipe 自体や、 recipe 経由で template (erbで記述) から使われる。基本的にrubyのHashそのもの。

attributes は recipe にも設定できるし、 role や node にも書ける。

recipe に書いた attributes がその recipe のデフォルト値で、それを role や node の attributes で必要に応じて上書きする、と考えると理解しやすい。

例:まず、 tokyo-office という role があったとしよう。とある東京オフィスにあるサーバ群はこの role を使うというルールになっている。今、この role に対して、LDAPクライントを設定したいとする。

最初に、LDAP cookbook ( recipe ) を作成する。このとき、LDAPサーバのホスト名(IP address)みたいなのがサイト固有の情報になるので、 attributes に切り出す。

次に作成した、 recipe を tokyo-office role に設定する。このとき attributes として切り出した LDAPサーバの IP addresses を role の attributes ととして設定する。

ここで、もし、その中のある、特定の node だけに対して例外的に特別な値(例えば、テスト用のLDAPサーバを見させたいとか)を書きたい場合には、 その node の attributes に書いて、 role の attributes を上書きする。

自分が理解しているのはこんな感じ。enjoy cooking!



さようならPuppet、こんにちはChef

30th Aug, 2010 | chef sysadmin puppet ruby

ここ最近、サーバの設定ファイルの管理で Chef を使い始めている。まだ全然詳しくないけど、今感じている「Chefの楽しさ」を誰かに伝えておきたかったので、ファーストインプレッションを簡単に。

Puppetを今までそこそこ使っていたので、どうしてもそことの比較な感じになっちゃいます。Puppetも良いのだけど、Chefは後発ということでさらに良くなっている感じ。

基本的な仕組

これは、Puppetとほぼ同じ。クライアント-サーバ型のシステム。設定を書き、それをサーバに置いておく。クライアントはサーバと接続し、自分自身の設定を書き換えたり、必要なソフトウェアをインストールしたりする。

rubyな設定ファイル

Puppetは基本的に独自DSLで設定ファイルを記述すので「覚えるのがめんどくさい」「細かいこと、ちょっと無茶なことをしようとすると大変」。Chefの設定ファイルはrubyそのものなので、rubyで表現できることは何でもできる。とは言えDSL風にもなってるのでrubyを知らなくてもなんとかなるレベルでもある。その辺はさすがにruby。実際にどんな感じで設定を書くか、というのは、 この辺参照 。

ローカルでのテストが楽

chef-soloというコマンドがあり、これを使うとChefサーバに接続せずにローカルだけでテストができる。大袈裟なテスト環境を作らなくても自分の環境でテストできるのがとても楽。

設定ファイルが直感的

Puppetは、manifestとかmoduleとかclassとか、どうも最後まで慣れなかったが、Chefは初めの数時間で、すーっと頭に入ってきた。この差はでかい。

いくつかの理由があるけど、まず、設定ファイルのディレクトリ構成がわかりやすいというのが大きい。

設定ファイル内の主要なディレクトリは、cookbooksとrolesの二つだけ。cookbooksの中には、cookbookと呼ばれるソフトウェア毎の設定を置くサブディレクトリがある。一つのcookbookに関連する設定はそのサブディレクトリ内にすべて置く。

例:

cookbooks
  + sshd
    + recipes
    + templates
    + attributes
  + sudo
    + recipes
    + templates
    + attributes
  + apache2
    + recipes
    + templates
    + attributes
  + .....
roles
  + hoge_app.rb
  + hoge_rproxy.rb

この「cookbook内で完結し独立している」というのがとても扱いやすい。完結しているので、自分で管理するのももちろん楽だけど、他の人や会社がが作っているcookbookの流用もしやすい。 Chef公式のcookbook はもちろん、 37 signalsのcookbooks もよく参考にしている。

roleは、どのcookbookをどういう設定で使うか、というのを書く。そして作成したroleを実際のサーバに割り当てる。一つのサーバが複数のroleを持つこともできる。このroleとcookbookという関係もとてもわかりやすい。

各roleの中にはどのcookbookを使うか、というのを羅列する。例えば,

run_list "recipe[apache2]", "recipe[apache2::mod_ssl]", "role[monitor]"

みたいな感じ。そして、cookbookに対する設定もrole内に書く。

default_attributes "apache2" => { "listen_ports" => [ "80", "443" ] }

(このサンプル から引用)

こんな感じ。とってもわかりやすいでしょ?

Git等との距離感

設定ファイルはもちろんGitとかで管理するのだけど、それと実際のChefの動作部分は特に関係ない。設定ファイルを書き換えた後commit/pushで設定の反映ではなく、rake upload_cookbooks 等のコマンドでサーバへ反映。これがなかなか気持ちいい。ソフトウェアをdeployする感覚と似ている。

よくわかってないところ

サーバ側の設定は 弊社のすばらしいシステム管理者の人 がしてくれたので自分はよくわかってない。結構ややこしいみたい。

嫌いなところ

SEO的にどうよ、な部分。Chef自体もそうだし、出てくる単語もcookbookとかrecipeとかknifeとか、ぐぐるの大変だよ!

そんなわけで

とりあえず使い始めてみましたよ。という感じです。

追記: もうちょっと書いた。

追記2: chefのプレゼン資料のようです。わかりやすい。



githubにRails開発者の求人広告載せてみた

13th Aug, 2010 | ruby rails github

githubには個人でも会社でもお世話になってるので新しくできたJobボードに載せてみた。もちろん求人自体は本物なので興味ある人は応募してください。勤務地は東京です。

https://jobs.github.com/positions/a9bc8e26-a6d5-11df-8cf1-63a2a0cb612b

載せるのはとても簡単。Webフォームに求人内容を書いて、クレジットカード情報を入力して完了。プレビュー含めインターフェースがよくできてるのはさすが。載せると修正用のURLが送られてくるのでtypoとかにビビリ過ぎなくても大丈夫(自分は知らなかったのでかなりビビった)。

どのくらい応募があるのか楽しみ。

この求人についてちょっと補足すると、海外に興味はあるけど、いきなりは海外は自信ないとかの人の練習にちょうどいいと思います。技術があれば英語はこれからでも大丈夫です。日本オフィスにも英語な人がたくさんいます。でも、社内公用語は英語です! とかは言ってないので安心です!

CV送れ、と書いてありますけど、日本語で履歴書とか業務経歴書でも大丈夫です。

追記(2010-10-04): 求人広告の成果ですが、一人いい人を採用できました。どこまで言っていいかわからないのですが、応募者数はそんなに多くなかったです。応募者の質は高かったと思います。

githubの広告はexpiredしてしまいましたが、まだ若干名募集しているので、興味のある人は、 こちらまで。



Rails 3 + mongoDB + haml + RSpec + jQuery のインストール - 2

11th Jul, 2010 | ruby rails mongodb haml rspec

(2010-08-30: Rails 3.0.0がリリースされたのでそれにあわせて更新。generator関連が少し変わってる)

前回 の続き。

主に FactoryGirl と MongoMapper の話。基本的に何も考えなくてもそのまま使えるのだけど。

まず、設定。

spec_helper.rb で、

config.use_transactional_fixtures = true

を

config.use_transactional_fixtures = false

にする。そうしないと、ActiveRecord::TestFixtures が呼ばれてしまうのだが、ActiveRecordを入れてないので落ちる。

そもそもMongoDBにはトランザクションとかないのでfalseでいい。

後は、ActiveRecordで使う場合と同じように、FactoryGirlの定義の読み込みを spec_helper.rb の中で行う。

Factory.find_definitions

mongoDBにはトランザクションがないので、テストの前にデータを自分で消しておいたほうがいいだろう。

config.before(:each) do
  MongoMapper.database.collections.each {|collection| collection.remove}
end

全体的にはこんな感じ。generatorが作ったものに、上記変更を入れただけ。

# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

require 'factory_girl'
Factory.find_definitions

RSpec.configure do |config|
  # == Mock Framework
  #
  # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
  #
  # config.mock_with :mocha
  # config.mock_with :flexmock
  # config.mock_with :rr
  config.mock_with :rspec

  # config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, comment the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = false

  config.before(:each) do
    MongoMapper.database.collections.each {|collection| collection.remove}
  end
end

試しに一つFacotryとテストを書いてみる。

File: spec/factories/entry.rb

Factory.define :entry do |f|
  f.title "MyString"
  f.body "MyString"
end

簡単なお試し用のテストを書いてみる。(テスト自体に意味はない)

require 'spec_helper'

describe Entry do
  it "should create 10 entries" do
    10.times { Factory(:entry) }
    Entry.count.should == 10
  end
end

書いたテストの実行

$ bundle exec rspec spec/models/entry_spec.rb
.

Finished in 0.03308 seconds
1 example, 0 failures

すばらしい!

FactoryGirlで、MongoMapper::Document同士のassociationも問題なく書ける。(ただし、MongoMapper::EmbeddedDocument から 親Documentへのassociationはうまく作ってくれなかった(正格には作ってくれるんだけど、Saveされない))

こんな感じで、Rails 2 + ActiveRecord時代とほとんど変わらない環境が Rails 3 + MongoMapper で、できたかな。