ブラックボックス

プログラミングのノウハウやライフハックをどんどん投稿していきたい

Dec 30, 2023 - 6 minute read - ノウハウ

【Hugo】S3+CloudFront上のHugoをCodeBuildで自動デプロイする

今年の夏にこのブログを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が検知しファイル内のコマンドを実行していきます。

以下を実行するよう定義しています。

  1. hugoコマンドが実行できるようhugoのバイナリをダウンロードし配置
  2. hugoコマンドを実行しビルド
  3. 生成されたpublicディレクトリ配下をS3バケットにアップロード
  4. CloudFrontへキャッシュ削除リクエスト

CodeBuild

AWSコンソールから CodeBuild > ビルドプロジェクト > ビルドプロジェクトを作成すると遷移し新規作成画面を表示します。
CodeBuild

以降は自動ビルド構築に必要な項目についてのみ記載していきます。

GitHubとの接続

先ほど作成したリポジトリと接続する為、ソース内のソースプロバイダから「GitHub」を選択、リポジトリは「OAuthを使用して接続する」を選択しGitHubに接続ボタンを押下します。
GitHubとの接続

認証が完了するとリポジトリが選択出来るようになるので、先ほど作成したリポジトリを選択します。
GitHubリポジトリ

プライマリソースのウェブフックイベント

masterブランチへのプッシュを条件にビルドを開始するよう設定します。
「コードの変更がこのレポジトリにプッシュされるたびに再構築する」にチェックを入れ、追加の入力項目を表示します。
GitHubリポジトリ
「イベントタイプ」から「プッシュ」を選択、「HEAD_REF - オプショナル」には^refs/heads/master$を入力します。

環境

今回はEC2環境上に都度ビルド環境を作りビルドを実行する形式とします。
画面が縦長で見づらいので、ポイントを記載します。
環境

「追加設定」内に設定する項目もあるので、必ず開くようにしてください。

  • 環境イメージ:マネージド型イメージ
  • コンピューティング:EC2
  • サービスロール:新しいサービスロール
  • 環境変数:
    • TZ: Asia/Tokyo
    • DISTRIBUTION_ID: CloudFrontのディストリビューションID

※OSをUbuntuとしているのはローカルのビルド環境がUbuntuだった為合わせただけです。

環境変数のDISTRIBUTION_IDはGitHubにプッシュしたbuildspec.ymlの最後の行に記載した

      - aws cloudfront create-invalidation --distribution-id ${DISTRIBUTION_ID} --paths '/*'

にて使用されます。

他はデフォルトで選択されている値でビルドプロジェクトを作成します。

GitHub側の確認

ビルドプロジェクトが作成されるとGitHub側のWebhooksに設定が追加されるので確認します。
リポジトリのSettings > Webhooksと遷移すると以下のようにCodeBuildのURLの設定が表示されます。
Webhooksの設定
これが表示されていればCodeBuildとGitHubの連携については完了です。

IAM

CodeBuildのプロジェクト作成で新しく作成したサービスロールに権限を追加します。
IAM > ポリシーと遷移し、先ほど作成したポリシーを選択します。
ポリシーは1,000個以上ありますがCodeBuildで検索すると出てきます。
IAM

ポリシーを編集する為、許可タブ内の編集ボタンを押下します。
ポリシーの詳細

ポリシーエディタで「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でも良かったのでは……?と思いましたが、まあそこは考えないことに。