Intelligent Technology's Technical Blog

株式会社インテリジェントテクノロジーの技術情報ブログです。

無料で活用!AWS - S3 + EC2 + AWS SDK for Ruby -

こんにちは。中山です。

前回前々回に引き続き、今回も、Amazon Web ServicesAWS)を無料で有効活用してみたいと思います。

今回は、いわゆるオンラインストレージサービスである「S3」を使ってみます。
「S3」単体での基本的な利用方法と、それから「EC2」と「S3」の連携についても、実践してみようと思います。

1.「S3」バケットの新規作成と、サンプルファイルのアップロード

1−1.バケットの新規作成

まず「AWS」の「Console Home」ページから、左下あたりの「S3」をクリックします。
f:id:IntelligentTechnology:20140522175012p:plain:w520

表示されたページで「Create Bucket」をクリックします。
Bucket(バケット)」は、「S3」上でオブジェクトを格納するためのコンテナのことです。
f:id:IntelligentTechnology:20140522175144p:plain:w560

任意のバケット名を指定して「Create」をクリックします。
f:id:IntelligentTechnology:20140522175736p:plain:w560

作成されたバケットの情報が、以下のように表示されます。
f:id:IntelligentTechnology:20140523100322p:plain:w560

このバケット名が、外部からアクセスする場合のドメイン名の一部になります。
例えば東京リージョンの場合、以下のようなドメインでアクセスできることになります。

{バケット名}.s3-website-ap-northeast-1.amazonaws.com

 

1−2.サンプルファイルのアップロード

「Actions」から「Upload」をクリックします。
f:id:IntelligentTechnology:20140523101038p:plain:w560

Add Files」でアップロードするファイルを選択したあと、右下の「Start Upload」をクリックします。
f:id:IntelligentTechnology:20140523102758p:plain:w560

先ほど作成したバケット内に、アップロードしたファイルが表示されます。
f:id:IntelligentTechnology:20140523103001p:plain:w560

なお「S3」は、無料期間中は

  • 5GB の標準ストレージ
  • 20,000 回までの Get リクエスト(1ヵ月あたり)
  • 20,000 回までの Put リクエスト(1ヵ月あたり)

