今年の夏にこのブログをHugoに移行しましたが、移行後はAWS上のS3+CloudFrontで動かしています。
現在の構成を簡単な図にすると以下のような形です。
EC2 on WordPressからの移行ということで、ミドルウェア類の管理の煩わしさからの解放と、料金的なメリットが非常に大きかったです。
一方、コンテンツの更新は面倒になり、更新するにはビルドしてS3バケットにアップロード、といった手順が必要となりました。
そこで、ビルドと更新を自動化する為、CodeBuildでコンテンツの更新をで行う仕組みを構築することとしました。
- MarkdownなどHugoのコンテンツはGitHubで管理する
- GitHubでmasterブランチへのPushを検知したらCodeBuildで自動的にビルドする
- ビルドが完了したらS3バケットにアップロードする
- CloudFrontのキャッシュを削除し更新後のコンテンツがすぐに表示されるようにする
本記事は既に前述の構成が組まれていることが前提となります。
S3+CloudFrontの構築方法については記載がございませんのでご注意ください。
最終的な構成図
以下のようにAWS上にCodeBuildを新規構築、記事となるMarkdownの管理にGitHubを新規導入しています。
導入方法について順番に記載していきます。
GitHub
GitHub上にHugoのコンテンツを管理するリポジトリを作成します。
プライベートリポジトリで問題ありません。
クローンしてhugoコマンドを実行し、問題なくビルドが行えるよう設定ファイル、テーマや画像などの静的コンテンツも格納します。
ただし、hugoコマンドでビルド後に生成されるコンテンツ(public
ディレクトリ配下)は必要ありません。
また、リポジトリのルートにはbuildspec.yml
というファイル名で以下のファイルを追加します。
version: 0.2
phases:
install:
commands:
- mkdir /tmp/hugo
- curl -Ls https://github.com/gohugoio/hugo/releases/download/v0.121.1/hugo_0.121.1_linux-amd64.tar.gz -o /tmp/hugo.tar.gz
- tar xf /tmp/hugo.tar.gz -C /tmp/hugo
- mv /tmp/hugo/hugo /usr/bin/hugo
- rm -rf /tmp/hugo*
build:
commands:
- hugo
post_build:
commands:
- aws s3 sync --delete public/ s3://[S3バケット名]
- aws cloudfront create-invalidation --distribution-id ${DISTRIBUTION_ID} --paths '/*'
phases > post_build > commands
の[S3バケット名]
は自身が管理しているS3バケット名に置き換えてください。
このファイルをCodeBuildが検知しファイル内のコマンドを実行していきます。
以下を実行するよう定義しています。
- hugoコマンドが実行できるようhugoのバイナリをダウンロードし配置
- hugoコマンドを実行しビルド
- 生成されたpublicディレクトリ配下をS3バケットにアップロード
- CloudFrontへキャッシュ削除リクエスト
CodeBuild
AWSコンソールから CodeBuild > ビルドプロジェクト > ビルドプロジェクトを作成する
と遷移し新規作成画面を表示します。
以降は自動ビルド構築に必要な項目についてのみ記載していきます。
GitHubとの接続
先ほど作成したリポジトリと接続する為、ソース内のソースプロバイダから「GitHub」を選択、リポジトリは「OAuthを使用して接続する」を選択しGitHubに接続ボタンを押下します。
認証が完了するとリポジトリが選択出来るようになるので、先ほど作成したリポジトリを選択します。
プライマリソースのウェブフックイベント
master
ブランチへのプッシュを条件にビルドを開始するよう設定します。
「コードの変更がこのレポジトリにプッシュされるたびに再構築する」にチェックを入れ、追加の入力項目を表示します。
「イベントタイプ」から「プッシュ」を選択、「HEAD_REF - オプショナル」には^refs/heads/master$
を入力します。
環境
今回はEC2環境上に都度ビルド環境を作りビルドを実行する形式とします。
画面が縦長で見づらいので、ポイントを記載します。
「追加設定」内に設定する項目もあるので、必ず開くようにしてください。
- 環境イメージ:マネージド型イメージ
- コンピューティング:EC2
- サービスロール:新しいサービスロール
- 環境変数:
- TZ:
Asia/Tokyo
- DISTRIBUTION_ID: CloudFrontのディストリビューションID
- TZ:
※OSをUbuntu
としているのはローカルのビルド環境がUbuntuだった為合わせただけです。
環境変数のDISTRIBUTION_ID
はGitHubにプッシュしたbuildspec.yml
の最後の行に記載した
- aws cloudfront create-invalidation --distribution-id ${DISTRIBUTION_ID} --paths '/*'
にて使用されます。
他はデフォルトで選択されている値でビルドプロジェクトを作成します。
GitHub側の確認
ビルドプロジェクトが作成されるとGitHub側のWebhooksに設定が追加されるので確認します。
リポジトリのSettings > Webhooks
と遷移すると以下のようにCodeBuildのURLの設定が表示されます。
これが表示されていればCodeBuildとGitHubの連携については完了です。
IAM
CodeBuildのプロジェクト作成で新しく作成したサービスロールに権限を追加します。
IAM > ポリシー
と遷移し、先ほど作成したポリシーを選択します。
ポリシーは1,000個以上ありますがCodeBuild
で検索すると出てきます。
ポリシーを編集する為、許可タブ内の編集ボタンを押下します。
ポリシーエディタで「JSON」を選択すると以下のような画面が表示されます。
CodeBuildの実行に必要なポリシーが設定されているので、ビルドしたファイルのアップロード、CloudFrontのキャッシュ削除の2つが行える権限を追加します。
ポリシーエディタ内のJSONのStatement
内に以下のJSONを追加します。
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": [
"arn:aws:s3:::[bucket name]"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::[bucket name]/*"
]
},
{
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": [
"arn:aws:cloudfront::[account id]:distribution/[distribution id]"
]
}
[bucket name]
はアップロード先のS3バケット名、[account id]
はAWSのアカウントID、[distribution id]
はCloudFrontのディストリビューションIDにそれぞれ置換してください。
動作確認
ここまで設定した内容に問題がないか動作確認をします。
試しにGitHubのリポジトリのmasterブランチに新しいコミットを追加しPUSHします。
GitHubとCodeBuildの連携に問題がなければ、PUSH後にAWSコンソール上のCodeBuild > ビルドプロジェクト
で以下のようにビルドステータスが「進行中」となり自動ビルドが走るようになります。
あとがき
ということで、だいぶ簡潔にですが設定方法のメモを記載しました。
この記事もCodeBuildでビルドされて公開されています(問題なく動いていれば)。
ビルドはEC2ではなくECRを使うとかLambdaを使うとか他にも方法はあるかもしれませんので、様子を見ながら改善していきたいなと思います。
自動ビルドはGitHub Actionsでも出来るかと思いますが、ビルド以降の処理はAWS側に全てを寄せたいという意向でCodeBuildを使用することにしました。
だったらリポジトリもCodeCommitでも良かったのでは……?と思いましたが、まあそこは考えないことに。