不適切な Flex 従量課金プラン アプリのデプロイから復旧する

デプロイでバグが発生した場合は、迅速に回復する方法が必要です。 この記事では、継続的インテグレーションと継続的デプロイ (CI/CD) プロセスを使用して、不適切なデプロイから Flex Consumption 関数アプリに復旧する方法について説明します。 このプロセスには、次の回復方法が含まれます。

回復方法 速度 いつ使用するか 説明
以前の正常な実行を再実行する (ロールバック) 最 速 既知の正常なバージョンが存在するか、バージョン間のデータまたは状態の変更がない 前の実行を選択して再実行し、ビルドとデプロイを待ちます。
git revert 次に git push (ロールフォワード) Moderate 簡単な修正。または、外部の状態をロールバックできない 問題の原因となったコミットを特定し、それをリバートして、プッシュしてください。 次に、同じビルドとデプロイ時間を待ちます。
git commit ホットフィックスを適用してから git push (ロールフォワード) 最も遅い 根本原因は既知であり、対象となる修正プログラムが必要です 根本原因を特定する。修正プログラムを作成、確認、テスト、マージする。ビルドとデプロイが完了するまで待ちます。

これらの戦略では、関数アプリのコードとアプリの設定の両方が回復されるため、構成の変更はコードの変更で回復できます。

デプロイを回復するために CI/CD が必要な理由

Flex Consumption プラン アプリにコードをデプロイする場合:

  • コードは、起動時にマウントされる BLOB ストレージ コンテナーに zip パッケージとしてデプロイされます。
  • 各デプロイによって、現在のパッケージが上書きされます。
  • プラットフォームは、以前のバージョンを保持するために組み込みのリビジョン履歴を保持しません。
  • デプロイ スロット機能は現在サポートされていません。
  • アプリ設定は、Azure ポータル、CLI、またはコードとしてのインフラストラクチャ (IaC) を使用して個別に適用され、プラットフォームでは以前の状態に復元できません。

これらのデプロイ動作では、Flex 従量課金プラン アプリを不適切なデプロイから回復するためのオプションが制限されます。

Git 履歴と CI/CD プロセスでは、特定の時点でのコードデプロイを追跡する唯一の方法が提供されます。 コードと構成の両方を含むデプロイをビルドすると、既知の正常なコミットで次の実行をポイントすることで、不適切なリリースから復旧できます。

Flex Consumption デプロイ モデルの詳細については、Flex Consumption プランおよびFlex Consumption プランでのサイトの更新を参照してください。

前提条件

アプリ設定を管理するためのデプロイを準備する

完全なロールバックを実行する前に、アプリ設定をソース管理に配置し、デプロイの一部として適用する必要があります。 この方法では、1 回の再実行でコードと構成の両方を回復できますが、設定の適用、再起動の待機、宣言されていない値のクリーンアップなどの追加の手順が必要です。

Tip

デプロイに設定が含まれていない場合は、展開されたコードのみをロールバックできますが、構成はロールバックできません。

このセクションでは、デプロイの一部としてアプリ設定を管理するための 2 つの方法について説明します。

Approach ワークフロー内 (Azure CLI) サービス定義内 (Bicep)
どのように機能するのか デプロイ手順では、 az functionapp config appsettingsを使用して JSON ファイルから設定を適用し、宣言されていない設定を削除します Bicepテンプレートは、siteConfig.appSettingsで設定を宣言します。ARM は、デプロイ時にコレクション全体を置き換えます
複雑さ 中程度。 JSON ファイルに加えて、ワークフロー内の追加の CLI ステップ より高い Bicep の知識が必要です
ドリフト検出 いいえ はい (what-if)
最適な用途 小規模チーム向けのスタートガイド 運用対応、マルチ環境、複雑なインフラストラクチャ

アプリ設定の一般的な情報については、「Azure Functionsのアプリ設定リファレンス」を参照してください。

アプリ設定に関する考慮事項

プログラムによるアプリ設定の構成を使用する場合は、これらの考慮事項に注意してください。

Important

