Azure PipelinesでmicroCMS+Next.jsのブログをStatic Web Appsにデプロイする

今回はmicroCMS+Next.jsで作成したシンプルなブログをAzure Pipelinesでビルドし、Azure Static Web Appsにデプロイする手順をご紹介します。

また、合わせてmicroCMSで記事を公開した際に、自動でビルド＆デプロイを実行する方法もご紹介します。

## 仕組みづくりのために利用したサービスのご紹介
* [microCMS](https://microcms.io/)
   * 日本で開発されたAPIベースのヘッドレスCMSの一つです。
* [Next.js](https://nextjs.org/)
   * Reactベースのフロントエンド フレームワークです。
   * microCMSと組み合わせることで簡単にブログサイトを作成することができます。
* [Azure Pipelines](https://azure.microsoft.com/ja-jp/services/devops/pipelines/)
   * Azure DevOpsの機能の一つで、ビルドやテスト、デプロイ等の自動で行うことができます。
* [Azure Static Web Apps](https://azure.microsoft.com/ja-jp/services/app-service/static/)
   * Azureが提供する静的サイトのリソースです。今回紹介するAzure PipelinesやGitHubなどでビルドし、静的サイトにデプロイすることができます。

## 前提
* Azure PortalおよびAzure DevOpsを利用するためのサブスクリプションは適用済みとします。
* Azure DevOpsのOrganizationおよびProjectは既に作成済みとします。
* Node.jsのバージョンはv18.xとします。（2022年11月現在のLTS）
* Gitは既にインストールされているものとします。

## microCMS+Next.jsのブログ作成
まずは、microCMS+Next.jsで簡単なブログサイトのプロジェクトを作成します。

また、Azure Pipelinesを利用し作成したプロジェクトをStatic Web Appsにデプロイします。

### microCMSのサービス作成
microCMSのサイトにアクセスし、サインアップおよびサービスの作成を行います。

https://microcms.io/
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/67a42bed-cdf6-b1c5-5816-7eb499c7e1b6.png)

### microCMS+Next.jsのプロジェクト作成
1. 下記のmicroCMS公式サイトのチュートリアルを「7. CSSで見た目を装飾する」まで手順に従い進めていき、Next.jsのプロジェクト作成およびmicroCMSの記事呼び出しを行えるよう実装します。
   * [microCMS + Next.jsでJamstackブログを作ってみよう](https://blog.microcms.io/microcms-next-jamstack-blog/)
1. プロジェクト直下に`.env.production`を作成します。内容は上記チュートリアルの`.env.development.local`と同じくmicroCMSのAPI Keyを指定します。
   ```
   API_KEY=xxxxxxxxxxxx
   ```

今回microCMSでは、このような記事を登録してみました。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/65e9b512-0a1c-b767-256d-a7648a670428.png)

### Static Web Appsの作成（Azure Portal）
Azure PortalでStatic Web Appsのリソースをを作成します。

1. 「リソースの作成」からStatic Web Apps（静的Webアプリ）を選択します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/3f7b9a11-34ce-a3d3-6d7a-c78d9647b8b8.png)

1. 下記の通りプロジェクトの詳細を入力します。他はデフォルトでOKです。
    * リソースグループ：任意のリソースグループ（なければ新規追加）
    * プラン: Free
    * Azure Functions とステージングの詳細: East Asia
    * デプロイの詳細: 今回は「その他」を選びます
      ![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/486cd0bd-d59c-4823-86f7-184df0291547.png)


1. 作成後、リソースの管理画面トップから「デプロイメントトークンの管理」を選択し、表示されたトークンをコピーします。（後の手順で利用します。）
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/7fa45d75-9fd2-7a4d-d9e5-4f1df2ab5e1d.png)

### リポジトリ、パイプライン作成（Azure DevOps）
Azure DevOpsでリポジトリとパイプラインを作成します。

#### リポジトリ
1. Reposから新しいリポジトリを作成します。
   ![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/ddc2647c-39f3-7d73-36bd-05b626175e58.png)
   ![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/364c70e4-e7d2-adf5-b5f9-a69aaa87f2f6.png)

1. リポジトリをCloneし、作成したNext.jsプロジェクトの資材をリポジトリにコミット＆プッシュします。

#### パイプライン
1. Azure Pipelinesから新しいパイプラインを作成します。
   ![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/3bcc44af-1acd-43a7-860e-fd36f292e87b.png)

1. リポジトリは「Azure Repos Git」を選択し、リポジトリはさきほど作成したものを指定します。
   ![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/48c9ae61-c43c-3664-3bb5-5bd15da5ab63.png)
   ![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/29e2c157-f77a-1dde-1649-1c45d537589b.png)

1. パイプラインのテンプレートは「Starter Pipeline」を選択します。
   ![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/89e46288-6f65-6b1a-e41a-3f2636d1c474.png)

1. yamlファイルの編集では、下記のとおりStatic Web Appsのデプロイタスクを追加します。
    ```yml
    trigger:
    - main

    pool:
      vmImage: ubuntu-latest

    steps:
    - script: echo Hello, world!
      displayName: 'Run a one-line script'

    - script: |
        echo Add other tasks to build, test, and deploy your project.
        echo See https://aka.ms/yaml
      displayName: 'Run a multi-line script'

    # Static Web Appsのデプロイ
    - task: AzureStaticWebApp@0
      inputs:
        app_location: '/'
        api_location: ''
        output_location: '.next'
      env:
        azure_static_web_apps_api_token: $(deployment_token)
    ```

1. Variablesから下記のとおり新しい変数を作成し、Static Web Appsのデプロイに必要なトークンを追加します。
    * Name: `deployment_token`
    * Value: Static Web Appsのデプロイメントトークン
        * Azure PortalのStatic Web Apps管理画面 > 「デプロイメントトークンの管理」から取得
    * Keep this value secret: チェック
   ![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/6cf2d371-f503-2161-7137-a980fd643354.png)
   ![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/f89898b2-82bf-bb69-935e-2771c10c4727.png)


### パイプラインを実行してみる
yamlファイルの編集後、`Save and Run`でパイプラインを実行してみます。
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/3fbc64f0-b088-6475-7059-bd6d24320f79.png)


