Amazon EC2 は安くて性能もよい素晴らしいサービスだが、EC2 で画像の多いウェブアプリを作ると画面が表示されるまでにやや時間がかかる。国内に置いたサーバの方に、ユーザエクスペリエンスでは分がある。Amazon CloudFront という CDN(Contents Delivery Network) サービスを使えば、この遅さを解消できるのではないかと期待して試してみた。



<p>
手順は次のとおり。
<ol>
<li>アカウントの設定で Amazon CloudFront を有効にする。EC2 や S3 を使っていても、CloudFront がそのまま使えるわけではない。明示的に有効にする(Sign Up)必要がある。</li>
<li>CloudFront で配信する object(ファイル)を S3 のバケットに用意する。</li>
<li>distribution を作成して domain name を得る。</li>
<li>domain name を用いてHTTPでアクセスする。</li>
</ol>
</p>

<h4>ツールのインストール</h4>
<p>perl のモジュールをインストールする。
<pre class="prettyprint">
# perl -MCPAN -e shell
Terminal does not support AddHistory.

cpan shell – CPAN exploration and modules installation (v1.7602)
ReadLine support available (try ‘install Bundle::CPAN’)
cpan> install Digest::HMAC_SHA1
cpan> install FindBin
cpan> install MIME::Base64
cpan> install Getopt::Long
cpan> install File::Temp
cpan> install File::Basename
cpan> install Fcntl
cpan> quit
Terminal does not support GetHistory.
Lockfile removed.
</pre>
</p>

<p>curl をインストールする。
<pre class="prettyprint">
# yum install curl
</pre>
</p>

<p>Amazon CloudFront Authentication Tool for Curl (cfcurl.pl) をインストールする。
<pre class="prettyprint">
# wget http://d1nqj4pxyrfw2.cloudfront.net/cfcurl.pl
</pre></p>

<p>Amazon用のcurlの設定ファイルを作成する。
<pre class="prettyprint">
# cat ~/.aws-secrets
%awsSecretAccessKeys = (
myaccount => {
id => ‘',
key => '',
},
);
# chmod 600 ~/.aws-secrets
</pre>
</p>

<h3>distribution を作成する</h3>
<h4>object (ファイル) を S3 bucket に用意する</h4>
<p>CloudFront での公開向けに新しい bucket を作成して、S3 Fox でディレクトリ毎ドラッグ&ドロップして楽をした。bucket のサブディレクトリのみ公開という設定ができないようなので、AMI などを保存している bucket と共用することはできないと思われる。</p>

<h4>distribution を作成して domain name を割り当ててもらう</h4>
<p>distribution とは、S3 bucket に格納した object(ファイル)を CloudFront に認識させるためのもの。S3 と CloudFront をつなげるのが distribution。ドメイン名を指定することはできない。
</p>

<p>distribution の作成リクエストを作成する。
<pre class="prettyprint">
# cat create_request.xml

<DistributionConfig xmlns="http://cloudfront.amazonzws.com/doc/2008-06-30/">
yourbucketname.s3.amazonaws.com
20081209150200</CallerReference>

true
</DistributionConfig>
</pre>
yourbucketname の部分には自分のバケットの名前を入れる。
</p>

<p>distribution の作成リクエストを送信する。
<pre class="prettyprint">
# ./cfcurl.pl --keyname gh -- -X POST -i -H "Content-Type:text/xml; charset=UTF-8" --upload-file create_request.xml https://cloudfront.amazonaws.com/2008-06-30/distribution

HTTP/1.1 100 Continue

HTTP/1.1 201 Created
ETag: E1A2X6NUDMD4NF
Location: https://cloudfront.amazonaws.com/2008-06-30/distribution/[distribution ID]
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Tue, 09 Dec 2008 06:07:52 GMT
Server: CloudFront


<Distribution xmlns="http://cloudfront.amazonaws.com/doc/2008-06-30/">
[distribution ID]
InProgress
2008-12-09T06:07:52.160Z</LastModifiedTime>
yourdomainname.cloudfront.net

yourbucketname.s3.amazonaws.com
20081209150200</CallerReference>

true
</DistributionConfig>
</Distribution>
☆実際は改行されていない。
</pre>
ドメイン名として yourdomainname.cloudfront.net が割り当てられた。yourdomainname の部分は、実際にはランダムに見える数字とアルファベットの羅列になる。
</p>

<p>デプロイ状態を確認する。
<pre class="prettyprint">
# ./cfcurl.pl --keyname gh -- https://cloudfront.amazonaws.com/2008-06-30/distribution/[distribution ID]


<Distribution xmlns="http://cloudfront.amazonaws.com/doc/2008-06-30/">
[distribution ID]
Deployed</Status&gt</span>
;2008-12-09T06:07:52.160Z</LastModifiedTime>
yourdomainname.cloudfront.net

yourbucketname.s3.amazonaws.com
20081209150200</CallerReference>
true
</DistributionConfig>
</Distribution>
☆実際は改行されていない。
</pre>
Deployed になった。
</p>

<h4>割り当てられたドメイン名を使ってHTTPでアクセスする</h4>
<p>http://yourdomainname.cloudfront.net/test.gif などでアクセスできることを確認する。ディレクトリを作成してある場合は http://yourdomainname.cloudfront.net/dir/test.gif となる。</p>

<h4>CNAME を使って独自ドメインでアクセスする</h4>

<p>yourdomainname.cloudfront.net のまま使っても良いのだが、きれいではない。そこで、独自ドメイン cdn.yourdomain.com に割り当てることにする。</p>