いずれかの方法を使用して必要なすべての設定を含めずに、デプロイされたアプリが壊れる可能性があります。

  • このセクションのどちらの方法でも、設定ファイルは完全な目的の状態として扱われます。 ファイルで宣言されていないアプリ設定は、すべてのデプロイでアプリから削除されます。 アプリが壊れないように、必要なすべての設定を常に含めます。

  • app-settings.json と Bicep ファイル テンプレートの変更は、コードの変更と同様に厳密に確認してください。 プル要求の設定の変更を確認して、運用環境に到達する前に構成エラーをキャッチします。

  • 最適なセキュリティを実現するには、接続に関する次のガイドラインに従ってください。

    • 可能な限りマネージド ID 接続を使用します。 ホスト ストレージ ()、デプロイ ストレージ、トリガー/バインディング接続用にAzureWebJobsStorageを設定します。 詳細については、「 展開設定の構成」を参照してください。

      • シークレットが避けられない場合は、Key Vault参照を使用します。 Key Vaultシークレットを安全に格納します。 シークレットを直接格納する代わりに、参照を使用して、実行時に必要なシークレットに安全にアクセスできます。 詳細については、「Key Vault参照の使用」を参照してください
  • CI/CD を使用すると、アプリ設定またはコードに対する各変更によって、個別の サイト更新がトリガーされます。 既定では、この展開プロセスでは、少なくとも 2 つのサイト更新プログラムが生成されます。最初に設定が適用されたとき、次にコードが展開されたときです。 ダウンタイムなしのデプロイの場合は、代わりに ローリング 更新 戦略を使用します。ここで、インスタンスはバッチでドレインされ、置き換えられます。 詳細については、 Flex 従量課金プランのサイト更新を参照してください。

ワークフローでアプリ設定を構成する

次の基本的な手順を使用して、アプリ設定構成ファイルをプロジェクトの展開に追加します。

  1. infra/app-settings.jsonなど、リポジトリに JSON ファイルを作成します。 このファイルには、次の例のような JSON 形式で必要なすべてのアプリ設定が含まれている必要があります。

    [
      {
        "name": "FUNCTIONS_EXTENSION_VERSION",
        "value": "~4"
      },
      {
        "name": "FUNCTIONS_WORKER_RUNTIME",
        "value": "dotnet-isolated"
      },
      {
        "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
        "value": "InstrumentationKey=00000000-..."
      },
      {
        "name": "AzureWebJobsStorage__blobServiceUri",
        "value": "https://mystorageaccount.blob.core.windows.net"
      },
      {
        "name": "AzureWebJobsStorage__queueServiceUri",
        "value": "https://mystorageaccount.queue.core.windows.net"
      },
      {
        "name": "AzureWebJobsStorage__tableServiceUri",
        "value": "https://mystorageaccount.table.core.windows.net"
      },
      {
        "name": "MyFeatureFlag",
        "value": "true"
      },
      {
        "name": "ServiceBus__fullyQualifiedNamespace",
        "value": "my-namespace.servicebus.windows.net"
      }
    ]
    
  2. 特定のデプロイ定義で、コードのデプロイが行われる前に設定を適用する手順を追加します。その間に 30 秒の一時停止があります。

次のセクションでは、両方の方法を使用した特定のデプロイ例を示します。

例: app-settings.json のデプロイ

このデプロイの例では、構成を含むようにデプロイを構成する方法を示します。 CI/CD メソッドに一致するタブを選択します。

