RailsのセッションストアにRedisを使う

レプリケーションとかが簡単そうなセッションストアということでRedisを使ってみることにした。

Redisのインストール

まずはRedisのセットアップから。
Chefで。ひとまずVagrantの環境に対して。

RedisのCookbook

ふたつ見つけた。

READMEの設定例などが親切だったので、とりあえずredisioの方を使ってみることにした。

Berksfileの編集

いつものごとくBerkshelfを使う。

cookbook 'redisio'
Vagrantfileの編集
chef.add_recipe "redisio::install"
chef.add_recipe "redisio::enable"

Vagrantのバージョンは1.3.5。

Vagrantへの反映
vagrant provision

こんなかんじでRedisのインストールはあっさりと完了すた。

redis-rails

次はセッションストアにRedisを使うためのRails側の設定。
redis-railsを使う。

Gemfileの編集
gem 'redis-rails'

bundle installしたらredis-railsのREADMEの通りに設定ファイルを編集。
一見あっさりとうまくいった。でもなんだかexpires_inとかがうまく働かないのでドキュメントを参考にしつつもいろいろ試して、結果として次のようにした。なんだかREADMEが更新されてないような気がする。

config/environments/initializers/session_store.rb
RedisRailsExample::Application.config.session_store :redis_store, expire_after: 60.minutes, servers: { 
  host: "localhost", 
  port: 6379, 
  namespace: "sessions"
}

development.rbやproduction.rbなどに書いてもいい。

Redisの認証

開発環境はこれでいいとして、本番では認証入れないとまずいよな、ということでやり方を模索。
Redisにパスワードを設定してこれをRailsから使うのに試行錯誤したが、実はRedisの設定で接続を許可するホストを限定するか、iptablesでアクセス制御するのが一般的なようだ。(そうだよね?)

なのでここから下はすごくいらないっぽいけど、せっかくやったので書いておく。
(そもそも無理にinitializers以下でやらなくてもdevelopment.rbやproduction.rbとかに書いてしまえばいいよね)

Vagrantfileの編集

Redisの設定を変更してパスワードを設定する。

chef.json = {
  :redisio=> {
    :default_settings => {:requirepass => ["hujiko"]}
  },
}

これでvagrant provisionするとパスワードが設定される。

ただし手動でRedisを再起動する必要があった。redisioが不親切なのか、こっちが何か悪いのか分からない。

config/environments/initializers/session.rb
RedisRailsExample::Application.config.session_store :redis_store, servers: { 
  host: "localhost", 
  port: 6379, 
  namespace: "cache", 
  password: "hujiko", 
  expires_in: 90.minutes  
}

しかしこれだと環境ごとに設定できないという問題が。

このあたりを参考にdevelopment.rbで色々と試したがだめだった。
だめだったリスト。

# 1. config.cache_store = :redis_store, 'redis://localhost:6379/0/cache', { password: 'hujiko', expires_in: 90.minutes }
# 2. config.cache_store = :redis_store, { :host => "localhost", :port => 6379, :db => 0, :password => "hujiko", :namespace => "cache", :expires_in => 90.minutes }
# 3. config.cache_store = :redis_store, { servers: { host: "localhost", port: 6379, db: 0, password: "hujiko", namespace: "sessions", expires_in: 90.minutes } }

環境ごとの認証設定

このあたりを参考に環境ごとにRedisの設定をできるようにする。

config/environments/initializers/session.rb
redis_store_config_file = File.join(Rails.root,'config','redis_store.yml')
raise "#{redis_store_config_file} is missing!" unless File.exists? redis_store_config_file
redis_store_config = YAML.load_file(redis_store_config_file)[Rails.env].symbolize_keys

RedisRailsExample::Application.configure do 
  config.session_store :redis_store, servers: { 
    host: redis_store_config[:host], 
    port: redis_store_config[:port], 
    namespace: redis_store_config[:namespace], 
    password: redis_store_config[:password], 
    expires_in: redis_store_config[:expires_in]  
  }
end
config/redis_store.yml
# Redis session store settings
development:
  host: localhost
  port: 6379
  namespace: sessions
  password: hujiko
  expires_in: 86400

test:
  host: localhost
  port: 6379
  namespace: sessions
  password: hujiko
  expires_in: 86400

staging:
  host: localhost
  port: 6379
  namespace: sessions
  password: hujiko
  expires_in: 86400

production:
  host: localhost
  port: 6379
  namespace: sessions
  password: hujiko
  expires_in: 86400

これで環境ごとにRedisサーバーを設定できるようになった。

なお繰り返し言うけど、パスワード不要ならこんなことせずに普通にdevelopment.rbとかproduction.rbとかに書けばいい。

TODO

* レプリケーション
* フェイルオーバー