メインコンテンツまでスキップ

Amazon S3 + CloudFrontで静的サイトを配信する - CodePipelineによるCI/CD構築

· 約12分
Shinya Kato
DayoneLabs管理人、ソフトウェア開発者、OSS開発者

Amazon S3 + CloudFrontで静的サイトを配信する - CodePipelineによるCI/CD構築

どうも、Shinyaです。この記事では、Docusaurusで作成した静的サイトのリソースをAmazon S3にオリジンとして配置し、Amazon CloudFrontで配信する構成の構築手順について解説します。AWS CodeCommit、CodeBuild、CodePipelineを組み合わせたCI/CDパイプラインにより、コンテンツの管理からビルド・配信までをAWSエコシステム内で完結させています。

この記事はこんな人にオススメ
  • Amazon S3 + CloudFrontで静的サイトを配信したい人
  • AWS CodePipelineを使ったCI/CDパイプラインに興味がある人
  • Docusaurusで作成したサイトをAWSにデプロイしたい人
  • AWSエコシステム内でコンテンツ管理から配信まで一貫して構築したい人
前提記事

この記事は、WordPressからDocusaurusへの移行記事の続編です。移行の経緯や技術選定の背景については、そちらの記事で解説しています。

全体構成

今回構築するシステムは、以下のAWSサービスで構成されています。

サービス役割
AWS CodeCommitGitリポジトリによるソースコード・コンテンツの管理
AWS CodePipelineCodeCommitへのプッシュ検知からCodeBuild実行までのパイプラインオーケストレーション
AWS CodeBuildDocusaurusの静的サイトビルドとS3への成果物配置
Amazon S3ビルド成果物のオリジンストレージ
Amazon CloudFrontCDNによるコンテンツ配信

コンテンツ作成から配信までのフロー

この構成の利点

S3 + CloudFront構成の利点
  • S3 + CloudFrontの組み合わせは、静的サイトホスティングにおけるAWSの標準的な構成パターン
  • S3のイレブンナイン(99.999999999%)の耐久性により、データの高い保全性を確保できる
  • CodeCommit、CodePipeline、CodeBuild、S3、CloudFrontとAWSエコシステム内でコンテンツ管理から配信まで完結できる
  • 将来的にリリースされるAWSサービスとの統合も期待できる

S3バケットの作成

最初に、CloudFrontのオリジンおよびCodeBuildのビルド成果物の配置先として機能するS3バケットを作成します。

AWS CLIを使用してバケットを作成します。バケット名はAWS全体で一意である必要があります。

aws s3 mb s3://YOUR-BUCKET-NAME

バケットが作成されたことを確認します。

aws s3 ls s3://YOUR-BUCKET-NAME

パブリックアクセスの遮断

S3バケットはデフォルトでパブリックアクセスがすべてブロックされています。この設定により、S3バケットのURLに直接アクセスしてもコンテンツを取得することはできません。

コンテンツへのアクセスはCloudFront経由に限定されます。CloudFrontでディストリビューションを作成しS3をオリジンとして指定すると、CloudFrontがOrigin Access Control(OAC)を通じてS3バケットにアクセスするためのポリシーを自動的に設定します。

この構成には以下のセキュリティ上の利点があります。

項目説明
パブリックアクセスの遮断S3バケットへの直接アクセスがブロックされ、意図しないコンテンツの公開を防止
CloudFrontへのアクセス集約すべてのリクエストがCloudFrontを経由するため、WAFやアクセスログなどのセキュリティ機能を一元的に適用可能
OACによるアクセス制御CloudFrontのみがS3バケットにアクセスできるポリシーが自動設定される
デフォルト設定のまま運用可能

S3のパブリックアクセスブロックはデフォルトで有効なため、バケット作成後に追加の設定は不要です。CloudFrontのディストリビューション作成時にOACとバケットポリシーが自動的に構成されます。

CodeCommitでのソースコード管理

今回の構成では、AWSエコシステムへの統合を目指し、AWS CodeCommitでWebサイトのソースコードと記事コンテンツを管理しています。CodeCommitはAWSが提供するマネージドGitリポジトリサービスで、GitHubなどと同じGitベースの操作が可能です。

