Vercelで環境変数を変えて複数デプロイする方法


前提

  • github
    • リポジトリはprivate
    • main ブランチ = master ブランチ
  • vercel
  • next.jsは使っていてもいなくてもいい

やりたいこと

例えば、github上でmainへのPRをマージしたときに、vercel上では そのコードで 環境変数とドメインだけが異なる本番環境,デモ環境,開発環境の3つの環境がデプロイされるようにしたい

  • 本番環境(prod)
    • 本番用の環境変数を使い、実際に本番APIと疎通する
    • ドメインは a.com とする
  • デモ環境(demo)
    • デモ環境用の環境変数を使い、デモ環境用APIと疎通する
    • ドメインは a.demo.com とする
    • to Bの顧客が試す環境というイメージ
  • 開発環境(dev)
    • 開発用の環境変数を使い、開発環境用APIと疎通する環境
    • ドメインは a.dev.com とする
    • 開発者が試す環境

AWS Amplifyは1ブランチに対して環境変数などを変えた複数ビルドを構築することができる
しかしVercelは production preview develop deployの概念が思想としてあり、ビルドがどのdeploy typeになるかルールがあるので、単純にはそのようなことができない

解決までの流れとしては、

  1. main と自動で同期される demo, dev ブランチをつくる
  2. demo, devブランチとドメインを紐付ける
  3. 環境変数を変えたビルドを作る
  4. vercelのドメインURLがproduction deployになっているので、demo, devが検索にヒットしうる問題を解決する

となる

1 ブランチ同期

1.1 方法

を使う
sshとhttpsどちらでもcloneできるが、楽なhttpsを使う

.github/workflows/sync_branches.yml
# @see https://github.com/marketplace/actions/github-repo-sync

name: Sync branches

on:
  push:
    branches:
      - main

jobs:
  sync_branches:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
      with:
        persist-credentials: false
    - name: "force push main to demo"
      uses: repo-sync/github-sync@v2
      with:
        source_repo: https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/[organization name]/[repository name].git
        source_branch: "main"
        destination_branch: "demo"
        github_token: ${{ secrets.GITHUB_TOKEN }}
    - name: "force push main to dev"
      uses: repo-sync/github-sync@v2
      with:
        source_repo: https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/[organization name]/[repository name].git
        source_branch: "main"
        destination_branch: "dev"
        github_token: ${{ secrets.GITHUB_TOKEN }}

[organization name]/[repository name] のところは適宜置き換える

1.1.1 github token をURLに入れても安全なのか

には

Before each job begins, GitHub fetches an installation access token for the job. The token expires when the job is finished.

とあるので大丈夫そう

1.2 protected branchにpushしたい場合

GitHubのbranch protection に設定しているとGitHub Actionsもpush不能になる

1.2.1 回避方法1: Personal access tokenを使う

によると

    - uses: actions/checkout@v2
      with:
        persist-credentials: false

にしておき、 github.token ではなく personal access token を使えばよいらしい
デプロイに個人のpersonal access tokenを使うのは退職などを考えるとアンチパターンなので、CI用に共有するbotユーザーアカウントを作って使うとよさそう
(試してはいない)

1.2.2 回避方法2: git hooks の pre-pushで防ぐ

GitHubが公式に誤爆push防止できるようになったことで廃れた印象があるが、今回はGitHubに頼らない手段として利用できる

「人間が開発するときにだけpre-pushが入っており誤爆pushを防げて、GitHub Actionsはpushできる」という状態にしたい
これはpackage.jsonのpostinstallで生成すれば雑だが達成できる

1.2.3 その他の回避方法

https://github.com/marketplace/actions/git-sync-action でもできるかも
https://github.com/marketplace/actions/sync-branches はPRを自動生成してくれるaction。PRで同期したい派なら使える
Vercel CLI でやるのは茨の道

2 Custom Domainの設定

にあるように設定すると、demoブランチに対して a.demo.com のようなURLでアクセスできるようにビルドが紐づく

3 環境変数の異なるビルドを作る

が公式の説明
process.env.VERCEL_GIT_COMMIT_REF を使う

next.jsを使っている場合はnext.config.jsのenvを経由して切り替えて渡す必要がある

また、余談として

.env.production .env.development は性質が違うので使えない

4 Custom Domainを検索避けしなければいけない場合の対策

Custom Domainを設定すると、

The production domain(s) are defined from the Domains tab of a Project on the Vercel Dashboard.
To add a production domain to a Project, visit Domains from the Project > Overview page, you can read more about this in the custom domains documentation.

とあるように、 production deploy扱い となる

productionとpreviewの違いはレスポンスヘッダーに X-Robots-Tag: no-index がついて検索避けされるかどうか である
Domain設定したvercelのビルド結果を参照できる3つのURLを見ると実際に以下の違いがあった

  • a.demo.com みたいに自分でdomain設定したURL
    • x-robots-tag: no-index なし
  • リポジトリ名-git-demo-団体名.vercel.app みたいなvercelが勝手に作るURL
    • x-robots-tag: no-index あり
  • リポジトリ名-ハッシュ値-団体名.vercel.app みたいなvercelが勝手に作るURL
    • x-robots-tag: no-index あり

大まかに考えて、回避策としては

  • main 起因のビルドでないなら x-robots-tag: no-indexをつける
  • main 起因のビルドでないなら <meta name="robots" content="noindex, nofollow"> をつける
  • DNS設定でpreview buildのdomainに向ける

が考えられる

4.1 next.jsを使っている場合の回避方法

next.config.js
  async headers() {
    return process.env.VERCEL_GIT_COMMIT_REF === 'main'
      ? []
      : [
          {
            source: '/',
            headers: [
              {
                key: 'X-Robots-Tag',
                value: 'no-index',
              },
            ],
          },
          {
            source: '/:any*',
            headers: [
              {
                key: 'X-Robots-Tag',
                value: 'no-index',
              },
            ],
          },
        ];
  },

こういうのを書くとうまく設定された

4.2 DNS設定だけでなんとかする場合(失敗)

https://vercel.com/docs/custom-domains#dns-records
やRoute53などの各々が利用しているところで

a.demo.com
CNAME リポジトリ名-git-demo-団体名.vercel.app

みたいなのを設定すればCustom Domainの設定も要らず、Custom Domainがproduction deployになる問題も楽に回避できるかと思ったが、何故か以下のような画面になって失敗した

感想

  • vercelにCustom Domainにもpreview modeを指定する設定がないのが不便に感じる
    • 要望出そうかな→feedbackに書いて送ってみた
  • vercelのpassword protectionの柔軟性がないこと等も含めてどうしてもうまく運用にマッチしない場合は、amplifyとか別のサービスをdev,demo作成に使うのが良いと思う
    • serverless functionに依存していたら使えない

参考資料