LoginSignup
5
8

More than 1 year has passed since last update.

【MinIO】RailsアプリケーションにS3互換ストレージ MinIO を導入してみる

Last updated at Posted at 2022-01-21

はじめに

プライベートでの共同開発において、「開発環境と本番環境の差異をできるだけ少なくしたい」という思いからローカルで動かせるS3互換ストレージを調べていました。業務でfake-s3というサービスを使用したことがありますが、MinIOというサービスも現場で使われている例を発見したのでそちらを導入してみました。

MinIOについて

MinIOとはAWS S3互換のオブジェクトストレージのことです。

  • 特徴
    • ローカルに仮想的な S3 環境を構築できる
    • ローカルの仮想環境なので不用意にAPIを叩いてもお金も掛からない

シナリオ

簡単なアプリを作成した後、MinIOを導入し、投稿した画像がMinIOに格納されるかを確認してみます。

1. アプリの土台を作成する

以下の機能をもつ簡易的なブログアプリを作成する。

  • 記事一覧機能
  • 記事詳細機能
  • 記事投稿機能

動作確認

MinIOを用いない状態で画像を投稿し、storageフォルダにファイルが格納されることを確認する

2. MinIOの導入

提供されているMinIOのdockerイメージを使用してMinIOを導入します。

動作確認

MinIOを導入した状態で画像を投稿し、MinIOのバケットににファイルが格納されることを確認する

1. アプリの土台を作成する

1. こちらの記事を参考にDockerでrailsのアプリケーションを新規作成します。
2. 必要モデルの生成

$ rails g model article

3. マイグレーションファイルの編集
一応タイトルと内容を追加しておきます。

db/migrate/20..._create_articles.rb
class CreateArticles < ActiveRecord::Migration[6.0]
def change
  create_table :articles do |t|
    t.string :title
    t.text :body

    t.timestamps
  end
end
end

4. データベースに反映

$ rails db:migrate

5. 必要コントローラーの生成

$ rails g controller articles

6. ActiveStorageの導入

$ rails active_storage:install
$ rails db:migrate
app/models/article.rb
class Article < ApplicationRecord
has_one_attached :image # 追加
end

7. 必要アクションの定義

app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
# 一覧
def index
  @articles = Article.all
end

# 詳細
def show
  @article = Article.find(params[:id])
end

# 新規投稿画面
def new
  @article = Article.new
end

# 新規投稿
def create
  @article = Article.new(article_params)

  if @article.save
    redirect_to @article
  else
    render :new
  end
end

private
  def article_params
    params.require(:article).permit(:title, :body, :image)
  end
end

8. ルーティングの設定

config/routes.rb
Rails.application.routes.draw do
resources :articles
end

9. viewの作成

app/views/articles/index.html.erb
<h1>Articles</h1>
<%= link_to '新規登録', new_article_path %>

<div>
<ul>
  <% @articles.each do |article| %>
      <li id="article_<%= article.id %>">
        <%= link_to article.title, article %>
      </li>
  <% end %>
</ul>
</div>
app/views/articles/show.html.erb
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>

<p>
<strong>Body:</strong>
<%= @article.body %>
</p>

<p>
<% if @article.image.attached? %>
  <%= image_tag @article.image %>
<% end %>
</p>

<%= link_to 'Back to Articles', articles_path %>
app/views/articles/new.html.erb
<h1>New Article</h1>

<%= form_with model: @article, local: true do |form| %>
<div>
  <%= form.label :title %><br>
  <%= form.text_field :title %>
</div>

<div>
  <%= form.label :body %><br>
  <%= form.text_area :body %><br>
</div>

<div>
  <%= form.label :image %><br>
  <%= form.file_field :image %>
</div>

<div>
  <%= form.submit %>
</div>
<% end %>


<%= link_to 'Back to Articles', articles_path %>

動作確認

1. 新規投稿フォームから画像を投稿してみます。
URL: http://localhost:3000/articles/new
スクリーンショット 2022-01-21 6.11.09.png

2. 投稿詳細画面を確認
URL: http://localhost:3000/articles/1
スクリーンショット 2022-01-21 6.13.44.png

3. ファイルの格納場所を確認
以下の記述によりstorageディレクトリにバイナリファイルが保存される。

