📑
AWS CDK で CloudFront + S3 を使った Web サイト配信環境をサクッと構築する方法
これは何
- AWS CDK で CloudFront + S3 構成で Web サイトを配信する環境を構築するメモ
- 構成
- S3 Bucket 自体の Web Site Hosting は利用しない
- CloudFront から S3 へのアクセスは OAC を利用して制御する
CDK App のプロジェクトを用意
mkdir my-project && cd my-project
npx aws-cdk init app --language typescript ./
ホストする html ファイルとディレクトリを作成
mkdir website-dist
touch website-dist/index.html
index.html の中身
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
CDK App を実装
lib/my-project-stack.ts
を以下のように実装
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
export class MyProjectStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const destinationBucket = new s3.Bucket(this, 'WebsiteBucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
const distribution = new cloudfront.Distribution(this, 'WebsiteDistribution', {
defaultRootObject: 'index.html',
defaultBehavior: {
origin: origins.S3BucketOrigin.withOriginAccessControl(destinationBucket)
}
});
new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [s3deploy.Source.asset('./website-dist')],
destinationBucket,
distribution,
distributionPaths: ['/*'],
});
new cdk.CfnOutput(this, 'Hosting URL', {
value: 'https://' + distribution.distributionDomainName
});
}
}
各メソッドやリソースのプロパティについて軽く解説
S3 Bucket
const destinationBucket = new s3.Bucket(this, 'WebsiteBucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
-
removalPolicy: cdk.RemovalPolicy.DESTROY
- CloudFormation Stack を削除した時に S3 バケットをどう扱うかの設定
-
cdk.RemovalPolicy.DESTROY
を指定すると Stack 削除時に S3 バケットも削除する
-
autoDeleteObjects: true
- S3 バケットが Stack から削除される時、または Stack が削除される時に全てのオブジェクトを自動的に削除するか
CloudFront distribution, origin
const distribution = new cloudfront.Distribution(this, 'WebsiteDistribution', {
defaultRootObject: 'index.html',
defaultBehavior: {
origin: origins.S3BucketOrigin.withOriginAccessControl(destinationBucket)
}
});
-
defaultRootObject: 'index.html'
- distribution のルート URL に対してリクエストした際に、 CloudFront がオリジンにリクエストするオブジェクト
-
defaultBehavior
- distribution のデフォルト挙動
-
origin
- behavior に一致した場合に CloudFront がリクエストをルーティングするオリジン
- aws_cloudfront_origins
- CloudFront distribution のオリジンを定義するためのライブラリ
-
origins.S3BucketOrigin.withOriginAccessControl(destinationBucket)
-
S3BucketOrigin
- S3 Bucket を CloudFront distribution のオリジンとして設定
-
withOriginAccessControl
- OAC (Origin Access Control) を有効化して S3 Bucket オリジンを設定
-
S3 Deployment
new s3deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [s3deploy.Source.asset('./website-dist')],
destinationBucket,
distribution,
distributionPaths: ['/*'],
});
- aws_s3_deployment
- ローカル等の環境から、指定したファイルやディレクトリを S3 バケットに格納するためのライブラリ
-
sources
- S3 バケットに格納するデータの指定
-
s3deploy.Source.asset('./website-dist')
- source として
./website-dist
ディレクトリを指定
- source として
-
destinationBucket
- デプロイ先となる S3 バケット
-
distribution
- デプロイ先となる S3 バケットをオリジンにする CloudFront distribution
- S3 バケットへのデプロイ後、エッジキャッシュの invalidation が行われる
-
distributionPaths
- エッジキャッシュの invalidation を行う対象となる file path 指定
Cfn Output
new cdk.CfnOutput(this, 'Hosting URL', {
value: 'https://' + distribution.distributionDomainName
});
- CloudFormation Stack の Outputs を扱う
-
'https://' + distribution.distributionDomainName
で CloudFront distribution にアクセスする URL を生成
CDK App をデプロイ
npm run build
npx aws-cdk deploy
動作を確認
npx aws-cdk deploy
が成功したら Outputs に CloudFront distribution の URL が出力されるので、この URL にアクセスして HTML が表示されれば OK
Outputs:
MyProjectStack.HostingURL = https://abcdefg.cloudfront.net
curl で確認する例
% curl https://abcdefg.cloudfront.net
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
環境削除
npx aws-cdk destroy
感想など
- Web で調べた情報が一部古かったりして試行錯誤してしまったが、結果的にはシンプルに実現出来てよかった
- シンプルにファイルや Static Web Site をホストしたい場合にサクッと使えて便利
- React などで実装した SPA も、ビルドアーティファクトを Source Asset に指定すれば問題ない
- ただし CloudFront のデプロイが必要となるため、これはやや時間がかかってしまう
- 自分の環境だと、長い場合はデプロイに 5分 くらいかかる場面もあった
- 開発中は S3 の Web Site Hosting で試しつつ、本格的に稼働する際に CloudFront に乗せる・・・みたいな運用でも良いかもしれない
試した環境
開発環境
% sw_vers
ProductName: macOS
ProductVersion: 14.6.1
BuildVersion: 23G93
package.json
{
"name": "my-project",
"version": "0.1.0",
"bin": {
"my-project": "bin/my-project.js"
},
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"test": "jest",
"cdk": "cdk"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/node": "22.5.4",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
"aws-cdk": "2.159.0",
"ts-node": "^10.9.2",
"typescript": "~5.6.2"
},
"dependencies": {
"aws-cdk-lib": "2.159.0",
"constructs": "^10.0.0",
"source-map-support": "^0.5.21"
}
}
Discussion