AWS SDK for JavaScriptを使ってS3にダイレクトでファイルをアップロードする
AWS SDK for JavaScriptがリリースされました。これにより、例えばS3にJavaScriptのファイルを配置して、クライアントサイドでJavaScriptを実行、その中でS3へのファイルアップロードの処理を行えば、別途S3へのアップロードを行うためのWebサーバが必要なくなります。
まず、最初にJavaScriptを使って、S3のバケットに対してlistObjectsしてみます。そのJavaScriptを含むHTMLファイルが以下です。
<head> <title>Sample</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <script src="https://sdk.amazonaws.com/js/aws-sdk-2.0.0-rc1.min.js"></script> <script type="text/javascript"> <!-- AWS.config.update({accessKeyId: 'ACCESS_KEY_ID', secretAccessKey: 'SECRET_ACCESS_KEY'}); var s3 = new AWS.S3({region: 'ap-northeast-1', maxRetries: 15}); s3.listObjects({Bucket: 'BUCKET_NAME'}, function(error, data) { if (error) { console.log(error); // an error occurred } else { console.log(data); // request succeeded } }); // --> </script> </body> </html>
これをWebサーバもしくはS3上に配置します。
この作業だけでは、Access Deniedと表示されてしまうので、さらに該当するバケットのCORS(Cross-Origin Resource Sharing)を設定します。CORSとは、S3とは違う他のドメインのサイトからS3上のリソースにアクセスするときの共有設定のことです。デフォルトではAllowedOriginが*のものに対して、GETメソッドのみ許可されているようです。それを以下のように変更します。
<CORSConfiguration> <CORSRule> <AllowedHeader>*</AllowedHeader> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedMethod>PUT</AllowedMethod> <AllowedMethod>POST</AllowedMethod> <AllowedMethod>DELETE</AllowedMethod> <MaxAgeSeconds>3000</MaxAgeSeconds> <AllowedHeader>Authorization</AllowedHeader> </CORSRule> </CORSConfiguration>
※AllowedOriginを、特定のURL(例:http://www.example.com/)に限定すると、より権限を限定できて良いです。
FirefoxのプラグインのFirebugを使って、Console Logを見てみると、以下のようにコンテンツを取得できていることがわかりました。
次に本記事のメインとなるS3 Uploadを試してみます。
以下のようなs3upload.htmlを作成しました。
<html> <head> <title>Sample</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <input type="file" id="file-chooser" /> <button id="upload-button">Upload to S3</button> <div id="results"></div> <script src="https://sdk.amazonaws.com/js/aws-sdk-2.0.0-rc1.min.js"></script> <script type="text/javascript"> <!-- AWS.config.update({accessKeyId: 'AKIAXXXXXXXXXXXXXX', secretAccessKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}); var bucket = new AWS.S3({params: {Bucket: 'BUCKET-NAME'}}); var fileChooser = document.getElementById('file-chooser'); var button = document.getElementById('upload-button'); var results = document.getElementById('results'); button.addEventListener('click', function() { var file = fileChooser.files[0]; if (file) { results.innerHTML = ''; var params = {Key: file.name, ContentType: file.type, Body: file}; bucket.putObject(params, function (err, data) { results.innerHTML = err ? 'ERROR!' : 'UPLOADED.'; }); } else { results.innerHTML = 'Nothing to upload.'; } }, false); // --> </script> </body> </html>
作成したs3upload.htmlを表示すると以下のような画面が表示されます。
適当なテキストファイルを選択してアップロードすると、以下のように表示されます。
S3 Management Consoleで確認すると、確かにアップロードされてました!
あとは、JavaScript内にAWS Security Credential情報がベタ書きされてしまっているのを、以前書いた記事にあるようにSecurity Token Serviceを使って、一時的なTokenを使うようにすれば、権限を制限させることもできます。
以上ですー。
S3バケット以下の特定のフォルダにのみアクセス可能なIAMユーザをつくる
以下のJSONポリシーをIAMユーザに割り当てることで、examplebucket以下のfolder1にのみアクセス可能でした。
{ "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Resource": ["arn:aws:s3:::examplebucket"], "Condition":{"StringLike":{"s3:prefix":["folder1/*"] } } } ] }
詳細はこちらをご覧ください。
http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingIAMPolicies.html
AWS OpsWorksでのカスタムAMIの利用について
AWS OpsWorksで2013年10月現在サポートされているAMIは、Amazon LinuxとUbuntu 12.04 LTSベースです。
これらを素のまま使うこともできますし、事前にEC2コンソールで起動して、必要なパッケージをインストールしておいて、それをOpsWorksで使うこともできます。
そこで、実際にOpsWorksでインスタンスを起動するときに、必要となるOpsWorks Agentをどうやってインストールさせているんだろう?と疑問に思っていたのですが、解決しました!
Cloud-initを使ってインストールさせてるんですね。
OpsWorksで起動したインスタンスを、EC2 ConsoleでUser Dataをみたところ、OpsWorks Agentをインストールさせるためのスクリプトが書かれていました。
なるほど!これで納得。
逆にCloud-initを使ってOpsWorks Agentをインストール・動作できるのであれば、他のOSのイメージででも技術的には動作可能かもしれないですね。(サポートの有無はまた別の話として。)
詳細はこちら。
http://docs.aws.amazon.com/opsworks/latest/userguide/workinginstances-custom-ami.html
OpsWorksで起動されるインスタンスは複数のレイヤーに属することができる
OpsWorksで作成したインスタンスは複数のレイヤーに属することができます。
例えばStatic Web Serverレイヤーに属するインスタンスを作成した場合、それにMySQLレイヤーも属させることで、1インスタンスで2つのレイヤーの役割をこなすことができます。
ただし、その設定が行えるのはインスタンスがstopの状態にあるときです。
具体的には以下のようなインスタンスのEdit画面で、レイヤーを追加してあげるだけです。
これで追加したレイヤーのChefレシピも動作するということですね。
これでより多くの構成をカバーできますね。
ただ、レイヤー間の互換性があるため、非互換のものは同居させることは出来ないようです。以下のように表示され、非互換のものは選択できません。
以下はその例です。
- PHP App Serverレイヤーが互換性のあるレイヤー:custom, db-master, memcached, monitoring-master, and rails-app.
- MySQLレイヤーが互換性のあるレイヤー:custom, lb, memcached, monitoring-master nodejs-app, php-app, rails-app, and web.
- HAProxyレイヤーが互換性のあるレイヤー:custom, db-master, and memcached
詳細はこちら。
http://docs.aws.amazon.com/opsworks/latest/userguide/layers.html
aws-cliを使ってAutoScaling Groupを作成してみる。
launch-configurationを作成
$ aws autoscaling create-launch-configuration --launch-configuration-name config1 --image-id ami-39b23d38 --instance-type t1.micro --key-name ap-northeast
作成結果を確認
$ aws autoscaling describe-launch-configurations --output text ap-northeast arn:aws:autoscaling:ap-northeast-1:XXXXXXXXXXXX:launchConfiguration:0ad52a06-34d4-4c70-940c-b4b5a23adbd9:launchConfigurationName/config1 ami-39b23d38 False config1 2013-08-23T10:44:36.777Z t1.micro INSTANCEMONITORING True RESPONSEMETADATA 5d980e12-0be1-11e3-a812-5b0041b22e4e
auto-scaling-groupを作成
$ aws autoscaling create-auto-scaling-group --auto-scaling-group-name group1 --launch-configuration-name config1 --min-size 2 --max-size 2 --vpc-zone-identifier subnet-d8de6cb0,subnet-96d96bfe
作成結果の確認
$ aws autoscaling describe-auto-scaling-groups --output text arn:aws:autoscaling:ap-northeast-1:XXXXXXXXXXXXXX:autoScalingGroup:3cffd102-8a3e-4756-8a20-3343b39ba977:autoScalingGroupName/group1 0 2 group1 300 2 2 subnet-d8de6cb0,subnet-96d96bfe config1 2013-08-23T10:58:55.700Z EC2 i-02215307 ap-northeast-1c Healthy InService config1 i-9fe2059a ap-northeast-1a Healthy InService config1 RESPONSEMETADATA 45062903-0be3-11e3-84d9-670da55b233a
インスタンス2つが、異なるサブネット(異なるAZ)で起動しているのが分かりますね。
ついでに削除処理もメモとして残しておきます。
$ aws autoscaling update-auto-scaling-group --auto-scaling-group-name group1 --min-size 0 --max-size 0 $ aws autoscaling delete-auto-scaling-group --auto-scaling-group-name group1 $ aws autoscaling delete-launch-configuration --launch-configuration-name config1 以上で削除完了です。AutoScaling groupの削除は、インスタンスが完全にterminateされてからでないと削除はできませんので、ご注意を。
Amazon Linux 2013.03にデフォルトでインストールされているAWS CLIにhelpが入ってない。
https://forums.aws.amazon.com/thread.jspa?messageID=449307
こちらのディスカッションフォーラムにもあるように、Amazon Linux 2013.03にはaws-cliのhelp(manual entry)が入っていないです。
$ aws --version aws-cli/0.9.3 Python/2.6.8 Linux/3.4.43-43.43.amzn1.x86_64
以下のようにhelpコマンドを実行しても表示されません。
$ aws help No manual entry for aws
ので、aws-cliを一旦削除して再インストールし直すことにしました。
$ sudo yum remove aws-cli $ sudo yum -y update $ sudo easy_install pip $ sudo pip install awscli
インストール後、helpを実行すると、
$ aws help AWS() AWS() NAME aws - DESCRIPTION The AWS Command Line Interface is a unified tool that provides a con- sistent interface for interacting with all parts of AWS. SYNOPSIS aws [options] <service_name> <operation> [parameters] Use aws service help for information on a specific service. OPTIONS --debug (boolean) Turn on debug logging. --endpoint-url (string)
正しく表示されました。よかったよかった。
ちなみに新しく入れたaws-cliのバージョンは
$ aws --version aws-cli/0.14.1 Python/2.6.8 Linux/3.4.43-43.43.amzn1.x86_64
元々入っていたのが0.9.3だったので、元々のは結構古かったみたいですね。
AWS CLIを使ってTagの値のみを取得する
AWS CLIを使って、以下のように割り当てられたインスタンスのTagの値のみ(今回はWordPress)を取得します。
今回はAmazon Linuxを使うので、AWS CLIのインストール方法は割愛します。
# Amazon Linux 2013.03に入っているデフォルトのaws-cliを使いました。バージョンは以下です。
$ aws --version aws-cli/0.9.3 Python/2.6.8 Linux/3.4.43-43.43.amzn1.x86_64
#バージョンが異なると、オプションの指定が異なる可能性があります。
まず以下の環境変数を設定します。
export AWS_DEFAULT_REGION=ap-northeast-1 export AWS_CREDENTIAL_FILE=/opt/aws/credential-file
credential-fileを作成します。
$ sudo cp /opt/aws/credential-file-path /opt/aws/credential-file $ sudo vi /opt/aws/credential-file AWSAccessKeyId=XXXXXXXXXXXXXXXXXX AWSSecretKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
以下コマンドを実行して動作確認。
$ aws ec2 describe-instances { "Reservations": [ { "OwnerId": "000000000000", "ReservationId": "r-883ce98b", "Groups": [ (以下省略)
ちゃんと出力されることを確認。
$ aws ec2 describe-tags { "ResponseMetadata": { "RequestId": "b98ff86b-24e7-4950-9161-c864e11c20a7" }, "Tags": [ { "ResourceType": "snapshot", "ResourceId": "snap-6d0d4c4d", "Key": "Name", "Value": "dev-urandom-1G" }, { "ResourceType": "security-group", "ResourceId": "sg-958dff94", "Key": "aws:cloudformation:stack-name", "Value": "WordpressSite" }, (以下省略)
通常describe-tagsを実行すると、全部のTagが出てきてしまうので、絞り込みをします。
$ aws ec2 describe-tags --filter '{"name":"resource-id","values":"i-06672203"}' { "ResponseMetadata": { "RequestId": "8c60bc2e-16bc-4882-8bfb-de5889eb84c3" }, "Tags": [ { "ResourceType": "instance", "ResourceId": "i-06672203", "Key": "Name", "Value": "WordPress" } ] }
これをさらに絞り込むためにjqを使います。jqは入力内容を元に出力を絞り込むためのプログラムです。
まずは、jqをインストール。
$ sudo yum install jq
そして、上記出力をjqを使って絞り込みます。
$aws ec2 describe-tags --filter '{"name":"resource-id","values":"i-06672203"}' | jq '.Tags[] | .Value' "WordPress"
以上で、WordPressの値のみを抽出することができました!
もちろん、Name以外のTagも取得できますので、いろいろ使いまわせそうですね。