config/environments/development.rb
...
config.active_storage.service = :local
...
config/storage.yml
...
local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

スクリーンショット 2022-01-21 6.15.48.png

2. MinIOの導入

1. docker-composeにMinIOの設定を追加する
MinIOのバージョンアップにより指定する環境変数がMINIO_ACCESS_KEYMINIO_SECRET_KEYからMINIO_ROOT_USERMINIO_ROOT_PASSWORDに変更となりました。

docker-compose.yml
version: "3"

services:
db:
  (省略)

web:
  (省略)
minio:
  image: minio/minio:latest
  command: ["server", "/data", "--console-address", ":9001"] # --console-address オプションの追加
  ports:
    - 9000:9000
    - 9001:9001 # コンソール用のポートフォワード設定追加
  volumes:
    - minio:/data
  environment:
    MINIO_ROOT_USER: minio # 元 MINIO_ACCESS_KEY
    MINIO_ROOT_PASSWORD: miniosecret # 元 MINIO_SECRET_KEY

volumes:
mysql-data:
minio:
  driver: local

2. storage.ymlを編集

config/storage.yml
local:
# service: Disk
# root: <%= Rails.root.join("storage") %>

service: S3
access_key_id: "minio"
secret_access_key: "miniosecret"
region: "us-east-1"
endpoint: "http://minio:9000"
bucket: rails-blog-minio
force_path_style: true

3. docker-compose.ymlを編集したのでbuildして再度コンテナ立ち上げる

$ docker-compose up -d --build

4. http://localhost:9001 にアクセスする
スクリーンショット 2022-01-21 7.08.26.png

5. ログイン
docker-compose.ymlに記述したUsername、Passwordを入力すると以下のような画面になります。
この時点ではまだBucketは作成されていません。
minioのコピー.png

6. Bucketの作成
サイドメニューの「Buckets」 → 「Create Bucket」でバケットを作成します。
名前はconfig/storage.ymlbucketで指定したバケット名にします。
スクリーンショット 2022-01-21 7.17.44.png

動作確認

1. 画像を投稿する
この状態で画像を投稿すると以下のようなエラーが発生します.

RuntimeError (Cannot load `Rails.config.active_storage.service`:
Missing service adapter for "S3"):

S3のためのアダプターがないと言われるので以下をGemfileにaws-sdk-s3を追加してinstallします。

Gemfile
gem "aws-sdk-s3", require: false

2. 再度画像を投稿して投稿詳細画面を確認してみます.
正しく画像が表示されていることが分かります。
スクリーンショット 2022-01-21 7.47.55.png

3. MinIOコンソール画面Bucketの中身の確認
以下のようにオブジェクトが一つ格納されていることが確認できます。
スクリーンショット 2022-01-21 7.48.52.png

4. storageディレクトリを確認
ファイルの格納先をMinIOに切り替えたため追加で記事を投稿してもstorageディレクトリに新しくファイルが格納されていません。

※画像の取得ができない場合は/etc/hostsにminioを追加してみてください。

etc/host
...
127.0.0.1       minio
...

おまけ

  • 先ほどはconsole画面から手動でBucketを作成しましたが、dockerを立ち上げた時点で作成されているとより運用しやすいと思うのでdocker-composeを再度編集していきます。
  • {}で示した、MINIO_ROOT_USER, MINIO_PASSWORD, bucket-nameを置き換えて指定してください
docker-compose.yml
version: "3"

services:
  db:
    (省略)

  web:
    (省略)

  minio:
    (省略)

  # ↓ 追加
  createbuckets:
    image: minio/mc
    depends_on:
      - minio
    entrypoint: >
      /bin/sh -c "
      until (/usr/bin/mc config host add myminio http://minio:9000 {MINIO_ROOT_USER} {MINIO_ROOT_PASSWORD} miniosecret) do echo '...waiting...' && sleep 1; done;
      /usr/bin/mc mb myminio/{bucket-name};
      /usr/bin/mc policy download myminio/{bucket-name};
      exit 0;
      "

volumes:
  mysql-data:
  minio:
    driver: local

終わりに

以上で開発環境(ローカル)にいながら本番環境を意識した開発ができるようになりました。

参考

5
8
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
5
8