しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure Static Web Apps のデプロイに Static Web Apps CLI を利用する

Azure Static Web Apps へアプリケーションをデプロイする際には GitHub Actions を使うことが多いはずですが、公式で用意されている Action はビルドまで行うように設計されているため、ビルドは自前で行ってデプロイだけを行いたいケースでは若干使いにくいです。

それ以外のケースでも、ちょっとした検証で GitHub からデプロイするように構成するのは非常に面倒なので、最近は Static Web Apps CLI を使ってデプロイをすることが多くなりました。

Static Web Apps CLI はローカルでの開発をサポートする機能だけではなく、そのまま Azure にデプロイする機能まで備えているため扱いやすいものとなっています。最近は個人で開発しているアプリで Static Web Apps へのデプロイは、あえて GitHub Actions 上で Static Web Apps CLI を使うようにしています。

公式の Action ではデプロイの認証情報として Deployment Token のみ利用可能ですが、Static Web Apps CLI では Deployment Token だけではなく Service Principal も利用可能になっているため、他の Azure リソースへのデプロイと認証情報を共有できるメリットもあります。

単純に Static Web Apps CLI のデプロイと言ってもパターンがあるので簡単にまとめておきます。

Deployment Token を利用したデプロイ

一番シンプルなデプロイ方法は Deployment Token を利用するものです。SWA CLI では --deployment-token パラメータか SWA_CLI_DEPLOYMENT_TOKEN 環境変数を使って渡すようになっています。Deployment Token の値でどの Static Web Apps にデプロイするか特定されるため、名前を指定する必要がありません。

swa deploy ./dist --env production --deployment-token ***

Azure Portal から GitHub を選択すると Deployment Token は自動で Secret に登録されますが、SWA CLI を使う場合は Azure Portal から Deployment Token をコピーする必要があります。

ローカルでの swa deploy コマンドの実行時に毎回 Deployment Token を指定するのは手間なので、環境変数に登録してから実行する方法が扱いやすいです。

対話型ログインを利用したデプロイ

Deployment Token を利用したデプロイはシンプルで扱いやすいですが、Deployment Token 自体の管理が非常に手間かつリスクになります。SWA CLI は Azure にログインして Deployment Token を管理する必要のないデプロイに対応しているため、更に扱いやすいものです。

最低限 swa deploy に渡す必要があるのは Static Web Apps の名前だけです。

swa deploy ./dist --env production --app-name ***

後は必要に応じて SWA CLI が Azure へのログインを行い、テナントやサブスクリプションの選択まで促してくれます。swa deploy に渡すパラメータで明示的にテナントとサブスクリプションを指定することも出来ますが、以下のように対話型で行った方が便利です。

最初にログインとサブスクリプションの選択を行うと、その情報は .env ファイルに保存されるため、次からはサブスクリプションを選択する必要なくデプロイが行えます。

Service Principal を利用したデプロイ

公式の Action でも要望が多く寄せられていた Service Principal を利用したデプロイも、SWA CLI は標準で対応しているので Static Web Apps のデプロイとバックエンドの App Service などのデプロイを同じ認証情報で行えるようになっています。

Service Principal を使う場合は swa deploy に渡すパラメータは一番多くなり、Client Secret の管理が少しネックになりますが、他と認証情報を共有できる強みは大きいです。

swa deploy ./dist --env production --app-name *** --tenant-id *** --subscription-id *** --client-id *** --client-secret ***

Deployment Token の時と同様に Service Principal の値は以下の環境変数を経由して渡すことも出来ます。

  • AZURE_TENANT_ID
  • AZURE_SUBSCRIPTION_ID
  • AZURE_CLIENT_ID
  • AZURE_CLIENT_SECRET

この環境変数は SWA CLI が内部で使っている Azure Identity が要求するものとなっています。なので他のアプリケーションでも使われている可能性があるのでバッティングには注意が必要です。

環境変数を設定するとデプロイは Static Web Apps の名前だけで済むようになるので楽です。

swa deploy ./dist --env production --app-name ***

