こんにちは。 エキサイト株式会社で内定者アルバイトをしています。
今回も、実際のリソースの作成を行いたいと思います。第9回は、CloudFrontです。
前の記事
CloudFrontとは?
CloudFrontはコンテンツ配信のためのリソースです。コンテンツにはHTMLファイル、CSSファイル、JSファイル、画像ファイルなどが含まれます。
低レイテンシーかつ高速な転送速度での配信が実現できるそうです。
また、トラフィックの暗号化やアクセス制御によりセキュリティを向上させ、AWS Shield Standardを利用することで追加料金なしでDDoS攻撃を防御することもできるようです。
このように、低レイテンシーかつ高セキュリティとのことで、ウェブサイトの提供、動的コンテンツ配信、ライブおよびオンデマンドのビデオストリーミング、パッチやアップデートの配信など様々なユースケースが提示されています。
Amazon CloudFront(グローバルなコンテンツ配信ネットワーク)| AWS
コンテンツ配信の流れ
アプリケーションの開発者は配信するコンテンツを格納するサーバであるオリジンサーバを指定します。オリジンサーバにはEC2インスタンスやS3バケット、ロードバランサーなどを指定することができます。
CloudFrontはオリジンサーバからコンテンツを取得して、これを配信します。
CloudFrontではbehaviorというものを設定します。
behaviorでは、パスパターン、オリジンサーバなどを指定し、どのパスパラメータに対するリクエストが来たらどのオリジンサーバにコンテンツ配信のリクエストを送信するかを設定できます。
また、CloudFrontにはオリジンサーバへのリクエスト回数を減らすために、キャッシュがありbehaviorごとにキャッシュポリシーを設定することができます。
behaviorには順番が存在し、指定した順番にパスパターンを評価します。
ですので、正しくコンテンツ配信を行うためにはbehaviorの順番が重要になる場合もあります。
実際に作成してみる
今回は以下のような設定を持つディストリビューション(CloudFrontにおけるインスタンスのようなもの)を作成します。パスやキャッシュポリシーなどは適当に設定したものです。
behavior
優先順位 | パスパターン | オリジン | キャッシュポリシー |
---|---|---|---|
0 | /load/* | ロードバランサー | キャッシュ無効 |
1 | /s3/*.js | S3(JS、CSSファイル用) | assets-cache-policy |
2 | /s3/*.css | S3(JS、CSSファイル用) | assets-cache-policy |
3 | デフォルト | S3(デフォルト用) | デフォルト |
assets-cache-policy
項目 | 設定 |
---|---|
デフォルトTTL(秒) | 600 |
最小TTL(秒) | 1 |
最大TTL(秒) | 31536000 |
キャッシュキー設定:HTTPヘッダ | なし |
キャッシュのGzip圧縮 | 有効 |
キャッシュのBrotli圧縮 | 有効 |
前回までのコード
前回はCloudWatchのダッシュボードとアラームを作成しました。
しかし、今回はその部分は使いませんので、VPCおよびサブネットを作成した部分を再掲します。
package com.myorg; import software.amazon.awscdk.CfnTag; import software.amazon.awscdk.services.ec2.CfnInternetGateway; import software.amazon.awscdk.services.ec2.CfnVPCGatewayAttachment; import software.amazon.awscdk.services.ec2.PrivateSubnet; import software.amazon.awscdk.services.ec2.PublicSubnet; import software.amazon.awscdk.services.ec2.Vpc; import software.constructs.Construct; import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; import java.util.List; public class MyProjectStack extends Stack { public MyProjectStack(final Construct scope, final String id) { this(scope, id, null); } public MyProjectStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); Vpc vpc = Vpc.Builder.create(this, "SampleVPC") .vpcName("sample-vpc") .cidr("cidr") .subnetConfiguration(List.of()) .build(); // Availability zone: ap-northeast-1a PrivateSubnet privateSubnetA = PrivateSubnet.Builder.create(this, "PrivateSubnetA") .availabilityZone("ap-northeast-1a") .vpcId(vpc.getVpcId()) .cidrBlock("cidr") .build(); PublicSubnet publicSubnetA = PublicSubnet.Builder.create(this, "PublicSubnetA") .availabilityZone("ap-northeast-1a") .vpcId(vpc.getVpcId()) .cidrBlock("cidr") .build(); // Availability zone: ap-northeast-1c PrivateSubnet privateSubnetB = PrivateSubnet.Builder.create(this, "PrivateSubnetB") .availabilityZone("ap-northeast-1c") .vpcId(vpc.getVpcId()) .cidrBlock("cidr") .build(); PublicSubnet publicSubnetB = PublicSubnet.Builder.create(this, "PublicSubnetB") .availabilityZone("ap-northeast-1c") .vpcId(vpc.getVpcId()) .cidrBlock("cidr") .build(); // NAT gatewayの追加 publicSubnetA.addNatGateway(); publicSubnetB.addNatGateway(); // Internet Gateway CfnInternetGateway internetGateway = CfnInternetGateway.Builder.create(this, "InternetGateway") .tags(List.of(CfnTag.builder() .key("Name") .value("sample-internet-gateway") .build())) .build(); // Internet gatewayをVPCにattachする CfnVPCGatewayAttachment.Builder.create(this, "VpcGateAwayAttachment") .vpcId(vpc.getVpcId()) .internetGatewayId(internetGateway.getAttrInternetGatewayId()) .build(); } }
CloudFrontのディストリビューションを作成するコード
// CloudFront // オリジン(S3バケット)の作成 Bucket defaultOriginBucket = Bucket.Builder.create(this, "CloudFrontOriginBucket") .bucketName("cloud-front-origin-bucket-01") .encryption(BucketEncryption.S3_MANAGED) .build(); Bucket assetsOriginBucket = Bucket.Builder.create(this, "CloudFrontOriginBucket2") .bucketName("cloud-front-origin-bucket-02") .encryption(BucketEncryption.S3_MANAGED) .build(); // オリジン(ロードバランサー)の作成 ApplicationLoadBalancer cloudFrontOriginLoadBalancer = ApplicationLoadBalancer.Builder.create(this, "CloudFrontOriginLoadBalancer") .loadBalancerName("origin-load-balancer") .vpc(vpc) .vpcSubnets(SubnetSelection.builder() .subnets(List.of(publicSubnetA, publicSubnetB)) .build()) .internetFacing(true) .build(); // ① キャッシュポリシーを定義 CachePolicy assetsCachePolicy = CachePolicy.Builder.create(this, "SampleCustomCachePolicy") .cachePolicyName("assets-cache-policy") .comment("Cache policy for js, css file") .defaultTtl(Duration.seconds(600)) .minTtl(Duration.seconds(1)) .maxTtl(Duration.seconds(31536000)) .headerBehavior(CacheHeaderBehavior.none()) .enableAcceptEncodingGzip(true) .enableAcceptEncodingBrotli(true) .build(); IOrigin s3Origin = S3Origin.Builder.create(assetsOriginBucket).build(); IOrigin loadBalancerOrigin = LoadBalancerV2Origin.Builder.create(cloudFrontOriginLoadBalancer).build(); // ② behaviorを作成 BehaviorOptions assetsBehaviorOptions = BehaviorOptions.builder() .origin(s3Origin) .cachePolicy(assetsCachePolicy) .cachedMethods(CachedMethods.CACHE_GET_HEAD) .viewerProtocolPolicy(ViewerProtocolPolicy.ALLOW_ALL) .allowedMethods(AllowedMethods.ALLOW_GET_HEAD) .compress(true) .build(); BehaviorOptions loadBalancerBehaviorOptions = BehaviorOptions.builder() .origin(loadBalancerOrigin) .cachePolicy(CachePolicy.CACHING_DISABLED) .build(); // ③ ディストリビューションを作成 Distribution sampleDistribution = Distribution.Builder.create(this, "SampleDistribution") .defaultBehavior(BehaviorOptions.builder() .origin(S3Origin.Builder.create(defaultOriginBucket).build()) .build()) .build(); sampleDistribution.addBehavior("/load/*", loadBalancerOrigin, loadBalancerBehaviorOptions); sampleDistribution.addBehavior("/s3/*.js", s3Origin, assetsBehaviorOptions); sampleDistribution.addBehavior("/s3/*.css", s3Origin, assetsBehaviorOptions); } }
前半ではオリジンサーバとなるS3バケットとロードバランサーを作成しています。
①では、キャッシュポリシーを定義しています。上記の表で示した通りの設定ですので、特に説明は不要かと思います。
②では、behaviorを作成しています。CDKではBehaviorOptions
クラスを使います。
origin
でオリジンを指定し、そのほかの設定項目を指定していきます。viewerProtocolPolicy
はビューワーがこのbehaviorによって管理されるファイルにアクセスするために許可されたプロトコルを表します。
ここではすべてのプロトコルを許可します。
この他にはHTTPSのみを許可するオプションと、HTTPでアクセスされたらHTTPSにリダイレクトするオプションがあります。
③では、実際にディストリビューションを作成しています。ここでは、デフォルトのbehaviorと追加のbehaviorを設定しています。
ちなみにデフォルトのbehaviorは、すべてのパスにマッチします(追加で設定したbehaviorのどれにもマッチしなかった場合に使われるので「デフォルト」と呼ばれます)。
さて、behaviorの優先順位をどのように指定するかですが、2通りの方法があるように思います。
1つ目はDistribution
のaddBehavior
メソッドを使う方法です。
これを使えば、addBehavior
で追加した順にbehaviorの優先順位が決まります。
addBehavior
には第1引数にパスパターンを、第2引数にオリジンを、オプショナルで第3引数にはBehaviorOptions
を渡します。
サンプルコードではこちらを使っています。
2つ目はLinkedHashMap
を使う方法です。
これは順番が保障されたMap
です。通常のHashMap
は順番が保障されていないため、Map.of()
でMap
を作成するとbehaviorの順番はバラバラになってしまう可能性があります。
LinkedHashMap
を使う場合には以下のようにします。
Map<String, BehaviorOptions> additionalBehaviors = new LinkedHashMap<>(); additionalBehaviors.put("/load/*", loadBalancerBehaviorOptions); additionalBehaviors.put("/s3/*.js", assetsBehaviorOptions); additionalBehaviors.put("/s3/*.css", assetsBehaviorOptions); Distribution sampleDistribution = Distribution.Builder.create(this, "SampleDistribution") .defaultBehavior(BehaviorOptions.builder() .origin(S3Origin.Builder.create(defaultOriginBucket).build()) .build()) .additionalBehaviors(additionalBehaviors) .build();
デプロイ
ここまで記述できたら、あとはデプロイするだけです。
cdk deploy
エラーなくデプロイが完了したらOKです。
終わりに
今回は、AWS CDKを用いてCloudFrontのディストリビューションを作成しました。
今回で、実際のAWSリソースの作成は一旦終了です。次回は、AWS CDKでGradleを使う方法についてご紹介したいと思います。
では、また別の記事で。
次の記事