Azure Container Appsで、MSSQLバックエンドを使用し、独立.NETでDurable Functionsアプリをホストする。

Azure Container Appsは、Microsoft SQL (MSSQL) ストレージ プロバイダーを使用する場合に、Durable Functionsのイベント ドリブン自動スケール (scale-to-0) をサポートする唯一のホスティング オプションです。 別のストレージ バックエンドを使用する場合は、最小レプリカ数を 0 より大きい値に設定する必要があります。

ヒント

新しいプロジェクトでは、Durable Task Scheduler を使用することを検討してください。これは、永続的なワークフローに推奨されるAzure管理バックエンドです。 このガイドでは、MSSQL バックエンドについて具体的に説明します。

Container Apps でのAzure Functionsの一般的な実行の詳細については、Azure Container Apps Azure Functions のホスティングに関するページを参照してください。

この記事では、次の方法について説明します。

  • ローカルの Durable Functions プロジェクトから Docker イメージを作成します。
  • Azure Container App と関連リソースを作成します。
  • Azure Container App にイメージをデプロイし、認証を設定します。

前提条件

ローカルの Durable Functions プロジェクトを作成する

このガイドでは、.NET の分離された Durable Functions プロジェクトが MSSQL バックエンドで構成されて動作していることを前提としています。 まだお持ちでない場合は、 MSSQL のクイックスタート に従ってローカルで作成してテストしてから、ここに戻ります。

続行する前に、次のことを確認します。

  • あなたのプロジェクトは、分離型ワーカーモデルを使用して.NET 8.0をターゲットにしています。
  • MSSQL ストレージ プロバイダーは、次の場所で構成されます。 host.json
  • アプリは正常に動作しますfunc start

コンテナーで関数アプリを実行するために最低限必要な環境を記述する Dockerfile をプロジェクト ルートに作成します。

  1. プロジェクトのルート ディレクトリで、 Dockerfile という名前の新しいファイルを作成します。

  2. 次の内容をコピーして Dockerfile に貼り付けます。

    FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env
    
    COPY . /src/dotnet-function-app
    RUN cd /src/dotnet-function-app && \
    mkdir -p /home/site/wwwroot && \
    dotnet publish *.csproj --output /home/site/wwwroot
    
    # To enable ssh & remote debugging on app service change the base image to the one below
    # FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0-appservice
    FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0
    ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
        AzureFunctionsJobHost__Logging__Console__IsEnabled=true
    
    COPY --from=installer-env ["/home/site/wwwroot", "/home/site/wwwroot"]
    
  3. ファイルを保存します。

  4. 次の内容の .dockerignore ファイルを追加します。

    local.settings.json
    
  5. .dockerignore ファイルを保存します。

コンテナー イメージを構築する

Docker イメージをビルドします。 Azure Functions Base by Microsoft で Azure Functions でサポートされている基本イメージの完全な一覧を見つける |Docker Hub

  1. Docker デーモンを起動します。

  2. docker login コマンドを使用して Docker にサインインします。

  3. メッセージが表示されたら、ユーザー名とパスワードでログインします。 "ログインに成功しました" というメッセージは、サインインしていることを確認します。

  4. プロジェクトのルート ディレクトリに移動します。

  5. 次のコマンドを実行してイメージをビルドし、 <DOCKER_ID> を Docker Hub アカウント ID に置き換えます。

    dockerId=<DOCKER_ID>
    imageName=<IMAGE_NAME>
    imageVersion=v1.0.0
    
    docker build --tag $dockerId/$imageName:$imageVersion .
    

    M シリーズ Mac で実行している場合は、代わりに --platform linux/amd64 を使用します。

  6. イメージを Docker にプッシュします。

    docker push $dockerId/$imageName:$imageVersion
    

    ネットワーク速度によっては、初期イメージのプッシュに数分かかる場合があります。 待っている間に、次のセクションに進みます。

Container Apps でDurable Functions用のAzure リソースを作成する

コンテナー アプリで Durable Functions を実行するために必要な Azure リソースを作成します。

  • Azure リソース グループ: 作成されたすべてのリソースを含むリソース グループ。
  • Azure Container App 環境: コンテナー アプリをホストする環境。
  • Azure Container App: Durable Functions アプリを含むイメージがこのアプリにデプロイされます。
  • Azure ストレージ アカウント: アプリケーション コードなどのアプリ関連データを格納するために関数アプリで必要です。

初期セットアップ

  1. 新しいターミナルで、Azure サブスクリプションにログインします。

    az login  
    
    az account set -s <subscription_name>
    
  2. 必要なコマンドを実行して、Azure Container Apps CLI 拡張機能を設定します。

    az upgrade
    
    az extension add --name containerapp --upgrade
    
    az provider register --namespace Microsoft.App
    
    az provider register --namespace Microsoft.OperationalInsights
    

ワークロード プロファイルは、環境にデプロイされたコンテナー アプリで使用できるコンピューティング リソースとメモリ リソースの量を決定します。 従量課金ワークロードプロファイルを作成し、スケール・トゥ・ゼロ機能をサポートし、使用量に応じた課金を行います。

  1. 環境変数を設定します。

    location=<REGION>
    resourceGroup=<RESOURCE_GROUP_NAME>
    storage=<STORAGE_NAME>
    containerAppEnv=<CONTAINER_APP_ENVIRONMNET_NAME>
    functionApp=<APP_NAME>
    vnet=<VNET_NAME>
    
  2. リソース グループを作成する。

    az group create --name $resourceGroup --location $location
    
  3. コンテナー アプリ環境を作成します。

    az containerapp env create \
      --enable-workload-profiles \
      --resource-group $resourceGroup \
      --name $containerAppEnv \
      --location $location \
    
  4. Durable Functions イメージに基づいてコンテナー アプリを作成します。

    az containerapp create --resource-group $resourceGroup \
    --name $functionApp \
    --environment $containerAppEnv \
    --image $dockerId/$imageName:$imageVersion \
    --ingress external \
    --kind functionapp \
    --query properties.outputs.fqdn
    
  5. アプリの URL を書き留めます。これは、 https://<APP_NAME>.<ENVIRONMENT_IDENTIFIER>.<REGION>.azurecontainerapps.ioのようになります。