の無料利用枠が設定されているようです。(参考
※Get/Putリクエスト数の合計については、AWSの「Console Home」の「Billing」ページから詳しく確認することができるようです。

無料活用ポイント!その1

「S3」、無料なのは 5GB まで。

 

2.「EC2」と「S3」との連携

2−1.S3 をもっと便利に使いたい

「S3」を単体で使う場合は、とても簡単に、直感的に操作できそうです。
しかし本当は、もっと「S3」を活用してみたい。例えば、

「EC2」上の Web アプリケーションでアップロードされたファイルを、自動的に「S3」のバケットに保存する。

といったことが簡単にできないものか・・・?

実は、できるのです。これを解決するためのキーワードが、「AWS SDK」です。
 

2−2.AWS SDK

AWS SDK」とは、「EC2」「S3」などの AWS のサービスを、プログラムから便利に利用するためのライブラリです。
利用するプログラミング言語ごとに「AWS SDK for Ruby」「AWS SDK for PHP」「AWS SDK for Java」などが用意されています。

今回は、「Ruby on Rails」アプリケーションで動作を試してみますので、「AWS SDK for Ruby」を使うことにしました。
 

2−3.「Access key ID」と「Secret access key」による認証が必要?

「EC2」などの別のサーバから、「AWS SDK」を用いて「S3」の機能を利用する場合、「S3」へアクセスするための認証処理が必要となります。
この認証処理を行うために、あらかじめ設定しておいた

というキーを用いる、という方法がひとつあるようです(参考)。

これらのキーは、以下のようにコンソールから変数として定義したり、

$ export AWS_ACCESS_KEY_ID={your_access_key_id}
$ export AWS_SECRET_ACCESS_KEY={your_secret_access_key}

また、以下のようにプログラム内に直接指定したりします。

AWS.config(
  :access_key_id => '{your_access_key_id}',
  :secret_access_key => '{your_secret_access_key}')

しかし、毎回これらのキーを設定するのはわずらわしく、またキーの流出の危険もあります。

これを解決するため、上記のキーを使う代わりに、

この「EC2」インスタンスに対しては、「S3」へのアクセスを常に許可しておきますよ

という設定を、あらかじめ定義しておくことができます。これが「IAM Role」です。
 

3.「IAM Role」の新規作成

AWS」の「Console Home」ページから、まんなかあたりの「IAM」をクリックします。
f:id:IntelligentTechnology:20140523133659p:plain:w520

表示されたページ左側の「Roles」をクリックしてページを切り替え、上側の「Create New Role」をクリックします。
f:id:IntelligentTechnology:20140523134422p:plain:w560

「Role Name」に任意の名称(ここでは「ec2」としました)を入力して「Continue」をクリックします。
f:id:IntelligentTechnology:20140523134542p:plain:w480

「Role Type」として、「AWS Service Roles」の中から「Amazon EC2」を選択して「Select」をクリックします。
f:id:IntelligentTechnology:20140523140222p:plain:w480

「Permissions」は、ここでは「Administrator Access」を選択して「Select」をクリックします。
f:id:IntelligentTechnology:20140523140637p:plain:w480

そのまま「Continue」をクリックします。
f:id:IntelligentTechnology:20140523140826p:plain:w480

Create Role」をクリックします。
f:id:IntelligentTechnology:20140523140929p:plain:w480

以上で「Role」の作成は完了です。今度はこれを、「EC2」インスタンスへ適用してみます。(「IAM Role」について、さらに詳しい情報についてはこちらをご参照ください。)
 

4.「IAM Role」の「EC2」インスタンスへの適用

「IAM Role」は、すでに生成済みの「EC2」インスタンスには適用することができません(!)。
したがいまして、新たに別の「EC2」インスタンスを生成して、そちらに「IAM Role」を関連づけることにします。

まずは前々回と同じように、「Console Home」の「EC2」のページから、新しい「EC2」インスタンスの作成を開始します。(前々回の記事の「2.EC2 インスタンスの作成」もあわせてご覧ください。)

前々回と同様に、

  • Amazon Machine Image(AMI)」=「Amazon Linux AMI」
  • 「Instance Type」=「Micro instances」

と選択します。
このあと、最後の「7.Review」ページに行く前に、「3.Configure Instance」ページを表示します。
f:id:IntelligentTechnology:20140523151240p:plain:w560

このページの中ほどの「IAM role」項目のところで、先ほど作成した「Role(今回は「ec2」という名称の Role)」を選択します。

また、既存の「EC2」インスタンスとの区別がつくように、「5.Tag Instance」のページで、「Name」タグにわかりやすい名称を設定しておくことにしましょう。
f:id:IntelligentTechnology:20140523151621p:plain:w560

ここまで完了したところで、再度、前々回と同様に「Security Gruop」を設定し、インスタンスを起動します。
 

5.「Ruby on Rails」と関連ライブラリのインストール

サンプルアプリを動かす前に、必要な環境を整えておきます。
前回と同様の手順で、「EC2」上に「Ruby on Rails」の動作環境を構築します。(前回の記事の「3.「Ruby on Rails」と関連ライブラリのインストール」もあわせて参考にしてください。)

5−1.「Ruby on Rails」のインストール

「EC2」のコンソールから、以下のコマンドを実行します。

$ sudo gem install rails

 

5−2.関連ライブラリのインストール

以下コマンドを実行します。

$ sudo yum install ruby-devel
$ sudo yum install gcc
$ sudo yum install sqlite-devel
$ sudo yum install gcc-c++

 

5−3.「Git」のインストール

以下コマンドを実行します。

$ sudo yum install git

 

5−4.「AWS SDK for Ruby」が必要とするライブラリのインストール

AWS SDK for Ruby」が必要とするライブラリをインストールするために、以下コマンドを実行します。

$ sudo yum install libxml2-devel
$ sudo yum install libxslt-devel

 

6.「Ruby on Rails」サンプルアプリケーションの実行

6−1.サンプルアプリのソース取得

今回のサンプルアプリは、「EC2」上で稼働させて、

このサンプルアプリに対してアップロードされたファイルを、自動的に「S3」のバケットに保存する。

という機能を提供するものです。

まずは「Ruby on Rails」アプリ用のフォルダ(ここでは「rails」フォルダ)を作成しておきます。

$ pwd
/home/ec2-user
$ mkdir rails
$ cd rails

サンプルアプリのソースは、あらかじめ登録しておいた「GitHub」のリポジトリから取得することにします。

$ git clone https://github.com/hatena-iti/uploader.git
$ cd uploader

 

6−2.サンプルアプリの設定

サンプルアプリに必要なパッケージをインストールします。以下のコマンドを実行します。

$ bundle install

もし以下のようなメッセージが表示された場合、

An error occurred while installing nokogiri (1.6.2.1), 
and Bundler cannot continue.

以下コマンドを実行します。

$ bundle config build.nokogiri --use-system-libraries
$ bundle install

 
次に、サンプルアプリのデータベースのマイグレーションを行います。以下のコマンドを実行します。

$ rake db:migrate

 

6−3.secrets.yml の作成

サンプルアプリ用の「secrets.yml」ファイルを手動で作成します。(前回の記事の「4−3.secrets.yml の作成」もご参照ください。)

$ cd config
$ cp -p secrets.yml.sample secrets.yml

 
以下のコマンド

$ rake secret

で生成した値を、「config/secrets.yml」内の「secret_key_base」項目の値として貼付けます。

できあがった「config/secrets.yml」ファイルは、例えば以下のような内容となります。

development:
  secret_key_base: eac8dd0e8eb50b30e94260759c4e147b9284d741799137dd3634a013519735bff4419bad647f02ec558c5cf16a86923d8c793672ec2dd6797219ee63********

test:
  secret_key_base: af3ef6d80a23b3b71866cd575f0de272fdd24e67f60841234e8e9f7c2009cf928d95e7b1bd72badb11de3b7de95e3beca119e297053efac1c92ae11a********

production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

 

6−4.サンプルアプリの実行

以下のコマンドを実行します。

$ rails server

ブラウザから、以下の URL にアクセスします。

http://{EC2 インスタンスの Public IP}:3000/

 
以下のようなページが表示されれば、成功です。
f:id:IntelligentTechnology:20140523164701p:plain:w520
 

7.サンプルアプリの操作とソースの解析

7−1.サンプルアプリの操作

上記のページから「My Contents」をクリックすると、以下のようなページに切り替わります。
このページで「Upload a new file」をクリックします。
f:id:IntelligentTechnology:20140523164922p:plain:w520

「S3」のバケット名を指定して、アップロードするファイルを指定したあと、「Create Content」をクリックします。
f:id:IntelligentTechnology:20140523165141p:plain:w520

アップロードしたファイルが正しく登録されました。
f:id:IntelligentTechnology:20140523165413p:plain:w520

「S3」のページのほうでも、アップロードしたファイルが正しく登録されていることを確認できます。
f:id:IntelligentTechnology:20140523181025p:plain:w560

「Destroy」をクリックすると、
f:id:IntelligentTechnology:20140523165413p:plain:w520

「S3」のほうからも正しく削除されました。
f:id:IntelligentTechnology:20140523165844p:plain:w560

Access key IDSecret access key を設定しなくても、「EC2」と「S3」との連携を実現することができました。
 

7−2.ソースの解析

今回のサンプルアプリでのポイントは、そんなに多くはありません。
まずは「Gemfile」。

・・・
# Use AWS SDK for Ruby
gem "aws-sdk"

ここでは、「AWS SDK for Ruby」を利用するための設定を追加しています。

次は「app/controllers/contents_controller.rb」。

class ContentsController < ApplicationController
  ・・・

  # コンテンツの新規追加リクエスト時に呼び出されるメソッド
  def create
    @content = Content.new(content_params)
    upload_file = params[:content][:upload_filename]

    # S3 インスタンスの取得
    s3 = AWS::S3.new

    # 指定されたバケットの取得
    b = s3.buckets[@content.s3_bucket]

    # アップロードされたファイルを S3 のバケットに登録
    # 登録するファイルには、:public_read 属性を指定して、ファイルの読み取りを公開する
    o = b.objects[upload_file.original_filename]
    o.write(upload_file.read, :acl => :public_read)

    ・・・
  end

  ・・・

  # コンテンツの削除リクエスト時に呼び出されるメソッド
  def destroy
    @content = Content.find(params[:id])

    # S3 インスタンスの取得
    s3 = AWS::S3.new

    # 対象バケットの取得
    b = s3.buckets[@content.s3_bucket]

    # 対象ファイルを S3 の該当バケットから削除
    o = b.objects[@content.filename]
    o.delete()

    ・・・
  end

  ・・・
end

コンテンツの新規追加、または削除のリクエスト時に呼び出されるメソッドの中で、「AWS SDK for Ruby」が提供する「AWS::S3」クラスを用いて、「S3」へのファイル登録や削除の操作を実現しています。
ポイントとしては、「IAM Role」を使って「EC2」と「S3」の連携を実現する場合でも、ソースコードのほうには特別な仕組みは必要ない、ということです。
 

8.まとめ

「EC2」と「S3」の連携も、「AWS SDK」を使うことで、これまた容易に実現できてしまいました。

また、「AWS SDK」を利用する方法のほかにも、「S3」を直接ファイルシステムとしてマウントすることもできるみたいですね。(参考:FuseOverAmazon s3fs
AWS、至れり尽くせりすぎて、恐ろしい!

最近値下げもあったようなので、ますます使わない理由が見つからなくなってきております。