LoginSignup
10
10

More than 3 years have passed since last update.

LocalStack で Rails による S3 の投稿をモックする

Last updated at Posted at 2020-05-26

LocalStack は、AWS のサービスを開発環境において擬似的に使用できるモックフレームワークです。
定番の S3 から Lambda まで多くのサービスを開発環境で体験できます。

本記事では、Railsチュートリアルの SampleApp を使用し、コンテナ環境で実装します。
コンテナの設定は、Railsチュートリアルの開発環境を Docker でもっと便利にしなイカ!? - Qiitaの続きとなります。

今回の実装コードは右の通りです=>(実装コード --github)



□ LocalStack の設定

■ コンテナの追加

  • version 0.11.0 からhttp://localhost:4566で全ての endpoint を受け付けている。
  • SERVICESにより、モックするサービスを定義する。
  • DATA_DIR: /tmp/localstack/dataにより、投稿画像を永続化する。
  • volumesで設定したディレクトリにスクリプトを配置すると、コンテナ生成時に実行してくれる( 詳細は後述 )。
  • なお、access key 等を設定する必要はない。
./docker-compose.yml
  ...
  smtp:
    ...
+ localstack:
+   image: localstack/localstack
+   ports:
+     - 8080:8080 # dashboard
+     - 4566:4566 # edge port
+   environment:
+     SERVICES: s3
+     AWS_DEFAULT_REGION: ap-northeast-1
+     DATA_DIR: /tmp/localstack/data
+   volumes:
+     - ./docker/localstack/:/docker-entrypoint-initaws.d
  volumes:
    ...

■ 初期設定スクリプト

S3 保存用のバケットを生成する必要があるため、次のファイルを作成すること。

./docker/localstack/setup_s3.sh
awslocal s3 mb s3://microposts

□ 既存ファイルの修正

■ 保存場所を S3 に固定

app/uploaders/picture_uploader.rb
class PictureUploader < CarrierWave::Uploader::Base
  ...
- if Rails.env.production?
-   storage :fog
- else
-   storage :file
- end
+ storage :fog
  ...
end

■ carrier_wave の初期設定を変更

config/initializers/carrier_wave.rb
CarrierWave.configure do |config|
  config.fog_credentials = {
    :provider              => 'AWS',
    :region                => ENV['S3_REGION'],
    :aws_access_key_id     => ENV['S3_ACCESS_KEY'],
    :aws_secret_access_key => ENV['S3_SECRET_KEY'],
  }
  config.fog_directory     =  ENV['S3_BUCKET']

  unless Rails.env.production?
    config.fog_credentials.merge!(
      {
        # [app -> localstack] コンテナ間の通信用に設定 ( http://localstack:4566 )
        :endpoint          => ENV['S3_ENDPOINT'],

        # デフォルトだと S3_BUCKET がサブドメインとなり接続できないため true に設定
        :path_style        => true,
      }
    )

    # endpoint がコンテナ間の通信用であるため、ホスト側から画像にアクセスするための URL ( http://localhost:4566 )
    config.asset_host = "#{ENV['S3_ASSET_HOST']}/#{ENV['S3_BUCKET']}"
  end
end

■ 環境変数の設定

./docker-compose.yml
  ...
  app:
    ...
    environment:
      APP_DATABASE_HOST: db
      APP_DATABASE_USERNAME: root
      APP_DATABASE_PASSWORD: pass
+     S3_REGION: ap-northeast-1
+     S3_ACCESS_KEY: dummy
+     S3_SECRET_KEY: dummy
+     S3_BUCKET: microposts
+     S3_ENDPOINT: http://localstack:4566
+     S3_ASSET_HOST: http://localhost:4566
    ...

□ テスト投稿

投稿前
スクリーンショット 2020-05-26 22.44.38.png
投稿成功!
スクリーンショット 2020-05-26 22.46.07.png

□ 余談: 投稿画像の永続化

前述の通りDATA_DIRを追加すると、投稿画像の永続化が可能となるが、コンテナ停止再起動でのみ有効となる。
もし、コンテナ削除時でもデータを保持したい場合、次の通り設定すること。

また、この設定の場合、意識的に volume を削除しないと保存容量が膨れ上がるため、注意する必要あり。

./docker-compose.yml
services:
  datastore:
    image: busybox
    volumes:
      - bundle_install:/usr/local/bundle
      - db_data:/var/lib/postgresql/data
+     - localstack_data:/tmp/localstack
...
  localstack:
    image: localstack/localstack
    ports:
      - 8080:8080 # dashboard
      - 4572:4572 # s3
    environment:
      SERVICES: s3
      AWS_DEFAULT_REGION: ap-northeast-1
      DATA_DIR: /tmp/localstack/data
    volumes:
      - ./docker/localstack/:/docker-entrypoint-initaws.d
+     - localstack_data:/tmp/localstack
volumes:
  bundle_install:
  db_data:
+ localstack_data:

□ メモ

コンテナから S3 保存を確認

docker-compose exec localstack ash

aws --endpoint-url=http://localstack:4572 s3 ls s3://${バケット名}

S3 に保存したファイルをコンテナ内にダウンロード

docker-compose exec localstack ash

aws --endpoint-url=http://localstack:4572 s3 cp #{key} ~/
cat ~/#{key}

ブラウザからファイルを確認

open http://localhost:4572/#{バケット名}

# TODO: ファイルの中身は 403 によりアクセス不可,何かしら設定が必要なはず
open http://localhost:4572/#{key}
10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10