パイプライン完了後、Static Web Appsにアクセスしてみるとこのように記事が取得できることが確認できます。

* 記事一覧ページ
   ![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/ff1fb55e-6b5b-7f50-3344-51e034f40adc.png)

* 「最初のブログ」のページ
   ![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/e5d2f9b6-7859-5067-f1db-2e8b79d0a86e.png)

  
## microCMS記事投稿後の自動デプロイ対応
Static Web Appsは公開されたものの、microCMS側で新しい記事を投稿したり、既存の記事を更新してもStatic Web Apps側は再度Pipelineを実行しないかぎり何も変わりません。

これはなぜかと言うと、今回作成したmicroCMS+Next.jsの構成は[JamStack](https://blog.microcms.io/jamstack-introduction/)という考え方を採用しているためです。

JamStackを簡単に説明すると、「ビルド時に事前にデータを取得してHTMLに組み込む」といった考え方です。

従来はブログ記事のデータ等を都度Webサーバーとやり取りして取得していましたが、ビルド時にデータ取得しHTMLを生成しておくことで負荷軽減などのメリットがあります。

### microCMSでのWebhook設定
下記の手順に従ってmicroCMS側でWebhookの設定を行います。

https://document.microcms.io/manual/webhook-setting

Azure DevOpsの場合は、下記のように設定します。
* Webhookの種類：カスタム通知
* 基本設定
   * Webhookの識別名：任意の名前
   * URL：`https://dev.azure.com/<DevOps Organization名>/_apis/public/distributedtask/webhooks/<DevOps Webhook名>?api-version=6.0-preview`
      * DevOps Organization名：Azure DevOpsのURLの`https://dev.azure.com/`の直後の名前です
      * DevOps Webhook名：任意の名前を設定します。この値は、後述のAzure DevOpsでの受信Webhookの名前と一致させる必要があるため控えておきます。
   * シークレット：任意のシークレットの値
      * こちらも、後述のAzure DevOpsでの設定で利用するため控えておきます。
![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/26cab76d-b3a5-9d12-48fd-9ce1f4d75ca6.png)

### Azure DevOpsでの受信Webhook設定
次に、Azure DevOpsで受信Webhookを設定します。

この設定をすることにより、microCMSで記事が公開された通知をAzure DevOps側が受け取ることができます。

参考：https://learn.microsoft.com/ja-jp/azure/devops/pipelines/process/resources?view=azure-devops&tabs=schema#define-a-webhooks-resource

1. Azure DevOpsのProject Settingsから「Service connections」を選択し新規作成します。
   ![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/e65e62fc-db32-fb18-b48c-d01bc8e813a0.png)

1. コネクションの種類は「Incoming WebHook」を選択します。
   ![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/58a1f5ae-ae90-7549-6090-07a905717755.png)


1. Webhookの設定を入力し、保存します。
   * WebHook Name：microCMS側で設定したURLの「DevOps Webhook名」と同じ名前を入力します。
   * シークレット：microCMS側で設定したシークレットと同じ値
   * Service Connection Name：任意の名前。後述のAzure Pipelinesのyamlで利用するため控えておきます。
   ![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/e53e42f2-44e0-e968-7a60-306f81801b00.png)

1. Azure Pipelinesのyamlファイル（`azure-pipelines.yml`）の最初に下記を追加します。
   * WebHook Name：Azure DevOpsで設定した受信Webhookの「WebHook Name」を入力します
   * connection：Azure DevOpsで設定した受信Webhookの「Service Connection Name」を入力します。

   ```yaml
   # Webhook受信時にパイプラインを実行
   resources:
     webhooks:
       - webhook: CMSWebhook                     # Webhook名
         connection: microCMSWebhookConnection   # Service Connection名

   trigger:
   - main

   ...

   ```

これで、microCMSでコンテンツが公開されたときにAzure Pipeline実行し、Static WebAppsに自動デプロイすることができるようになりました。

### 動作確認
microCMSでこのような記事を追加してみます。
![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/bbab0165-c412-3040-ee61-0e6ccaf913f2.png)

すると、自動的にAzure Pipelineが起動されました。
![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/b74b116a-ecd5-2eeb-1898-0fbbb7b0631d.png)

Pipeline完了後、Static Web Appsを確認すると先ほど追加した記事も表示されました。
![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/525d4142-66c8-6414-2009-041d2a67c245.png)


## まとめ
microCMS+Next.jsで作成したブログはAzure Pipelinesの設定ファイルに少し追記するだけで、簡単にAzure Static WebAppsにデプロイすることができます。

また、Webhookの設定を行うことでmicroCMSでコンテンツを公開したときに自動的にビルド＆デプロイをさせる方法もご紹介しました。

こうすることで、記事が投稿した後に手動でパイプラインを動かしデプロイするような作業は無くなり、スムーズにブログを最新化、公開できます。

## 参考資料
* [Next.js](https://nextjs.org/)
* [microCMS](https://microcms.io/)
   * [コンテンツのWebhookを設定](https://document.microcms.io/manual/webhook-setting)
* microCMS公式ブログ
   * [microCMS + Next.jsでJamstackブログを作ってみよう](https://blog.microcms.io/microcms-next-jamstack-blog/)
   * [Jamstackとは何か？まずは基本を理解しよう！](https://blog.microcms.io/jamstack-introduction/)
* Azure DevOps
   * [YAML でリソースを定義する](https://learn.microsoft.com/ja-jp/azure/devops/pipelines/process/resources?view=azure-devops&tabs=schema#define-a-packages-resource)
* [Azure Static Web Apps のビルド構成](https://learn.microsoft.com/ja-jp/azure/static-web-apps/build-configuration?tabs=azure-devops)