まず、CodeCommitにリポジトリを作成し、Docusaurusプロジェクトのソースコードをプッシュします。

buildspec.ymlの配置

後述するCodeBuildでビルドを実行するために、buildspec.ymlをリポジトリのルートに配置します。buildspec.ymlはCodeBuildが参照するビルド仕様ファイルで、ビルドの各フェーズで実行するコマンドを定義します。

以下は、Docusaurusプロジェクトで使用しているbuildspec.ymlの例です。

buildspec.yml
version: 0.2

phases:
install:
runtime-versions:
nodejs: 24
commands:
- npm install

build:
commands:
- npm run build

post_build:
commands:
- aws s3 sync ./build s3://YOUR-BUCKET-NAME/ --delete

artifacts:
files:
- 'build/**/*'
name: BuildArtifact

cache:
paths:
- 'node_modules/**/*'

各セクションの役割は以下の通りです。

セクション役割
phases.installNode.js 24のランタイムを指定し、npm installで依存パッケージをインストール
phases.buildnpm run buildでDocusaurusの静的サイトをビルド
phases.post_buildaws s3 syncでビルド成果物をS3バケットに同期。--deleteフラグにより、S3上の不要なファイルも削除される
artifactsビルド成果物の出力先を定義
cachenode_modulesをキャッシュし、次回以降のビルドを高速化
S3バケット名の置き換え

YOUR-BUCKET-NAMEの部分は、先の手順で作成したS3バケットの名前に置き換えます。

CodeBuildによるビルド環境の構築

AWS CodeBuildでビルドプロジェクトを作成し、CodeCommitのリポジトリからソースを取得して静的サイトをビルドする環境を構築します。

ビルドプロジェクトの作成

CodeBuildの管理画面からビルドプロジェクトを作成します。設定のポイントは以下の通りです。

  1. プロジェクト名: 一意のプロジェクト名を設定
  2. ソースの設定: ソースプロバイダに「CodeCommit」を選択し、ビルド対象のリポジトリとブランチを指定
  3. 環境の設定: OSは「Linux」、ランタイムは「Standard」、イメージは「aarch64」の最新バージョンを選択
  4. サービスロール: 「新しいサービスロール」を選択し、自動作成されるロールを使用
  5. Buildspec: 「buildspecファイルを使用する」を選択(リポジトリルートのbuildspec.ymlが参照される)

S3アクセス用のIAMポリシー設定

CodeBuildで自動作成されるサービスロールには、S3への操作権限が含まれていません。buildspec.ymlpost_buildフェーズでS3バケットへの同期を実行するために、以下のカスタムポリシーを作成し、サービスロールにアタッチします。

S3アクセス用カスタムポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3SyncForBuild",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::YOUR-BUCKET-NAME",
"arn:aws:s3:::YOUR-BUCKET-NAME/*"
]
}
]
}
IAMポリシーの設定漏れに注意

このポリシーをアタッチしないと、CodeBuildの実行時にS3バケットへのアクセスが拒否され、post_buildフェーズでエラーが発生します。ビルドログにAccess Deniedが表示された場合は、サービスロールのポリシー設定を確認します。

各アクションの用途は以下の通りです。

アクション用途
s3:PutObjectビルド成果物のアップロード
s3:GetObject既存オブジェクトの取得(同期時の差分確認)
s3:ListBucketバケット内のオブジェクト一覧取得(同期時の差分確認)
s3:DeleteObject--deleteフラグによる不要ファイルの削除

CodePipelineによるパイプラインの構築

CodeBuildの設定のみでは、CodeCommitへのプッシュを自動的に検知してビルドを実行することはできません。CodeCommitへのプッシュをトリガーとした自動ビルドを実現するために、AWS CodePipelineを使用してCI/CDパイプラインを構築します。

パイプラインの作成