Service Principal を使ったデプロイでは Static Web Apps への Contributor 権限が必要になります。App Service のようにリソース固有のロールは用意されていないので、強めの権限を与える必要があります。

GitHub Actions で SWA CLI を使ったデプロイフローを組む

Static Web Apps CLI を利用するとデプロイのみを簡単に実行できるので、GitHub Actions でのデプロイ時に利用するとビルドとデプロイを分離できるため、Oryx に依存しないアプリケーションに最適な方法でビルドを行えるようになります。

以下は Deployment Token を利用したシンプルなデプロイフローの例です。SWA CLI をインストールする手間は発生しますが、ビルドとデプロイを分離することで見通しも良くなっています。

name: Azure Static Web Apps CI/CD

on:
  push:
    branches: [ master ]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Use Node.js 20
      uses: actions/setup-node@v4
      with:
        node-version: 20

    - name: npm ci and build
      run: |
        npm ci --prefix frontend
        npm run build --prefix frontend

    - name: Deploy to Static Web App
      run: |
        npm i -g @azure/static-web-apps-cli
        swa deploy ./frontend/dist/ --env production --deployment-token ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}

実際に運用しているアプリケーションでも SWA CLI を使ったデプロイを既に組んであるので、こちらのワークフローも参考にしてください。それぞれの処理を分けておくとデプロイに失敗した場合に、失敗した処理だけリトライ出来るため効率的です。

そして Service Principal を利用したデプロイフローのサンプルは以下の通りになります。基本的には Deployment Token を利用する場合と同じですが、swa deploy に渡すパラメータを減らすため環境変数に Secrets の値を設定している点が異なっています。

name: Azure Static Web Apps CI/CD

on:
  push:
    branches: [ master ]

env:
  AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
  AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
  AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
  AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Use Node.js 20
      uses: actions/setup-node@v4
      with:
        node-version: 20

    - name: npm ci and build
      run: |
        npm ci --prefix frontend
        npm run build --prefix frontend

    - name: Deploy to Static Web App
      run: |
        npm i -g @azure/static-web-apps-cli
        swa deploy ./frontend/dist/ -n <SWA NAME> --env production --no-use-keychain

これまで説明していない --no-use-keychain についてですが、GitHub Actions 上ではキーチェーンが使えず問題となるため指定しています。

実際にデプロイフローを動かしてみると、以下のように Service Principal を使って Azure にログインを行い、Static Web Apps へのデプロイまで完了していることが確認出来ます。

Service Principal は権限がある Static Web Apps であれば自由にデプロイできるので、複数の Static Web Apps へのデプロイも 1 つの認証情報で実現出来ます。これは管理面からみると大きなメリットとなります。

Federated Credentials (OIDC) には未対応

既に GitHub Actions を使って Azure へのデプロイを組んだことのある人なら、絶対に Federated Credentials (OIDC) を使いたくなると思うのですが、残念ながら現時点の SWA CLI では対応していないため Client Secret の管理から逃げられません。

Federated Credentials については今回は説明しませんので、以下のエントリを参照してください。

SWA CLI は内部的に Azure Identity ライブラリを使用している関係上、Azure CLI から認証情報を取得出来れば綺麗に解決可能です。現在は Federated Credentials への対応のため Pull Request を作成してレビューを待っている状態です。

この Pull Request がマージされると、ローカルや GitHub Actions 上で Azure CLI が持っている認証情報でデプロイ可能となるため、より安全なデプロイフローを実現できます。

既に GitHub に関連付いたものを SWA CLI に変更する

新規に Static Web Apps を作成した時に GitHub を関連付けて作成した場合は、SWA CLI からデプロイしようとするとエラーとなるケースがあります。解消するには Azure CLI を使って az staticwebapp disconnect を実行して関連付けを解除する必要があります。

Azure CLI を利用すると再び GitHub 関連付けることも可能なはずですが、試したところ謎のエラーが出て動作しませんでした。一応 az staticwebapp update を使うと GitHub の設定以外は行えるので、後は手動で対応する形になりそうです。