はじめに
adobe/s3mockを使うことでAWS S3をモック化することができます。
ローカル開発環境のDockerにadobe/s3mockを追加することで、実際のAWS S3を利用せずともS3の機能を実現することができます。
導入方法
adobe/s3mockの追加
docker-compose.ymlに下記を追加することでadobe/s3mockを利用することができます。
services:
web:
...
+ s3:
+ image: adobe/s3mock
+ environment:
+ - initialBuckets=my-bucket
+ - retainFilesOnExit=true
+ - root=/s3mock
+ ports:
+ - "9090:9090"
+ volumes:
+ - s3_data:/s3mock
volumes:
+ s3_data:
...
environmentにinitialBucketsを指定することで、最初からバケットを作成しておくことができます。
retainFilesOnExitをtrueに指定し、rootで指定したパスをvolume化することで、
投稿した画像を永続化することができます。
aws-sdk-s3を使用した画像投稿
adobe/s3mockを導入できたので、早速aws-sdk-s3を使用して画像を投稿したいと思います。
まずGemfileにaws-sdk-s3を追加します。
gem 'aws-sdk-s3', '~> 1'
config/initializers/aws.rbなどのファイルを作成して、region, credentialsを設定します。
ローカル環境でadobe/s3mockを使用する場合は、endpointを'http://s3:9090'(s3はdocker-compose.ymlに記載したサービス名)、force_path_styleをtrueに指定します。
AWS上のS3に実際アクセスはしないので、ENV["AWS_ACCESS_KEY"]とENV["AWS_SECRET_ACCESS_KEY"]は適当な値で大丈夫です。
Aws.config.update({
region: 'ap-northeast-1',
credentials: Aws::Credentials.new(ENV["AWS_ACCESS_KEY"], ENV["AWS_SECRET_ACCESS_KEY"])
})
if Rails.env.development?
Aws.config.update({
endpoint: 'http://s3:9090',
force_path_style: true
})
end
動作確認
initialBucketsにmy-bucketを指定しているので、デフォルトでmy-bucketのバケットが作成されていることが確認できます。
s3 = Aws::S3::Resource.new
s3.buckets.each {|b| p b.name }
=> "my-bucket"
画像をアップロードすることもできます。
file_path = Rails.root.join('sample.jpg')
obj = s3.bucket('my-bucket').object('image/sample.jpg')
obj.upload_file(file_path)
署名付URLを発行しアップロードした画像を表示することもできます。
ただし、endpointにhttp://s3:9090を指定しているため、デフォルトでは
http://s3:9090/my-bucket/image/sample.jpg?から始まるURLが発行され
そのままではブラウザから画像を表示することができません。
なので、画像を表示する際にはendpointを'http://localhost:9090'に指定するといいと思います。
client = Aws::S3::Client.new(endpoint: 'http://localhost:9090')
signer = Aws::S3::Presigner.new(client: client)
@url = signer.presigned_url(:get_object, bucket: 'my-bucket', key: 'image/sample.jpg')
=> "http://localhost:9090/my-bucket/image/sample.jpg?から始まるURL"
生成した@urlはimage_tagで実際に表示することができます。
<%= image_tag @url %>
CarrierWaveを使用した画像投稿
Gemfileにcarrierwaveとfog-awsを追加します。
gem 'carrierwave'
gem 'fog-aws'
ローカル環境でadobe/s3mockを使用する場合は、endpointを'http://s3:9090'、force_path_styleをtrueに指定します。
ブラウザから画像を表示することができるよう
config.asset_hostには'http://localhost:9090/my-bucket'を指定します。
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'
CarrierWave.configure do |config|
if Rails.env.development?
config.storage :fog
config.fog_provider = 'fog/aws'
config.fog_directory = 'my-bucket'
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV['AWS_ACCESS_KEY'],
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
region: 'ap-northeast-1',
endpoint: 'http://s3:9090',
path_style: true
}
config.asset_host = 'http://localhost:9090/my-bucket'
end
end
後は、画像を投稿したいモデルに「アップロード画像用のカラム」と「アップローダークラス」を用意し、
アップローダークラスのstorageを:fogにすることでadobe/s3mockを使用した画像投稿が行えます。
storage :fog
ActiveStorageを使用した画像投稿
S3を利用するActiveStorageの設定にすれば大丈夫です。
'aws-sdk-s3'を利用するので、endpointなどの設定はconfig/initializers/aws.rbでしているので追加で設定を行う必要はありません。
config.active_storage.service = :amazon
amazon:
service: S3
access_key_id: <%= ENV["AWS_ACCESS_KEY"] %>
secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>
region: ap-northeast-1
bucket: my-bucket
注意点
ActiveStorageを使用する場合、endpointが'http://s3:9090'のままなので
このままだとブラウザから画像を表示することができません。
なので、ブラウザで画像も表示したい場合はさらにもう一工夫してあげる必要がありそうです。


