VercelへのデプロイをGitHub Actions経由で行うことでVercelチームメンバー以外でも開発に参加できるようにする
TL;DR
- フロントエンドをVercelでホストするプロジェクトをチームで開発していた
- Vercelにチームを作り、開発メンバー全員をチームに招待して、月額$20×人数を支払っていた
- なぜなら、Vercelの標準のGitHub連携を使う場合、GitHubにコミットするメンバーは全員Vercelのチームメンバーである必要がある ため
- GitHub連携をしている状態で、Vercelのチームメンバーでない人がGitHubにコミットをpushすると、Vercelへのプレビューデプロイが失敗してCIが赤くなる
- 自分以外の開発メンバーはVercelのダッシュボードを触ることはまったくないのに、GitHub連携のためだけに全員分の $20 を払うのはさすがにもったいなかった
- そこで、Vercelの標準のGitHub連携を使うのをやめて、自分のアクセストークンを使ってGitHub Actions経由でVercelへデプロイするように設定し、自分以外の開発メンバーはVercelのチームメンバーでなくした
Vercel標準のGitHub連携の問題点(?)
皆さんご存知のとおり、Vercelには標準でGitHubなどのGitリポジトリと連携してデプロイを自動化してくれる機能があります。
この画面の GitHub
ボタンからリポジトリを選んでセットするだけで、そのリポジトリへのコミットが自動でVercelにデプロイされるようになり、さらに Production Branch
で指定したブランチへのコミットの場合のみ自動でProduction環境にプロモートしてくれるようになります。
便利すぎますね。
しかしチーム開発でこの機能を使う場合、Vercelのプロジェクトを所有するチームのメンバーでないGitHubユーザーがコミットをpushすると、そのコミットに対するVercelへのプレビューデプロイが権限不足により失敗してしまいます。
これを回避するためには、GitHubリポジトリにコミットをpushする可能性のある開発者全員をVercelチームのメンバーにしておく必要があります。
2023年4月現在の Vercelの料金体系 では、チームメンバーは全員最低でもProプラン($20/mo)でなければならないので、単純に 月額$20×開発者の人数 のお金が必要になります。
サービスを便利に使わせてもらう以上、然るべき対価を支払うのは当然のことなのですが、開発者全員がVercel自体のダッシュボードとかを触りたいわけでもないのに、デプロイを自動化するためだけに、ごく稼働の少ない人も含めて全員に対して一律$20/moというのは、さすがに財布が辛すぎるというのが正直な感想です…💸
Vercelチームメンバーを自分一人にして大幅節約
よくよく調べてみると、以下の公式ドキュメントにてGitHub Actions経由で手動でVercelにデプロイする方法が紹介されていました。
How to Use GitHub Actions to Deploy to Vercel
これを使えば、自分以外の開発メンバーをVercelチームのメンバーから外しても、標準のGitHub連携を使っているときと同じ体験が得られそうです。
細かい説明は後回しにして先に結論を言うと、最終的に以下のようなワークフローを書くことで期待どおりの結果を得ることができました🙌
# .github/workflows/ci.yaml
name: CI
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
on: push
jobs:
test:
# 略
preview:
if: ${{ github.ref != 'refs/heads/release' }}
needs: test
runs-on: ubuntu-latest
environment:
name: preview
url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 18
check-latest: true
- name: Install Vercel CLI
run: npm install --global vercel@latest
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy Project Artifacts to Vercel
id: deploy
run: echo "url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT
- name: Assign staging domain to deployment (if main branch)
if: ${{ github.ref == 'refs/heads/main' }}
run: vercel alias ${{ steps.deploy.outputs.url }} stg.my-service.com --scope=my-team --token=${{ secrets.VERCEL_TOKEN }}
prod:
if: ${{ github.ref == 'refs/heads/release' }}
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 18
check-latest: true
- name: Install Vercel CLI
run: npm install --global vercel@latest
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy Project Artifacts to Vercel
run: vercel deploy --prod --prebuilt --token=${{ secrets.VERCEL_TOKEN }}
大枠は
How to Use GitHub Actions to Deploy to Vercel
に書かれているとおりです。
ただし、この例では、本番にデプロイするブランチは main
ではなく release
です。
また、テストのジョブに依存(needs
)させたかったので、ドキュメントの例とは違って1ファイルにまとめた上でジョブの if
文で対象のブランチを分けています。
workflow_run
を使えば別ファイルのワークフローに依存したワークフローを書けるので必ずしも1ファイルにまとめる必要はないのですが、個人的にこっちのほうが慣れてて分かりやすいのでこうしました。
上記ドキュメントで言及されていないこともいくつかやっています。
まずは preview
ジョブの Deploy Project Artifacts to Vercel
ステップに注目してください。
- name: Deploy Project Artifacts to Vercel
id: deploy
run: echo "url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT
vercel deploy
コマンドを実行するだけでなく、そのの出力結果(デプロイメントのURL)を GITHUB_OUTPUT
環境変数に url
という名前を付けて格納しています。
この結果が、preview
ジョブの定義冒頭部分の
environment:
name: preview
url: ${{ steps.deploy.outputs.url }}
で利用されており、これによって preview
という名前のデプロイ環境にVercelのプレビューデプロイのURLが紐づき、結果としてPRのConversationタブに下図のような行が出力され、PRの画面から直接プレビューデプロイを見に行くことができるようになります。
参考
また、もう一点特筆すべき点として、preview
ジョブの Assign staging domain to deployment (if main branch)
ステップに注目してください。
- name: Assign staging domain to deployment (if main branch)
if: ${{ github.ref == 'refs/heads/main' }}
run: vercel alias ${{ steps.deploy.outputs.url }} stg.my-service.com --scope=my-team --token=${{ secrets.VERCEL_TOKEN }}
これは、main
ブランチへのpushの場合のみ、vercel alias
コマンドを使ってデプロイメントのURLにステージング環境のドメインをアサインするという処理です。
stg.my-service.com
という部分は、ステージング環境のドメインのつもりで書いていますmy-team
という部分は、Vercelのチーム名のつもりで書いています
Vercel標準のGitHub連携では、特定のブランチに対してサブドメインを割り当てるということがドメインの設定画面から簡単にできました(下図)が、今回はこれも手動で行う必要があるわけです。
また、そもそもですが、
How to Use GitHub Actions to Deploy to Vercel
に書かれているとおり、このワークフローが実際に動作するには、VERCEL_TOKEN
VERCEL_ORG_ID
VERCEL_PROJECT_ID
という3つのシークレットが設定されている必要があります。
VERCEL_TOKEN
は https://vercel.com/account/tokens で作成したもの、VERCEL_ORG_ID
VERCEL_PROJECT_ID
はローカルで vercel login && vercel link
して作成された .vercel/project.json
から得られるものをそれぞれ設定すればOKです。
まとめ
というわけで、VercelへのデプロイをGitHub Actions経由で行うことでVercelチームメンバー以外でも開発に参加できるようにする(結果的に大幅に費用を節約する)方法を解説しました。
他の開発メンバーのコミットもすべて自分のアクセストークンを使ってデプロイされるようになるので、あまりに規模の大きいプロジェクトでは1日のデプロイ数の制限(Proプランだと3,000)に気をつける必要があるかもしれませんが、多くのケースでほとんど問題にならないでしょう。
以上、お役に立てば幸いです。
Discussion
ありがとうございます!参考にさせていただきました🙏
一箇所想定どおりに動かない箇所があり、
が自分の場合はうまく動作してくれませんでした。
参考とされていたHow to deploy to Vercel with GitHub Actionsに沿って、下記のように変更したところ、想定どおりにView deploymentが表示されました。
コメントありがとうございます!
2022/10/11に
でアナウンスされているとおり、
::set-output
はすでに非推奨となっており、本稿で使用したが新しく導入された正しい記法となっています。
リンク先にも記載があるとおり、self-hosted runner を使っている場合にはバージョンの指定を
2.297.0
以上にしないと新しい記法が使えるようにならないようなので、動かないのはそれが原因でしょうかね・・ubuntu-latest
などの GitHub-hosted runner を使っている場合には特に何もしなくても新しい記法が使える認識です。このことは把握していませんでした。ありがとうございます🙏
ただ、
ubuntu-latest
なんですけど、想定どおり動かなかったんですよね…。何かまた進展があればコメントさせていただきます。
そしたら、ちょっと謎ですね、、😓
もし何か分かったら教えていただけるとありがたいです🙏