[AWS]CloudFront + nginx(http_image_filter_module) + S3 を使って画像変換サーバを構築する

投稿者: | 2014/08/18

珍しく(初めて?)AWSネタです。
仕事でAWSのVPCを構築しているのですが、画像を取り扱うサーバが欲しいとの要望がありました。
画像を表示するだけならCloudFront+S3だけで強力な画像(CDN)サーバを構築することができるのですが、今回は画像サイズもリアルタイムで変換して表示してほしいとのことでした。

幸いにも社内で以前、nginxのhttp_image_filter_moduleを使って画像変換している実例(実サーバ)があるのでそれを参考に構築してみました。

構成図

簡単な図です。

diagram

今回やりたかったこと

  • ユーザが独自ドメインとマッピングされたCloudFrontにアクセスすると、CloudFrontに画像がキャッシュされていればその画像を返します
  • もし画像がキャッシュされていなければELB・EC2インスタンス経由でS3にある画像を取得します
  • EC2インスタンスにhttp_image_filter_moduleが組み込まれたnginxがインストールされており、画像サイズをQueryString(width, heightなど)で指定すると、S3に保存している画像をリサイズして返します

なぜ、ELBを設置しているかと、以下の2つの理由があります。

  1. 画像変換サーバ(EC2インスタンス)の負荷対策
    • CloudFrontに画像がキャッシュされていれば頻繁にアクセスされず負荷が上がることがないと思いますが、最低限の負荷対策はしておきたいです。ELB配下に置いておくことでAutoScalingにも対応できます。
  2. 画像変換サーバ(EC2インスタンス)をPrivateSubnetに置きたかった
    • セキュリティ的観点からEC2インスタンスをPublicSubnet(RouteTablesでInternet Gatewayに出ていけるように設定しているSubnet)に置くことで外部から攻撃されるのを考慮しました
    • 外部からアクセスできる入り口をELBのみにし、EC2インスタンスはELBからのアクセス(http,https)のみを許容することで安全にサーバを運用することができると考えています

環境

前提条件

  • VPC,Subnet,SecurityGroup,NATインスタンスなどの作成・設定は省略しています
  • aws-cliの初期設定も省略しています

VPC内にELBを作成・設定する

aws-cliを使ってみます。

elb-image-filterという名前で作成しました。SubnetはPublicSubnetを指定します。

次にELBのHealthCheckを設定します。

IntervalHealthyThresholdなどはお好みで設定してください。

VPC内にEC2インスタンスを作成する

こちらもaws-cliを使って作成しました。

作成したEC2インスタンスにNameタグを付けます。

先ほど作成したEC2インスタンス(i-xxxxxxxx)にvpc-image-filterというNameタグを付けました。

ELB配下にEC2インスタンスを追加します。

この時点ではまだnginxをインストールしていない(80ポートは開いていない)ため、ELBのHealthCheckに失敗(OutOfService)しています。

EC2インスタンスにnginxをインストール・設定する

インストール方法は、nginx(1.4.7)をソースからインストールするを参照してほしいのですが、今回インストールするときの相違点を以下に挙げます。

  • nginxのバージョンについて
    • 何でも良いのですが、現時点(2014/08/18)でStableである1.6.1でインストールします
  • パッケージのインストールについて
    • http_image_filter_moduleをインストールするには、gdが必要なので予めインストールしておきます。

  • configureのオプションについて
    • http_image_filter_moduleをインストールするには、configureのオプションに--with-http_image_filter_moduleを付ける必要があります

nginxをインストールしたら起動します。

ELBのHealthCheckがInServiceになるのを待ちます。先ほど設定したHealthCheckだと約1分程度でInServiceになるはずです。

もしずっと待ってもOutOfServiceになっていたら、VPCのネットワーク設定(NetworkACL,SecurityGroup)やnginx,ELBの設定を見直してください。