ワークフローの deploy ジョブに次の手順を追加します。 actions/checkout@v4 ジョブにdeployを追加して、infra/app-settings.jsonを使用できるようにし、ワークフロー レベルのRESOURCE_GROUP ブロックにenvを追加します。 この手順では、最初に設定を適用し、再起動を待ってからコードをデプロイしてから、宣言されていない設定をクリーンアップします。

  deploy:
    needs: build
    steps:
      - name: 'Checkout repository'
        uses: actions/checkout@v4

      - name: 'Download artifact from build job'
        uses: actions/download-artifact@v4
        with:
          name: ${{ env.BUILD_ARTIFACT_NAME }}
          path: ./downloaded-artifact

      - name: 'Log in to Azure'
        uses: azure/login@v2
        with:
          client-id: ${{ vars.AZURE_CLIENT_ID }}
          tenant-id: ${{ vars.AZURE_TENANT_ID }}
          subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

      - name: 'Apply app settings'
        run: |
          az functionapp config appsettings set \
            --name ${{ env.AZURE_FUNCTIONAPP_NAME }} \
            --resource-group ${{ env.RESOURCE_GROUP }} \
            --settings @infra/app-settings.json

      - name: 'Wait for settings restart'
        run: sleep 30

      - name: 'Deploy code'
        uses: Azure/functions-action@v1
        with:
          app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
          package: ./downloaded-artifact

      - name: 'Remove undeclared app settings'
        run: |
          DESIRED=$(jq -r '.[].name' infra/app-settings.json)
          CURRENT=$(az functionapp config appsettings list \
            --name ${{ env.AZURE_FUNCTIONAPP_NAME }} \
            --resource-group ${{ env.RESOURCE_GROUP }} \
            --query "[].name" -o tsv)
          TO_DELETE=""
          for setting in $CURRENT; do
            if ! echo "$DESIRED" | grep -qx "$setting"; then
              TO_DELETE="$TO_DELETE $setting"
            fi
          done
          if [ -n "$TO_DELETE" ]; then
            az functionapp config appsettings delete \
              --name ${{ env.AZURE_FUNCTIONAPP_NAME }} \
              --resource-group ${{ env.RESOURCE_GROUP }} \
              --setting-names $TO_DELETE
          fi

OIDC ベースのワークフローの azure/login@v2 手順では、 az cli コマンドに必要な認証を提供します。

Bicep デプロイで設定を定義する

IaC デプロイの場合は、Bicep テンプレートでアプリ設定を直接管理します。 Bicepは、個別のクリーンアップ手順を必要とせずに、すべてのデプロイでsiteConfig.appSettings コレクション全体をネイティブに置き換えます。 また、 what-ifを使用したドリフト検出もサポートしています。

Bicep ファイルのアプリ設定セクションのみを更新すると、デプロイ中に他のすべてのAzureリソースは変更されません。 この記事では、Bicep の記述方法を最初から最後まで網羅しているわけではありません。 Flex Consumption の完全版テンプレートについては、Azure Functions の Infrastructure as Codeを参照してください。

Bicep テンプレートの関連するフラグメントを次に示します (appSettings部分のみ)。

siteConfig: {
  appSettings: [
    {
      name: 'MyFeatureFlag'
      value: 'true'
    }
    {
      name: 'ServiceBus__Connection'
      value: '@Microsoft.KeyVault(SecretUri=https://my-vault.vault.azure.net/secrets/sb-conn)'
    }
  ]
}

コードのデプロイの前にBicep テンプレートをデプロイする手順を追加し、その間に 30 秒待機します。 Bicepを使用したアプリ設定の更新は非同期です。 アプリが再起動して新しい値が取得され、再起動中にコードをデプロイできない場合があります。

      - name: 'Deploy infrastructure'
        run: |
          az deployment group create \
            --resource-group ${{ env.RESOURCE_GROUP }} \
            --template-file infra/main.bicep \
            --parameters appName=${{ env.AZURE_FUNCTIONAPP_NAME }}

      - name: 'Wait for settings restart'
        run: sleep 30

      - name: 'Deploy code'
        uses: Azure/functions-action@v1
        with:
          app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
          package: ./downloaded-artifact

デプロイをロールバックします。

ロールバックとは、前回の正常な実行を再実行したことを意味します。 再実行では、(現在のブランチ HEAD ではなく) 実行をトリガーした 元のコミット SHA がチェックアウトされるため、その時点からコードと設定ファイルが再構築されてデプロイされます。 新しいコミットは必要ありません。

以前の正常な実行を再実行してデプロイをロールバックするには:

  1. GitHub リポジトリの [アクション] タブに移動します。
  2. 不適切なデプロイの前に最後に 成功した ワークフローの実行を見つけます。
  3. [ すべてのジョブを再実行] を選択します。
  4. ワークフローは、実行のコミットをチェックアウトし、コードを再構築してデプロイし、そのコミットの app-settings.jsonからアプリ設定を同期します。

再実行で再ビルドされるもの

