こんにちは。中山です。
前回、前々回に引き続き、今回も、Amazon Web Services(AWS)を無料で有効活用してみたいと思います。
今回は、いわゆるオンラインストレージサービスである「S3」を使ってみます。
「S3」単体での基本的な利用方法と、それから「EC2」と「S3」の連携についても、実践してみようと思います。
1.「S3」バケットの新規作成と、サンプルファイルのアップロード
1−1.バケットの新規作成
まず「AWS」の「Console Home」ページから、左下あたりの「S3」をクリックします。
表示されたページで「Create Bucket」をクリックします。
「Bucket(バケット)」は、「S3」上でオブジェクトを格納するためのコンテナのことです。
任意のバケット名を指定して「Create」をクリックします。
作成されたバケットの情報が、以下のように表示されます。
このバケット名が、外部からアクセスする場合のドメイン名の一部になります。
例えば東京リージョンの場合、以下のようなドメインでアクセスできることになります。
{バケット名}.s3-website-ap-northeast-1.amazonaws.com
1−2.サンプルファイルのアップロード
「Actions」から「Upload」をクリックします。
「Add Files」でアップロードするファイルを選択したあと、右下の「Start Upload」をクリックします。
先ほど作成したバケット内に、アップロードしたファイルが表示されます。
なお「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」のバケットに保存する。
といったことが簡単にできないものか・・・?
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」をクリックします。
表示されたページ左側の「Roles」をクリックしてページを切り替え、上側の「Create New Role」をクリックします。
「Role Name」に任意の名称(ここでは「ec2」としました)を入力して「Continue」をクリックします。
「Role Type」として、「AWS Service Roles」の中から「Amazon EC2」を選択して「Select」をクリックします。
「Permissions」は、ここでは「Administrator Access」を選択して「Select」をクリックします。
そのまま「Continue」をクリックします。
「Create Role」をクリックします。
以上で「Role」の作成は完了です。今度はこれを、「EC2」インスタンスへ適用してみます。(「IAM Role」について、さらに詳しい情報についてはこちらをご参照ください。)
4.「IAM Role」の「EC2」インスタンスへの適用
「IAM Role」は、すでに生成済みの「EC2」インスタンスには適用することができません(!)。
したがいまして、新たに別の「EC2」インスタンスを生成して、そちらに「IAM Role」を関連づけることにします。
まずは前々回と同じように、「Console Home」の「EC2」のページから、新しい「EC2」インスタンスの作成を開始します。(前々回の記事の「2.EC2 インスタンスの作成」もあわせてご覧ください。)
前々回と同様に、
と選択します。
このあと、最後の「7.Review」ページに行く前に、「3.Configure Instance」ページを表示します。
このページの中ほどの「IAM role」項目のところで、先ほど作成した「Role(今回は「ec2」という名称の Role)」を選択します。
また、既存の「EC2」インスタンスとの区別がつくように、「5.Tag Instance」のページで、「Name」タグにわかりやすい名称を設定しておくことにしましょう。
ここまで完了したところで、再度、前々回と同様に「Security Gruop」を設定し、インスタンスを起動します。
5.「Ruby on Rails」と関連ライブラリのインストール
サンプルアプリを動かす前に、必要な環境を整えておきます。
前回と同様の手順で、「EC2」上に「Ruby on Rails」の動作環境を構築します。(前回の記事の「3.「Ruby on 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
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/
以下のようなページが表示されれば、成功です。
7.サンプルアプリの操作とソースの解析
7−1.サンプルアプリの操作
上記のページから「My Contents」をクリックすると、以下のようなページに切り替わります。
このページで「Upload a new file」をクリックします。
「S3」のバケット名を指定して、アップロードするファイルを指定したあと、「Create Content」をクリックします。
アップロードしたファイルが正しく登録されました。
「S3」のページのほうでも、アップロードしたファイルが正しく登録されていることを確認できます。
「Destroy」をクリックすると、
「S3」のほうからも正しく削除されました。
Access key ID や Secret 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」の連携を実現する場合でも、ソースコードのほうには特別な仕組みは必要ない、ということです。