Rails開発環境のストレージ周りをminioで幸せにする

Adways Advent Calendar 11日目の記事です。

http://blog.engineer.adways.net/entry/advent_calendar/archive


こんにちは、清水です。

普段はRailsでサービス開発を行っているエンジニアです。

みなさん普段の開発環境はどうなっているでしょうか?

AWS??ローカルにVM??Docker??

最近関わるサービスについてはDockerで開発環境を構築するようにしています。

サービス開発で悩ましいのは本番とローカルの環境に差分があることだと思います。
解決方法はいろいろありますが、出来れば大きな変更は入れずに切り分けたいです...

さて、サービスの本番環境はAWSが多いですが、各サービスと開発環境でのマッピングを考えると...

サービス 本番環境(AWS) 開発環境(Docker)
データストア RDS MySQL
キャッシュ ElastiCache or EC2 Redis
Webサーバ Nginx on EC2 Nginx
ストレージ S3 ???

ストレージ部分が ??? ですね。

アップロードされたファイルの扱いに困っていました。ローカルのストレージに入れるのもいいのですが、長らく自分の中でコレ!というものが決まっていませんでした。

そこで、使い始めたのがminioです。 Go製のオブジェクトストレージサーバです。

  • S3互換(大事)
  • 簡単に構築できる(大事)
  • Web UI(うれしい)

Web UIは LIVE DEMO もあります。

S3互換のおかげで、Railsの画像アップロードによく使われる paperclipcarrierwave からも簡単に使うことができます。

Railsをサンプルに使ってみましょう。

docker-composeから一気に起動します。

# cat docker-compose.env
... snip
MINIO_ACCESS_KEY=[access key を入れてください]
MINIO_SECRET_KEY=[secret key をいれてください]

# cat docker-compose.yml
---
version: '2'
services:
  datastore:
    build: containers/datastore
    container_name: minio-sample-container
  minio:
    build:
      context: .
      dockerfile: Dockerfile-minio
    ports:
      - '9000:9000'
    command: [server, /minio]
    volumes_from:
    - datastore
    env_file:
    - ./docker-compose.env
  mysql:
    image: mysql:5.6.35
    command: mysqld --character-set-server=utf8
    env_file:
    - ./docker-compose.env
    ports:
    - '3306:3306'
    volumes_from:
    - datastore
  rails:
    build: .
    depends_on:
    - minio
    - mysql
    ports:
      - '3000:3000'
    env_file:
    - ./docker-compose.env
    environment:
      RAILS_ENV: docker
    volumes:
    - .:/usr/src/app
    volumes_from:
    - datastore
    links:
      - minio
      - mysql

# docker-compose up -d

dockerと通信できるIPにポート9000でアクセスすると

f:id:AdwaysEngineerBlog:20161215173309p:plain

(minioにはCLIツールとして mc というものもあり、WebUIに頼らなくても操作できて便利です。)

bucketを作ったり、bucketへの権限を変更できます。Railsから参照するバケットの作成と参照権限を与えておきます(minio-sample としました)。

これで準備ができたので、それぞれの設定を追加していきます。

paperclip の場合

RAILS_ENV=docker での起動時の設定を追加します。

# config/initializers/paperclip.rb
PAPERCLIP_OPTS = case Rails.env
  when 'docker'
    {
      image: {
        styles: {
          original: '1920x1680>',
        },
        storage: :s3,
        s3_protocol: :http,
        s3_region: 'us-east-1', # 固定
        s3_credentials: "#{Rails.root}/config/s3.yml",
        s3_host_name: 'localhost:9000', # 環境に合わせて変更します
        s3_options: {
          endpoint: 'http://minio:9000',
          force_path_style: true,
        },
        path: ":attachment/:id/:style.:extension",
        url: ':s3_path_url',
      }
    }
  else
    # 他の環境の分をここに
  end

モデル側は

has_attached_file :image, PAPERCLIP_OPTS[:iamge]

気をつける点として s3_options にある force_path_style を忘れないようにします。

ファイルのPUT先のエンドポイントが

ttp://minio-sample.minio:9000 -> ttp://minio:9000/minio-sample

に変わります。

carrierwave の場合

# config/initializers/carrierwave.rb
CarrierWave.configure do |config|

  case Rails.env
    when 'docker'
      config.fog_credentials = {
        provider: 'AWS',
        aws_access_key_id: ENV['MINIO_ACCESS_KEY'],
        aws_secret_access_key: ENV['MINIO_SECRET_KEY'],
        region: 'us-east-1',
        endpoint: 'http://minio:9000',
        path_style: true,
      }
      config.asset_host = 'http://localhost:9000/minio-sample-carrierwave'
      config.fog_directory = 'minio-sample-carrierwave'
    else
    # 他の環境をここに
  end
end

paperclipとほとんど同じ設定でいけます。

まとめ

minioのおかげで開発環境のほとんどをDockerの中に閉じ込めることができました。

データはdockerのコンテナに閉じ込めているので、worktreeが違う場所でも同様のデータが参照できるようになったのでとても便利です。


上記の設定を入れたリポジトリが こちら になります。

(アップロードする画面も作っていません...)

(docker-for-macを使用して作成しているので、hostなどは適宜変更してください)


次は本間さんの記事です。

http://blog.engineer.adways.net/entry/advent_calendar/12