本記事はCloudflareのカレンダー 16日目の記事です
Gatsby製のブログをNetlifyからCloudflarePagesに移行したが考慮不足でしばらく気付かず問題があったのでメモ
直前のデプロイ時から、特定ディレクトリ以下に差分があるかチェックし、処理を分ける
前提
- Gatsby製のブログ
- 記事の全文検索にAlgoliaを使っている
- gatsby-plugin-algoliaを使ってインデックスの更新を行っている
ビルド時に前回デプロイからの差分を確認し、記事ファイルにのみ差分がある場合はAlgoliaのインデックスを更新する
常に更新にすると、RenovateなどのPRでインデックスの更新が走ってしまい以前のAlgoliaの無料枠で収まらなくなってしまうため(だったはず)
上記前提の元、Cloudflareへ移行後からAlgoliaのIndex更新が途絶えていた
移行時の記事
Netlifyの場合
Netlifyではビルド時の環境変数に$CACHED_COMMIT_REF
,$COMMIT_REF
が用意されている
Build environment variables | Netlify Docs
- CACHED_COMMIT_REF
- 現在のビルドの直前のビルドで使用したコミットハッシュ
- COMMIT_REF
- 現在のビルドで使用するコミットハッシュ
この2つを用いて前回のデプロイ時のコミットから記事のディレクトリ以下に差分があった場合はAlgoliaのインデックスを更新する処理を走らせる
ということをしていた
Netlifyでしか扱えない環境変数を前提としてデプロイスクリプトを書いていたため、CloudFlareに移行後は当然正常に動かなくなっていた
Cloudflare Pagesの場合
Build configuration · Cloudflare Pages docs
環境変数を見ると現在のコミットREFしかなさそう
前回デプロイビルド時のCOMMIT SHAを何かしらの方法で取得する必要がある
CloudflareのAPIを使って直前のデプロイ時のコミットハッシュを取得する
デプロイに関するAPIが用意されているのでそれを使って直前のデプロイ時のコミットハッシュを取得できる
CloudflareのアカウントIDはWorkers & Pages
のOverviewで右側メニューのAccount ID
というところで確認できる
Pagesのデプロイリストを取得
事前に下記を環境変数に設定しておく
- CF_ACCOUNT_ID: アカウントID
- CF_API_KEY: CloudflareのAPIキー
- CF_PROJECT: Pagesのプロジェクト名
curl -X GET "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PROJECT}/deployments" \ -H "Authorization: Bearer ${CF_API_KEY}" \ -H "Content-Type:application/json"
下記はドキュメントのExampleから持ってきたレスポンスのサンプル
{ "errors": [], "messages": [], "result": [ { "aliases": [ "https://branchname.projectname.pages.dev" ], "build_config": null, "created_on": "2021-03-09T00:55:03.923456Z", "deployment_trigger": { "metadata": { "branch": "main", "commit_hash": "ad9ccd918a81025731e10e40267e11273a263421", "commit_message": "Update index.html" }, "type": "ad_hoc" }, "env_vars": { "BUILD_VERSION": { "value": "3.3" }, "ENV": { "value": "STAGING" } }, "environment": "preview", "id": "f64788e9-fccd-4d4a-a28a-cb84f88f6", "is_skipped": true, "latest_stage": null, "modified_on": "2021-03-09T00:58:59.045655", "project_id": "7b162ea7-7367-4d67-bcde-1160995d5", "project_name": "ninjakittens", "short_id": "f64788e9", "source": null, "stages": [ { "ended_on": "2021-06-03T15:39:03.134378Z", "name": "queued", "started_on": "2021-06-03T15:38:15.608194Z", "status": "active" }, { "ended_on": null, "name": "initialize", "started_on": null, "status": "idle" }, { "ended_on": null, "name": "clone_repo", "started_on": null, "status": "idle" }, { "ended_on": null, "name": "build", "started_on": null, "status": "idle" }, { "ended_on": null, "name": "deploy", "started_on": null, "status": "idle" } ], "url": "https://f64788e9.ninjakittens.pages.dev" } ], "success": true, "result_info": { "count": 1, "page": 1, "per_page": 100, "total_count": 1 } }
deployment_trigger.metadata
にコミットハッシュやブランチの情報が入っている
また、日時で降順になっている、実際に試してみたら現在実行中のデプロイの情報もこのリストに含まれるようだった
デプロイスクリプトでAPIの情報を利用する場合、1つ目は今実行中のデプロイということになるので次のデプロイを指定する必要がある
あとは対象ブランチをdefaultブランチ(productionビルドを行うブランチ)でのデプロイに絞ってあげればOK
ということでちょっと微妙だが
jq '.result[]|select(.deployment_trigger.metadata.branch=="master")' | jq -scr '.[1]|.deployment_trigger.metadata.commit_hash'
- 0: 現在のデプロイ
- 1: 1つ前のproductionデプロイ
という感じで直前のデプロイのコミットハッシュを取得できる
デプロイ時の環境
見直したらもう少し改善余地がありそうだが次のようなデプロイスクリプトとなった
- deploy.sh
#!/bin/bash # install jq curl -o $HOME/.local/bin/jq -L https://github.com/jqlang/jq/releases/download/jq-1.7/jq-linux64 && chmod +x $HOME/.local/bin/jq git fetch --depth 100 if [ "$BUILD" = "production" ]; then res=$(curl -X GET "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/til/deployments" \ -H "Authorization: Bearer ${CF_API_KEY}" \ -H "Content-Type:application/json") LATEST_DEPLOY_COMMIT_SHA=$(echo ${res} | jq '.result[]|select(.deployment_trigger.metadata.branch=="master")' | jq -scr '.[1]|.deployment_trigger.metadata.commit_hash') # 差分があると終了コード1 git diff --quiet $LATEST_DEPLOY_COMMIT_SHA $CF_PAGES_COMMIT_SHA content/blog/entries/ rc=$? if [ "$rc" = "1" ]; then echo "content changed." CONTENT_CHANGED=true yarn build else echo "content not changed." CONTENT_CHANGED=false yarn build fi else echo "this build is preview build." CONTENT_CHANGED=false yarn build fi
これをデプロイ時に実行するようにCloudflare Pagesで設定しておく
CONTENT_CHANGED
の値によってAlgoliaのプラグイン側で、インデックスの更新可否を判断している
以下デプロイ環境で必要だったので処理を追加している
- Build V2環境を利用しているため
jq
が入っていなかったのでインストール - デプロイ時のチェックアウトは
--depth 0
でソースコードを取得しているようだったので、デプロイスクリプトでgit fetch --fetch 100
を追加- さすがに100あればコミットハッシュを取得できるだろうという理由
これで無事直前のデプロイと差分があるか確認できるようになり、差分がある場合はAlgoliaのインデックスを更新するというような分岐ができるようになった
まとめ
- CloudFlare Pagesのビルドプロセス上でAPIをたたいてデプロイ情報を取得した
- デプロイ情報からコミットハッシュを取得して現在のデプロイのコミットハッシュと比較して特定ディレクトリ以下に差分があるか判断できるようにした
- 差分がある場合はAlgoliaのインデックス更新処理を走らせるようにした
NetlifyでやっていたことをCloudfFlare Pagesのデプロイプロセスでも実現できるようにした
CloudflareのAPIキーの発行は権限の設定を細かく設定できてある程度リスク管理できるよう
勉強にはなりました