InServiceになったら、ブラウザからELBのDNSName(http://elb-image-filter-xxxxxxxx.ap-northeast-1.elb.amazonaws.com/)を確認して、nginxのページ(Welcome to nginx!)が表示されることを確認してください。

S3にバケット作成&画像アップロードする

S3のバケット作成と画像アップロードはManagementConsoleから行いました。
バケット名はimage-filer、画像ファイル名はtest.jpgにしました。

画像をアップロードしてもそのままではブラウザから確認できないため、パーミッションを変更します。
アップグレードした画像に対して、下図のようにパーミッションを設定します。GranteeEveryoneを選択し、Open/Downloadにチェックを入れてください。

s3_permission

https://s3-ap-northeast-1.amazonaws.com/image-filter/test.jpgか、https://image-filter.s3-ap-northeast-1.amazonaws.com/test.jpg にアクセスして画像が表示されればOKです。

S3にある画像のサイズを変換させて表示させる

ここでようやく、nginxのhttp_image_filter_moduleを使った設定を行います。
/etc/nginx/nginx.conf に記述していますが、別ファイルに記述してIncludeしても良いです。
設定内容は、簡単!リアルタイム画像変換をNginxだけで行う方法 | cloudrop を参考にしました。

複雑そうな設定に見えますが、画像サイズなどのパラメータにしたがって、nginx -> S3へのリバースプロキシを設定しているだけです。

nginxを再起動(ORリロード)します

http://elb-image-filter-xxxxxxxx.ap-northeast-1.elb.amazonaws.com/test.jpg?width=300&height=500&type=resize などheight, weightのパラメータ値を設定し、ブラウザからアクセスしてリサイズされた画像を表示されればOKです。

CloudFrontの設定を行う

CloudFrontのCDN作成は、ManagementConsoleで、Create DistributionsからCloudFrontを作成します。
下図のように、Origin Domain Nameには、ELBのDNSNameを選択してください。OriginIDは自動的に入力されるので変更しなくても良いです。

create_distribution

Default Cache Behavior Settingsでは、Forward Query StringsをYesに設定するだけであとはデフォルト設定で良いです。
Distribution Settingsにある、Alternate Domain Names(CNAMEs)は後で設定します。

default_cache_behaivor_settings

設定するとCloudFront Distributionsの一覧に追加されますのでStatusDeployedになるまで待ちます。

Deployedになったら、ブラウザで、http://xxxxxxxxxxxxxx.cloudfront.net/test.jpg?width=300&height=500&type=resize にアクセスして画像が表示されればOKです。
xxxxxxxxxxxxx.cloudfront.net は作成されたCloudFrontのDomanNameです。

画像変換サーバのnginxのアクセスログを確認すると、初回アクセスのみアクセスされ、同じリクエストをするとCloudFront側でキャッシュされるため画像変換サーバにアクセスが来なくなることが分かります。異なる画像サイズを指定する度に画像変換サーバにアクセスされますが、CloudFront側にもリサイズされた画像がキャッシュされます。

独自ドメインの設定

ここまでで画像変換サーバの構築は終わっているのですが、URLがhttp://xxxxxxxxxxxxxx.cloudfront.net〜のようになっていますので、独自ドメインで画像を表示できるようにします。
ドメインをimg.example.comとして設定します。

独自ドメインの設定には、CloudFrontとRoute53の設定が必要です。また、必要に応じてnginxの設定も変更します。

CloudFrontの設定

下図のようにAlternate Domain Names(CNAMEs)に独自ドメインを設定します。

cloudfront_cname

設定完了後、CloudFront DistributionsにてCNAMEaの列にドメインが表示されればOKです。

cloudfront_list

Route53の設定

下図のようにALIASレコードを設定します。

  • Name: 独自ドメイン(サブドメイン)
  • Type: Aレコード
  • Alias: Yes
  • Alias Target: CloudFrontで割り当てられたドメイン(xxxxxxxxxxxxxx.cloudfront.net)

route53_alias

CNAMEレコードでも良いのですが、ALIASレコードの方が余計なリクエストをしなくて済むみたいです。
参考:Amazon Route 53のALIASレコード利用のススメ

設定が完了したら、digコマンドでDNSレコードを確認してみます。

複数IPアドレスが返ってくるようになるはずです。

nginxの設定

ServerNameを変更します。localhsot(デフォルトサーバ)でも良いのですが、複数のVirtualHostを設定したい場合はServerNameをELBのDNS名に変更します。
また、ELBのDNS名が長すぎてnginx: [emerg] could not build the server_names_hash, you should increase server_names_hash_bucket_size: 64というエラーが出るため、server_names_hash_bucket_size 128;というパラメータを設定しています。

下記がnginxの設定ファイルの最終版です。

nginxを再起動(ORリロード)します。

全て設定完了後、ブラウザから http://img.example.com/test.jpg?width=500&height=650&type=resize にアクセスして画像が表示されることを確認してください。

もし画像が表示されない場合は

キャッシュを削除すると表示されることがあります。

  • PCのDNSキャッシュ

Mac OS Xの場合

  • ブラウザのキャッシュ
    • スーパーリロードする

最後に

CloudFrontと組み合わせた画像変換サーバを構築してみました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*