<p>まず、DNS で CNAME を設定する。ここでは、cdn.yourdomainname.comyourdomainname.cloudfront.net に割り当てる。DNS で設定しただけで cdn.yourdomainname.com でアクセスすると "Sorry, invalid request" とエラーが返るので注意。</p>

<p>CloudFront に CNAME を設定する。まずは distribution configuration を取得する。
<pre class="prettyprint">
# ./cfcurl.pl --keyname gh -- -X GET -i https://cloudfront.amazonaws.com/2008-06-30/distribution/[distribution ID]/config

HTTP/1.1 200 OK
ETag: E3UVV2001DSTPM
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Wed, 10 Dec 2008 01:45:59 GMT
Server: CloudFront


<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2008-06-30/">
yourbucketname.s3.amazonaws.com
20081209150200</CallerReference>
true
</DistributionConfig>
☆実際は改行されていない。
</pre>
</p>

<p>取得した XML に CNAME の設定を追加する。ここでは cdn.yourdomainname.com というドメインを設定した。
<pre class="prettyprint">
# cat add_cname_request.xml

<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2008-06-30/">
yourbucketname.s3.amazonaws.com
20081209150200</CallerReference>
cdn.yourdomainname.com</CNAME>
true
</DistributionConfig>
</pre>
</p>

<p>
リクエストを送信する。
<pre class="prettyprint">
# ./cfcurl.pl --keyname gh -- -X PUT -H 'If-Match: E3UVV2001DSTPM' -H 'Content-Type: text/xml; charset=UTF-8' --upload-file add_cname_request.xml -i https://cloudfront.amazonaws.com/2008-06-30/distribution/E34IPDB0XMHUZ8/config

HTTP/1.1 100 Continue

HTTP/1.1 200 OK
ETag: E1R8F57QTNMIK7
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Wed, 10 Dec 2008 01:54:39 GMT
Server: CloudFront


<Distribution xmlns="http://cloudfront.amazonaws.com/doc/2008-06-30/">
E34IPDB0XMHUZ8
InProgress
2008-12-10T01:54:39.556Z</LastModifiedTime>
daazlu5bwln5.cloudfront.net

yourbucketname.s3.amazonaws.com
20081209150200</CallerReference>
cdn.yourdomainname.com</CNAME>
true
</DistributionConfig>
</Distribution>
☆実際は改行されていない。
</pre>
</p>

<p>http://yourdomainname.cloudfront.net/test.gif などでアクセスできることを確認する。</p>

<h3>distrubution を削除する</h3>
<p>
ETag を取得する。
<pre class="prettyprint">
# ./cfcurl.pl --keyname gh -- -X GET -i https://cloudfront.amazonaws.com/2008-06-30/distribution/[distribution ID]/config

HTTP/1.1 200 OK
ETag: E1A2X6NUDMD4NF
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Tue, 09 Dec 2008 06:49:07 GMT
Server: CloudFront


<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2008-06-30/">
yourbucketname.s3.amazonaws.com
20081209150200</CallerReference>
true
</DistributionConfig>
</pre>
</p>

<p>上記で得られた ETag と XML をどこかに保存しておく。XML の中の Enabled を false にして、PUT すると、distribution を disabled にできる。
<pre class="prettyprint">
-bash-3.2# ./cfcurl.pl --keyname gh -- -X PUT -H 'If-Match: E1A2X6NUDMD4NF' -H 'Content-Type: text/xml; charset=UTF-8' --upload-file disable_request.xml -i https://cloudfront.amazonaws.com/2008-06-30/distribution/[distribution ID]/config

HTTP/1.1 100 Continue

HTTP/1.1 200 OK
ETag: E1VR3TXI7JKY94
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Tue, 09 Dec 2008 07:43:19 GMT
Server: CloudFront


<Distribution xmlns="http://cloudfront.amazonaws.com/doc/2008-06-30/">
[distribution ID]
InProgress
2008-12-09T07:43:20.254Z</LastModifiedTime>
yourdomainname.cloudfront.net

yourbucketname.s3.amazonaws.com
20081209150200</CallerReference>
false
</DistributionConfig>
</Distribution>
☆実際は改行されていない。
</pre>
</p>

<p>上記で得られた ETag の値を用いて distribution を削除する。
<pre class="prettyprint">
# ./cfcurl.pl --keyname gh -- -i -X DELETE -H 'If-Match: E1VR3TXI7JKY94' https://cloudfront.amazonaws.com/2008-06-30/distribution/[distribution ID]
</pre>
</p>

<h3>(おまけ)distribution の一覧を取得する</h3>
<pre class="prettyprint">
# ./cfcurl.pl --keyname gh -- -i -X GET https://cloudfront.amazonaws.com/2008-06-30/distribution

HTTP/1.1 200 OK
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Tue, 09 Dec 2008 08:02:09 GMT
Server: CloudFront


<DistributionList xmlns="http://cloudfront.amazonaws.com/doc/2008-06-30/">

100
false</IsTruncated>

[distribution ID]
Deployed
2008-12-09T06:45:12.827Z</LastModifiedTime>
yourdomainname.cloudfront.net
yourbucketname.s3.amazonaws.com
false
</DistributionSummary>
</DistributionList>
☆実際は改行されていない。
</pre>

<p>それにしても、S3 はコマンドラインから操作しようとすると、何をするのにも苦痛を伴う。普通は S3Fox などを使うほうがいい。
<ul>
<li>S3Fox は無料。v0.4.5 で CloudFront の distribution も操作できるようになった。
<li>Bucket Explorer は有料の Amazon S3、CloudFront の操作ソフト。CloudFront 対応はまだベータ版。しかも、ベータ版はお試し利用ができずに、ライセンスを購入する必要があるようだ。</li>
</li></ul>
</p>