データベースの作成

  1. 関数アプリに必要な Azure Storage アカウントを作成します。

    az storage account create --name $storage --location $location --resource-group $resourceGroup --sku Standard_LRS
    
  2. Azure portal で、状態情報を保持する Azure SQL データベースを作成 します。 作成時:

ID ベースの認証を構成する

マネージド ID は、接続文字列内の資格情報など、アプリからシークレットを排除することで、アプリの安全性を高めます。 システム割り当てマネージド ID とユーザー割り当てマネージド ID のどちらを選択してもかまいませんが、アプリのライフサイクルに関連付けられていないため、ユーザー割り当てマネージド ID をお勧めします。

このセクションでは、Azure Storage の ユーザー割り当てマネージド ID を 設定します。

  1. 環境変数を設定します。

    subscription=<SUBSCRIPTION_ID>
    identity=<IDENTITY_NAME>
    
  2. マネージド ID リソースを作成します。

    echo "Creating $identity"
    az identity create -g $resourceGroup -n $identity --location "$location"
    
  3. コンテナー アプリにユーザー ID を割り当てます。

    echo "Assigning $identity to app"
    az containerapp identity assign --resource-group $resourceGroup --name $functionApp --user-assigned $identity
    
  4. ロールベースのアクセス制御 (RBAC) アクセス許可のスコープを設定します。

    scope="/subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.Storage/storageAccounts/$storage"
    
  5. ユーザー ID の clientIdを取得します。

    # Get the identity's ClientId 
    clientId=$(az identity show --name $identity --resource-group $resourceGroup --query 'clientId' --output tsv)
    
  6. ストレージ アカウントにアクセスするために、 ストレージ BLOB データ所有者 ロールを割り当てます。

    echo "Assign Storage Blob Data Owner role to identity"
    az role assignment create --assignee "$clientId" --role "Storage Blob Data Owner" --scope "$scope"
    

アプリ設定を設定する

Azure Container Apps で Durable Functions アプリをホストする場合、マネージド ID を使用した MSSQL データベースへの認証はサポートされません。 現時点では、このガイドでは接続文字列を使用して認証を行います。

  1. Azure portal の SQL データベース リソースから 、Settings>Connection 文字列 に移動して接続文字列を見つけます。

    Azure ポータルにおける Azure SQL データベースの接続文字列のスクリーンショット

    接続文字列の形式は次のようになります。

    dbserver=<SQL_SERVER_NAME>
    sqlDB=<SQL_DB_NAME>
    username=<DB_USER_LOGIN>
    password=<DB_USER_PASSWORD>
    
    connStr="Server=tcp:$dbserver.database.windows.net,1433;Initial Catalog=$sqlDB;Persist Security Info=False;User ID=$username;Password=$password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
    

    前のデータベース作成手順のパスワードを忘れた場合は、SQL Server リソースでパスワードをリセットできます。

    Azure SQL サーバー リソース ページの [パスワードのリセット] ボタンのスクリーンショット。

  2. SQL データベースの接続文字列を、sqldbconnection というシークレットとしてコンテナー アプリに格納します。

    az containerapp secret set \
    --resource-group $resourceGroup \
    --name $functionApp \
    --secrets sqldbconnection=$connStr
    
  3. アプリに次の設定を追加します。

    az containerapp update \
    -n $functionApp \
    -g $resourceGroup \
    --set-env-vars SQLDB_Connection=secretref:sqldbconnection \
    AzureWebJobsStorage__accountName=$storage \
    AzureWebJobsStorage__clientId=$clientId \
    AzureWebJobsStorage__credential=managedidentity \
    FUNCTIONS_WORKER_RUNTIME=dotnet-isolated
    

デプロイされたDurable Functions アプリをテストする

  1. HTTP テスト ツールを使用して、HTTP トリガー エンドポイントに POST 要求を送信します。これは次のようになります。

    https://<APP NAME>.<ENVIRONMENT_IDENTIFIER>.<REGION>.azurecontainerapps.io/api/DurableFunctionsOrchestrationCSharp1_HttpStart
    

    応答は、Durable Functions オーケストレーションが正常に開始されたことを知らせる HTTP 関数の最初の結果です。 応答には便利な URL がいくつか含まれていますが、オーケストレーションの最終的な結果はまだ表示されません。

  2. statusQueryGetUriの URL 値をコピーしてブラウザーのアドレス バーに貼り付けて実行します。 または、引き続き HTTP テスト ツールを使用して、 GET 要求を発行することもできます。

    この要求によって、オーケストレーション インスタンスの状態が照会されます。 インスタンスが完了し、Durable Functions アプリの出力または結果が表示されます。

    {
        "name":"HelloCities",
        "instanceId":"7f99f9474a6641438e5c7169b7ecb3f2",
        "runtimeStatus":"Completed",
        "input":null,
        "customStatus":null,
        "output":"Hello, Tokyo! Hello, London! Hello, Seattle!",
        "createdTime":"2023-01-31T18:48:49Z",
        "lastUpdatedTime":"2023-01-31T18:48:56Z"
    }
    

次のステップ