CodePipelineの管理画面からパイプラインを作成します。設定のポイントは以下の通りです。

  1. パイプラインタイプ: 「カスタムパイプラインを構築する」を選択
  2. パイプライン名: 一意の名前を指定(例: codepipeline-xxx-build
  3. サービスロール: 「新しいサービスロール」を選択
  4. ソースステージ: CodeCommitを選択し、ビルド対象のリポジトリとブランチを指定
  5. 変更検出: 「ソースの変更を自動的に検出するEventBridgeルールを作成」にチェックが入っていることを確認
  6. ビルドステージ: 「その他のビルドプロバイダー」からCodeBuildを選択し、先に作成したビルドプロジェクトを指定
  7. テストステージ: スキップ
  8. デプロイステージ: スキップ(S3へのデプロイはbuildspec.ymlpost_buildで実行するため)
EventBridgeによる変更検知

ソースステージの設定で「EventBridgeルールを作成」にチェックを入れると、CodeCommitのリポジトリへのプッシュイベントをAmazon EventBridgeが検知し、自動的にパイプラインを起動します。

パイプラインの作成が完了すると、以下のフローが自動化されます。

CloudFrontによるコンテンツ配信

ディストリビューションの作成

Amazon CloudFrontでディストリビューションを作成し、S3バケットのコンテンツをCDN経由で配信します。

  1. CloudFrontの管理画面で「ディストリビューションを作成」を選択
  2. 必要に応じてプランを選択(検証目的であればフリープランで開始可能)
  3. Distribution name: サイト名など一意の名前を入力
  4. Distribution type: 「Single website or app」を選択
  5. ドメイン設定: Route 53でドメインを管理している場合は同時に設定可能(後からの設定も可能)
  6. Origin type: 「S3」を選択
  7. S3 origin: 先に作成したS3バケットを指定(「Browse S3」から選択可能)
  8. その他のオプションは初期値のまま、「Create distribution」まで進めてディストリビューションを作成

Default root objectの設定

ディストリビューションの作成後、管理画面の詳細セクションに「ディストリビューションドメイン名」が表示されます。これがCloudFrontから割り当てられた一時的なURLです。

ただし、初期状態ではルートURL(https://xxxx.cloudfront.net/)でアクセスした際にエラーが返される場合があります。これは、Default root objectが未設定のためです。

以下の手順で設定します。

  1. ディストリビューションの管理画面で「一般」タブを選択
  2. 「編集」を選択
  3. Default root objectの項目にindex.htmlを入力
  4. 変更を保存

この設定により、https://xxxx.cloudfront.net/へのアクセスが自動的にhttps://xxxx.cloudfront.net/index.htmlとして処理されます。

トラブルシューティング: AccessDeniedエラー

CloudFrontのディストリビューションドメイン名でサイトにアクセスした際に、以下のようなエラーが返される場合があります。

<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
</Error>

ディストリビューション作成前後でS3バケットのポリシーを手動で変更していない場合、このエラーの主な原因はDefault root objectの未設定です。

ディストリビューション作成時に、CloudFrontはS3バケットに対して必要なアクセスポリシーを自動的にアタッチします。そのため、ポリシーを手動で変更していなければ、権限の問題でこのエラーが発生することは通常ありません。

https://xxxx.cloudfront.net/index.htmlのようにファイル名を明示的に指定してアクセスが成功する場合は、Default root objectにindex.htmlを設定することで解消できます。

まとめ

この記事では、Docusaurusで作成した静的サイトをAmazon S3 + CloudFrontで配信し、CodeCommit、CodePipeline、CodeBuildによるCI/CDパイプラインを構築する手順について解説しました。

この構成により、CodeCommitへのプッシュをトリガーとして、ビルドからS3への配置、CloudFrontでの配信までが自動化されます。AWSエコシステム内でコンテンツ管理から配信までを一貫して運用できる点が、この構成の特徴です。


参考リンク:

免責事項:
当記事は管理人の開発時に書き留められたメモをもとにAIを活用して編纂されたものです。 管理人は記事の公開前に内容の校正・校閲を行い、記事の信頼性と正確性の向上に務めますが、それらを保証するものではありません。 また、当記事の編集時の誤字やコード例の不具合等によって読者が何らかの損害等を被った場合でも、管理人は一切の責任を負いません。 当記事に掲載したコンテンツの利用については自己責任でお願い致します。