再実行により、古いコミットからコードが再構築されます。 元のバイナリ成果物は再利用されません。 この動作は、次のことを意味します。

  • ピン留めされた依存関係ロック ファイル (package-lock.jsonrequirements.txt など) では、出力は機能的に同じです。
  • ビルド時間は、通常のデプロイと同じです。 インスタントではありません。
  • ビルド時にフェッチされた外部依存関係 (NuGet、npm、pip) は引き続き使用できる必要があります。

ロールバックの考慮事項

  • 依存関係ロック ファイル (package-lock.jsonrequirements.txt、またはロックされた .csproj バージョン) をソース管理にピン留めします。 固定されたロック ファイルを使用すると、デプロイを再実行すると、再実行がいつ行われるかに関係なく、機能的に同じビルドが生成されます。

  • 再実行では、元のコミットからのワークフローまたはパイプライン YAML が使用されます。 ただし、シークレットとパイプライン変数は、再実行時に現在の値に解決されます。 元の実行と再実行の間にシークレットをローテーションすると、新しいシークレット値が使用されます。

  • 再実行すると、デプロイされたアプリは既知の良好な状態に復元されますが、Git 履歴は変更されません。 ブランチの HEAD は、依然として破損したコミットを指しています。

  • 再実行しても復元されないもの:

    • Azureホスティング プラン、ネットワーク、ID の割り当てを含め、デプロイの外部で管理されるリソース構成です。
    • データベース、メッセージ キュー、ストレージなどのダウンストリーム サービスのデータまたはスキーマの変更。
    • Key Vault のシークレット値 ソース管理では、Key Vault参照のみが保持されます。 シークレットのローテーションは、Key Vault の操作です。
  • ロールバック プロセスを定期的にテストします。 壊れていることに気づくのを、本番環境でのインシデントが発生するまで待ってはいけません。

ロールバック後にブランチを修正する

次のプッシュトリガー実行では壊れたコミットが再デプロイされるため、ブランチをプルする他の開発者は壊れたコードを引き続き表示します。 次のいずれかのアクションを使用して、この状況を解決する必要があります。

  • 問題に対処する修正プログラムコミットを作成します。これは基本的にロールフォワード操作です。
  • 新しいコミットを作成して壊れたコミットを元に戻す git revert を実行します。これはロールフォワード アクションでもあります。
  • 問題を解決するまでマージを禁止するブランチ ポリシー。

これらのアクションのいずれかを完了するまで、そのブランチで新しい実行をトリガーしないでください。 検証のガイダンスについては、「 マージ前の検証」を参照してください。

展開をロール フォワードする

ロール フォワードとは、新しいコミットをプッシュして問題を修正することを意味します。 壊れたデプロイは修正プログラムがデプロイされるまで有効なままであるため、この戦略は、アプリがその期間中に機能低下した動作を許容できる場合に最適に機能します。

  1. ブランチで修正コミットを作成します。 この修正は次のいずれかです:

    • 問題に直接対処する 修正プログラム
    • 問題のある変更を取り消す新しいコミットを作成するgit revert <bad-commit-sha>git revert はコード変更を元に戻しますが、新しいコミットが作成されて新しいデプロイが実行されるため、ロールフォワードと見なされます。
  2. 修正プログラムで構成の変更も必要な場合は、同じコミットで (app-settings.json または Bicep テンプレートで) アプリ設定を更新します。

  3. コミットをプッシュします。 デプロイによって、修正プログラムが自動的にビルドおよびデプロイされます。

マージする前に検証する

どの復旧戦略を採用する場合でも、問題の深刻化を避けるため、コミットを本番ブランチにマージする前に検証して修正してください。

これらの推奨事項は、事前対応としてロールフォワードする場合でも、ロールバック後にブランチを修正する場合でも適用されます。

  • ステージング環境を使用する: Flex 従量課金プランは現在デプロイ スロットをサポートしていないため、運用ブランチにマージする前に、別の Flex Consumption プラン アプリにデプロイして修正プログラムを検証することを検討してください。

  • 正常性チェックを自動化する: アプリで正常性チェック エンドポイントを呼び出し、肯定的な応答を検証するデプロイ後のステップを追加します。 失敗した場合は、前回成功した実行の再実行をトリガーして自動的にロールバックすることを検討してください。

  • デプロイ後の監視: 回帰検出用に Application Insights アラートを設定します。 早期検出により、不適切なデプロイの影響が軽減されます。