Amazon Web Services入門: PHPとEC2/S3/SQS/SimpleDBで作るビデオ共有サイト
Tweet
新年あけましておめでとうございます、五十川です。
PHPデベロッパー向けのAmazon Web Services(AWS)のリソースはhttp://aws.amazon.com/php/にまとめられていますが、そのArticles & Tutorialsカテゴリーにある、Introduction to AWS for PHP Developersという記事は、AWSの主要サービスの概要と、PHPによるその操作を学ぶチュートリアルで、ここで取り上げられているサービスに初めて取り組むPHPデベロッパーには格好の入門となっており、ここではこのチュートリアルを紹介したいと思います。
また、このチュートリアルはAmazon純正のライブラリを利用していますが、AWS用のライブラリには様々なものがあり、この記事の最後ではそのひとつ、CloudFusionを紹介しようと思います。
なお、以下のチュートリアルのスクリプトの実行には、もちろんAWSアカウントが必要で、スクリプトの実行に応じてAWSの利用料が課金されます。チュートリアルには、例えば起動したEC2インスタンスを停止(Terminate)するなど、余計な課金がされないようにする手順は説明されていませんので、AWS Consoleや各種デベロッパーツールを利用して(あるいはチュートリアルの復習も兼ねて、そうしたプログラムを自作するなどして)、適宜対処してください。
チュートリアルのシナリオ
チュートリアルはビデオ共有サイトを題材にしており、AWSのうち、EC2、S3、SQS、SimpleDBを利用します。
- ウェブサーバはEC2でホストされる
- ユーザは任意の形式のビデオをサイトのファイルアップロードフォームからアップロードできる
- アップロードされたビデオはS3に保存され、SQSで管理されるバッチプロセスでFLVに変換される
- 変換されたビデオはS3に保存され配信される
- ビデオのメタデータはSimpleDBに記録される
一般的なビデオ共有サイトでは、ユーザから投稿される様々な形式のビデオを、共通の形式(一般的にFLV)に変換して視聴に供します。ビデオの変換は相応のリソースと時間を消費するため、バッチプロセスで処理され、キューシステムで管理されますが、チュートリアルではここにSQSを採用しています。また、バッチプロセスをウェブサーバとは別のコンピュータ(EC2インスタンス)に分離し、さらにそれらが複数に分散されることを想定し、変換前後のビデオはS3に保存します。
チュートリアルの著者について
チュートリアルの著者は、Feedsterを経て現在はAPIのマネージメントサービスを提供するMasheryのチーフアーキテクトを務めるClay Lovelessさんです。彼はオライリーのPHP Cookbook Second Editionの4つの章の著者であり、かつて存在していたpearified.comの運営者でもありました。また、このチュートリアルで使われるS3のストリームラッパー実装(Killersoft_Wrapper_S3)とSOAPクライアント(AWSSoapClient)は彼自身の手によるものです。
チュートリアルファイルのダウンロード
http://s3.killersoft.com/AWSforPHP/awsfiles.zip
チュートリアルのPHPスクリプトは、バージョン5.1.2以上のPHPでの実行を前提にしています。チュートリアルファイル中のcompatibility.phpで動作要件を確認できます。
チュートリアルはAmazon純正の以下のライブラリを利用します。
チュートリアルファイルにはこれらのライブラリが含まれていますが、それらはチュートリアルが執筆された時点のバージョンのものであり、最新のものではありません。当然、対象となるAPIバージョンもチュートリアルの執筆時点のものとなっている点に注意してください。
設定ファイルの作成
チュートリアルは/etc/aws.confファイルに保存された設定情報を利用します。
/etc/aws.confファイルに、Security Credentialsで表示されるAccess Key IDとSecret Access Key、及びAccount Numberを、以下の書式で記述します。
; AWS Security Credentials ; Access Key ID access_key = "06224BHAZ75910F2" ; Secret Access Key secret_key = "aIfbA2568+12TEqLDYpiqOyRULvi9" ; Account Number account_id = "123412341234"
さらに/etc/aws.confファイルに、チュートリアルのPHPスクリプトが作成するファイルを保存するディレクトリのパスを、以下の書式で追記しておきます。
; Path to writable directory where we can save files tutorial_file_path = "/tmp"
接続の確認
チュートリアルの最初に登場するPHPスクリプトは、avail-zones.phpです。このスクリプトは、EC2のゾーンの利用可否を問い合せるDescribeAvailabilityZonesリクエストを発行します。
$ php avail-zones.php <?xml version="1.0"?> <DescribeAvailabilityZonesResponse xmlns="http://ec2.amazonaws.com/doc/2008-05-05/"> ...
このスクリプトは最もプリミティブなRESTリクエストの作成例で、外部ライブラリに依存せずにURLをいちから組み立てています。そのため、スクリプトの実行で、/etc/aws.confファイルに記述したSecurity Credentialsの正当性が確認できるとともに、そのソースを読み解くことで、RESTリクエストのURLの構成、特にその署名(Signature)の作成方法が把握できるようになっています。
SOAPリクエスト
すべてのAWSはRESTとSOAPの両インタフェースで利用できます。チュートリアルは基本的にRESTを利用しますが、一部のスクリプトにはそのSOAP版も用意されています。
SOAPリクエストではX.509 Certificateが必要になります。Security CredentialsでX.509 Certificateを設定後、/etc/aws.confファイルに、cert-....pemファイルとpk-....pemファイルのパスを以下の書式で追記します。SOAPを利用しない場合は、この手順は不要です。
; X.509 Certificate Path cert_file = "/path/to/my/cert-....pem" ; RSA private key private_key_file = "/path/to/my/pk-....pem"
avail-zones-soap.phpは、avail-zones.phpのSOAP版です。
$ php avail-zones-soap.php us-east-1a: available ...
これ以降に登場するチュートリアルのPHPスクリプトはその冒頭でexample_setup.phpをインクルードしています。このexample_setup.phpは、/etc/aws.confファイルから設定情報を読み込み、あわせて各スクリプトが利用するクラスライブラリ用のオートロードを定義しています。
EC2インスタンスの起動
初めてチュートリアルに取り組む際は、実際にEC2インスタンスを起動する前に、まずec2-prelaunch.phpを実行して、キーペアの作成とセキュリティグループの設定を行います。
ec2-prelaunch.php
- DescribeKeyPairsリクエストで「awstutorial」キーペアの存在を確認
- キーペアが存在しない場合、CreateKeyPairリクエストでキーペアを作成し、プライベートキーを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「id_rsa-awstutorial」ファイルに保存
- DescribeSecurityGroupsリクエストで「awstutorial」セキュリティグループの存在を確認
- グループが存在しない場合、CreateSecurityGroupリクエストでグループを作成
- グループの設定でポート80とポート22が開放されていない場合、AuthorizeSecurityGroupIngressリクエストでポートを開放
$ php ec2-prelaunch.php Creating awstutorial keypair... generated fingerprint f3:e4:e6:c8:92:dd:f1:52:be:ea:a3:9d:75:57:ba:65:61:a7:a3:28 generated material -----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY----- Creating awstutorial security group ...done. Opening awstutorial port 80 ...done. Opening awstutorial port 22 ...done.
ec2-launch.phpを実行すると実際にEC2インスタンスが起動します。
ec2-launch.php
- RunInstancesリクエストで、ID「ami-2b5fba42」のAMI(Fedora Core 8)のインスタンスを起動し、そのインスタンスIDを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-instance.txt」ファイルに保存
- パブリックDNS名(ホスト名)が割り振られるまで、DescribeInstancesリクエストを定期的に実行し、パブリックDNS名が割り振られたらそれを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-hostname.txt」ファイルに保存
$ php ec2-launch.php Launching awstutorial instance. i-b98db8d1 is pending Waiting for public hostname........................... i-b98da8d1 is running at ec2-75-101-188-56.compute-1.amazonaws.com Instance booted in 76.150985002518 seconds.
EC2インスタンスの設定
/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリに移動し、ec2-prelaunch.phpスクリプトとec2-launch.phpスクリプトの実行によって保存されたファイルを使って、必要な環境変数を設定します。
$ cd /tmp $ export AWSTUTORIAL_HOST=`cat \`pwd\`/awstutorial-hostname.txt` $ export AWSTUTORIAL_KEY=`pwd`/id_rsa-awstutorial
/etc/aws.confファイルをEC2インスタンスにアップロードし、インスタンス上でチュートリアルのスクリプトを実行する環境を整えます。
$ scp -i $AWSTUTORIAL_KEY /etc/aws.conf root@$AWSTUTORIAL_HOST:/etc/aws.conf
$ ssh -i $AWSTUTORIAL_KEY root@$AWSTUTORIAL_HOST \
'curl -O http://s3.killersoft.com/AWSforPHP/awsfiles.zip; \
unzip awsfiles.zip -d /var/www/'
$ scp -i $AWSTUTORIAL_KEY awstutorial-*.txt root@$AWSTUTORIAL_HOST:/tmp/
インスタンスにSSHログインします。
$ ssh -2 -i $AWSTUTORIAL_KEY root@$AWSTUTORIAL_HOST
インスタンス上で、PHPとApacheのインストールを行います。
# yum -y install php \
php-mcrypt.i386 \
php-soap.i386 \
php-xml.i386 \
php-cli.i386 \
httpd.i386
インスタンス上で、チュートリアルファイルのindex.phpをドキュメントルートにコピーし、アップロードされたビデオファイルを保存する/var/www/html/uploadsディレクトリを作成して、Apacheを起動します。
# cp /var/www/awsfiles/index.php /var/www/html/index.php # mkdir /var/www/html/uploads # chown apache:apache /var/www/html/uploads # service httpd start
インスタンスのApacheの起動後に、ローカルコンピュータのウェブブラウザで、インスタンスのパブリックDNS名にアクセスすると、ファイルアップロードフォームが表示されます。インスタンスのパブリックDNS名は、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-hostname.txt」ファイルに保存されています(もちろんAWS Consoleでも確認できます)。
ファイルアップロードフォームから適当なファイルをアップロードすると、インスタンスの/var/www/html/uploadsディレクトリにファイルが保存されます。現在のindex.phpが行うのはこの単純なファイルアップロード処理だけです。チュートリアルのシナリオでは、アップロードされたファイルはS3に保存され、そのパスがSQSに登録されて変換処理を待ち受けますが、現在のindex.phpは、まだそうした処理は行いません。
そこで次に、SQSにキューを作成し、index.phpを差し替えます。
SQSキューの作成
EC2インスタンス上で、sqs-makequeue.phpを実行して「awstutorial」という名前のキューを作成します。
sqs-makequeue.php
- ListQueuesリクエストで、名前が「awstutorial」で始まるキューの存在を確認
- キューが存在しない場合、CreateQueueリクエストでキューを作成
# php /var/www/awsfiles/sqs-makequeue.php Creating awstutorial... Queue awstutorial created at https://queue.amazonaws.com/842929249205/awstutorial
アップロードファイルのS3への転送とSQSキューへのメッセージ送信
EC2インスタンス上で、現在のindex.phpをチュートリアルファイルのindex2.phpと差し替えます。
# cp /var/www/awsfiles/index2.php /var/www/html/index.php
新しいindex.phpはファイルアップロード処理の完了後にsqs-queue-conversion.phpをインクルードします。sqs-queue-conversion.phpは、アップロードされたファイルをS3に転送し、そのパスをメッセージとしてキューに送信します。
sqs-queue-conversion.php
- アップロードされたファイルをS3に転送
- SendMessageリクエストで、S3に転送したファイルのパスをメッセージとして「awstutorial」キューに送信
チュートリアルでは、S3の操作は、チュートリアルの著者であるClay Lovelessさん自身が開発したKillersoft_Wrapper_S3クラスを利用します。Killersoft_Wrapper_S3はS3に対するストリームラッパーの実装で、対応のファイルシステム関数などで、「s3://〜」というURLでS3のオブジェクトを操作できるようにするものです。
以下はsqs-queue-conversion.php中でKillersoft_Wrapper_S3を使用している箇所の抜粋で、Killersoft_Wrapper_S3::selfRegisterメソッドでラッパーを登録することで、is_dir、mkdir、file_put_contentsといったお馴染みの関数で、S3オブジェクトの操作が行われています。
Killersoft_Wrapper_S3::selfRegister();
...
$bucket = 's3://awstutorial-'
. md5(
$creds['access_key'] .
$creds['secret_key'] .
$host
);
if (! is_dir($bucket)) {
mkdir($bucket);
}
...
file_put_contents(
"{$bucket}/{$upload_name}",
file_get_contents($upload_file)
);
なお、チュートリアルでは、アップロードされたファイルはそのオリジナルのファイル名のままで保存されます。当然、同じ名前のファイルがアップロードされると同名のファイルが上書きされてしまうため、実用に供する場合はユニークなファイル名を割り当てる処理を追加する必要がありますが、チュートリアルではそうした処理は端折られています。
キューの確認
キューの状態はjob-check.phpを実行することで確認できます。
job-check.php
- S3に転送したファイルの存在確認
- GetQueueAttributesリクエストでキューにある可視メッセージの大凡の数(ApproximateNumberOfMessages)を取得して表示
- ReceiveMessageリクエストでキューにあるメッセージを受信してそのメッセージボディを表示(メッセージを確認するだけなので、他のプロセスの受信を妨げないようにVisibilityTimeoutは最小限に設定)
# php /var/www/awsfiles/job-check.php s3://awstutorial-a136e5e1e1e3ce3c44ffb1affbe79f1d/sample.mov is on S3! Queue awstutorial has ~1 messages. Found a message with a body of: s3://awstutorial-a136e5e1e1e3ce3c44ffb1affbe79f1d/sample.mov
キューからのメッセージの受信と削除
チュートリアルでは、アップロードされたファイルはFLV形式に変換されます。変換処理を担当するプロセスはキューを監視し、新しいメッセージを受信すると変換処理を実施します。job-fetch.phpはこうしたプログラムの例です。
job-fetch.php
- ReceiveMessageリクエストでキューにあるメッセージを受信(VisibilityTimeoutは20秒に設定)
- メッセージのパスがS3上に実在するか確認
- パスが実在しない場合、DeleteMessageリクエストでメッセージを削除して終了
- パスが実在する場合、S3からファイルを転送して変換処理を実施
- 変換処理が成功したら(変換後のファイルが存在していたら)DeleteMessageリクエストでメッセージを削除
- 変換後のファイルをS3に転送し、変換元のファイルを削除
# php /var/www/awsfiles/job-fetch.php Conversion complete! Deleting completed job from queue. Uploading converted file back to S3 Deleting original since we no longer need it
メッセージの受信時にVisibilityTimeoutで設定した秒数を経過すると、(メッセージが削除されていない場合)そのメッセージは再び可視状態となり、他のクライアントが受信可能になります。そこで実際のVisibilityTimeoutの設定は、複数のクライアントが重複してメッセージを受信しないように調整する必要があります。
なお、job-fetch.phpはビデオの変換にFFmpegを利用します。従ってjob-fetch.phpを実行するコンピュータにはFFmpegが必要で、チュートリアルの「Step 3: Perform Conversion Job」にはEC2インスタンスへのFFmpegのインストール手順が紹介されています。しかし、FFmpegのインストールや実行はチュートリアルの本旨ではなく、実際のところFFmpegのインストールは結構な手間なので、インストールや変換がうまくいかない場合は、job-fetch.phpのFFmpegの実行コマンドを編成している箇所を、以下のように適当に改変して対処してしまってください。
// ffmpeg command for transformation
// $cmd = '/usr/bin/ffmpeg -i '
// . escapeshellcmd($localin)
// . ' -ar 22050 '
// . '-acodec mp3 -ab 32k -r 25 -s 320x240 '
// . '-vcodec flv -qscale 9.5 '
// . escapeshellcmd($localout);
$cmd = sprintf('cp %s %s',
escapeshellcmd($localin),
escapeshellcmd($localout));
SimpleDBによるビデオデータベース
チュートリアルでは、変換処理が完了した各ビデオは、そのデータが以下のような構造のSimpleDBデータベースに登録されます。
| Item Name | userid | category | file | description | size | tags | item1 | clay | tutorials | sample.mov | Just a sample video. Watch! | 71k | apple |
|---|
本来こうしたデータの登録は、ファイルのアップロードや変換処理の完了にあわせて行われるべきものですが、チュートリアルでは別途に手動で(!)行われます。さらにチュートリアルでは、リストを表示したりビデオを再生するウェブインタフェースは結局用意されません(つまりこのサイトのユーザは、アップロードしたビデオを見ることはできません)。もちろん、そのあたりはチュートリアルの本旨ではないのですが、まあとにかくバッサリ端折られてますんで、あらかじめご了解ください。
ドメインの作成
SimpleDBでは、RDBMSのテーブルに相当する概念を「ドメイン」と呼びます。sdb-create-domain.phpを実行すると、「awstutorial」という名前のドメインが作成されます。
sdb-create-domain.php
- CreateDomainリクエストで「awstutorial」という名前のドメインを作成
# php sdb-create-domain.php RequestId: 897b7cba-e9c0-1f11-9531-275dcf846e9b BoxUsage: 0.0055590278
SimpleDBへのリクエストのレスポンスには、その利用料金の指標となる「Box Usage」の値が含まれます。
EC2では同時に起動可能なインスタンス数はデフォルトで20ヶに制限されていますが、SimpleDBにも同様の制限があり、デフォルトではドメイン数は100ヶまで、1ドメインあたりのデータ量は10GBまでに制限されています。そして、EC2と同様にリクエストベースでこの制限を緩和することが可能です。
ドメインの一覧
sdb-list-domains.phpを実行すると、作成したドメインの一覧を確認できます。
sdb-list-domains.php
- ListDomainsリクエストでドメインの一覧を取得
# php sdb-list-domains.php DomainName awstutorial
アイテムの追加
sdb-create-records.phpを実行してアイテム(レコード)を追加します。追加されるアイテムは、上表の「item1」のものです。
sdb-create-records.php
- PutAttributesリクエストで「awstutorial」ドメインに「item1」という名前のアイテム、及びその属性(各カラム値)を保存
# php sdb-create-records.php RequestId: ee265eb4-0924-684a-b261-7cec5030ff23 BoxUsage: 0.0000220339
1アイテムあたりの属性数は256ヶ以下、1ドメインあたりの属性数は10億ヶ以下に制限されています。
SELECTクエリーの実行
SimpleDBでは、限定的なSELECT文を用いてアイテムを検索することができます。sdb-sqlselect.phpは、tags属性値が「app」で始まるアイテムを検索する「SELECT * FROM awstutorial WHERE tags LIKE 'app%'」を実行します。
sdb-sqlselect.php
- Selectリクエストで「SELECT * FROM awstutorial WHERE tags LIKE 'app%'」を実行
# php sdb-sqlselect.php Item Name: item1 file: sample.mov userid: clay size: 71k tags: apple category: tutorials description: Just a sample video. Watch!
利用可能なSELECT文の詳細は、Using Select to Create Amazon SimpleDB Queriesに記載されています。
1度のリクエストで取得可能なアイテムは2,500件以下、または合計データ量が1MB以下に制限されています。リクエストがこの制限を超えるアイテムにマッチした場合(及びクエリーの実行が5秒以上経過した場合)はレスポンスにNextToken要素が含まれ、その値を用いることで「次ページ」のリクエストが行えます。
チュートリアルのsdb-list-items.phpでは、Selectリクエストではなく、Queryリクエスト、及びQueryWithAttributesリクエストが行われていますが、これらはいずれも最新のAPIバージョン2009-04-15ではDeprecatedとなっています。
チュートリアルの紹介は以上です。チュートリアルではAmazon純正のライブラリを利用していましたが、AWSのライブラリには他にも様々なものがあり、以下ではそのひとつ、CloudFusionを紹介します。
CloudFusion(旧称Tarzan AWS)
CloudFusionはAWS等のクラウドサービス用のPHPライブラリです。CloudFusionは、AWSについては単一のパッケージで複数のサービスをサポートしており、現時点のバージョン2.5では、EC2、S3、SQS、SimpleDB、CloudFront、及びProduct Advertising APIをサポートしています。またAWS以外にも、クラウドサービスの基盤を提供するオープンソースソフトウェアであるEucalyptusをサポートしています。
以下はチュートリアルの「sdb-create-records.php」にある、SimpleDBのドメイン「awstutorial」にアイテム「item1」を追加するコードをCloudFusionのもので書き換えた例です。
require_once 'cloudfusion.class.php';
$sdb = new AmazonSDB(
'Your AWS Access Key ID',
'Your AWS Secret Access Key');
$response = $sdb->put_attributes('awstutorial',
'item1',
array(
'userid' => 'clay',
'category' => 'tutorials',
'file' => 'sample.mov',
'description' => 'Just a sample video. Watch!',
'size' => '71k',
'tags' => array('apple')),
true);
print_r($response);
なお、上の例ではAccess Key IDとSecret Access Keyをコンストラクタのパラメータに指定していますが、これらはCloudFusionでは通常config.inc.phpに記述しておきます。これ以降に登場する例はいずれも、これらがconfig.inc.phpに記述されていることを前提に、コンストラクタのパラメータは省略しています。
CloudFusionには以下のような特徴があります。
リクエストの並列実行
CloudFusionではcurl_multi_*によるリクエストの並列実行が可能です。
以下は通常の、逐次リクエストを実行する例です。ここではSQSキューに10ヶのメッセージを送信しています。AmazonSQS->send_messageメソッドは直ちにリクエストを実行し、レスポンスオブジェクトを返します。
require_once 'cloudfusion.class.php';
$sqs = new AmazonSQS;
$responses = array();
for ($i = 0; $i < 10; $i++) {
$responses[] = $sqs->send_message(
'https://queue.amazonaws.com/awstutorial',
"This is message #$i");
}
print_r($responses);
以下は上の例を、リクエストを並列実行するように書き換えたものです。CloudFusionのAmazon*クラスの多くのメソッドは、パラメータの最後にTRUEを指定すると、リクエストを実行してレスポンスオブジェクトを返す代わりに、リクエストのcURLハンドルを返します。ハンドルの配列をRequestCore->send_multi_requestのパラメータに指定するとリクエストが並列実行され、その各レスポンスオブジェクトの配列が返されます。
require_once 'cloudfusion.class.php';
$sqs = new AmazonSQS;
$handles = array();
for ($i = 0; $i < 10; $i++) {
$handles[] = $sqs->send_message(
'https://queue.amazonaws.com/awstutorial',
"This is message #$i",
true);
}
$request = new RequestCore;
$responses = $request->send_multi_request($handles);
print_r($responses);
組み込みのキャッシュ機構
CloudFusionにはレスポンスのキャッシュ機構が用意されており、必要に応じて利用することができます。現在対応しているキャッシュストレージは、ファイル、SQLite、MySQL、PostgreSQL、APC、及びMemcacheとなっています。
容易なクラスのカスタマイズ
CloudFusionでは、通常内部的に使われるクラスについても容易にそのカスタムクラスが利用出来るようになっています。以下は例として、リクエストURLを返すgetRequestUrlメソッドを実装したResponseCoreの継承クラスを作成しています。カスタムクラスを利用するには、Amazon*クラスのset_*_classメソッドのパラメータにカスタムクラスの名前を指定します。
require_once 'cloudfusion.class.php';
class CFCustomResponse extends ResponseCore {
public function getRequestUrl() {
if (isset($this->header['x-cloudfusion-requesturl'])) {
return $this->header['x-cloudfusion-requesturl'];
}
return null;
}
}
$sqs = new AmazonSQS;
$sqs->set_response_class('CFCustomResponse');
$response = $sqs->send_message(
'https://queue.amazonaws.com/awstutorial',
"This is another test message.");
echo $response->getRequestUrl() . "\n";
カスタムクラスはCloudFusionの命名規則に従ったファイル名を与えることで、CloudFusionのオートロードの対象になります。現在のCloudFusionのクラスファイルの命名規則は、クラス名が「Amazon」で始まる場合はそれを除去し、「CF」で始まる場合はそれをアンダースコアに置換し、クラス名をすべて小文字にして「.class.php」を続けるというものです。例えば上の例の「CFCustomResponse」クラスの場合、そのファイル名は「_customresponse.class.php」となります。
ドキュメント
CloudFusionのドキュメントは比較的よく整備されており、APIリファレンスには、多くのメソッドにサンプルコードが用意されています。
以上、AWS用のライブラリの例としてCloudFusionを紹介しました。AWS用のライブラリには、このCloudFusionや、チュートリアルで登場したKillersoft_Wrapper_S3のように、Amazon純正のもの以外にも様々なものがあり、プロジェクトのニーズ次第では検討の余地があるのかもしれません。

