LoginSignup
5
3

.NET Aspire を デプロイする

Last updated at Posted at 2023-12-29

はじめに

この記事は .NET Aspire に関する一連の記事の一部です。

.NET Aspire + Dapr についてはこちらをご覧ください。メインは Dapr についてですが、.NET Aspire を使用する場合についても記載があります。


この記事は .NET Aspire で構築したアプリケーションを Azure Developer CLI を使って Azure Container Apps にデプロイする記事です。

開発環境

  • Windows 11
  • Visual Studio 2022 17.11.0 Preview 1.1
    • .NET Aspire 8.0.0
  • Docker Desktop 4.30.0 (149282)
  • Azure Developer CLI 1.9.3

.NET Aspire は VSCode でも扱うことができますが、本記事では Visual Studio 2022 Preview 版を使用します。

.NET Aspire 管理下のアプリをデプロイするとは

.NET Aspire はコンテナで稼働することを前提としています。そのため、各プロジェクトをコンテナ化してコンテナレジストリに Uploadしてから対象のリソースにデプロイする、という順番をとることになります。

次に .NET Aspire 管理下のシステムのうち、デプロイ対象となる箇所がどこなのかを理解しておく必要があります。.NET Aspire Starter アプリケーションの構成を確認してみましょう。

image.png

ちなみにこの構成図は .NET Aspire を使ってみる で構築した分散アプリケーションのプロジェクト構成図と全く同じです。このうち、デプロイの対象となるのは次の赤枠で囲われた箇所になります。

image.png

手動で各プロジェクトをコンテナ化しなければならないわけですが、数が多くなるとちょっとうんざりですね。

この記事では.NET Aspire の Starter アプリケーションをデプロイします。アプリケーション作成時に「キャッシュ用に Redis を使用する(Docker が必要)」を選択してください。

image.png

これは.NET Aspire を使ってみる で構築した結果と同じものになります。

Visual Studio で Azure (Container Apps)にデプロイする

この後に説明しましたが、初期リリースでは .NET Aspire は Azure Developer CLI を使うことでしか Azure にデプロイできませんでした。どの Preview 版だったかは記憶が定かではないのですが、Visual Studio から直接 .NET Aspire アプリを Azure にデプロイできるようになっています。

やってみましょう。AppHost プロジェクトを右クリックし、発行を選択します。

image.png

2024/5現在、Visual Studio から Azure へのデプロイは Azure Container Apps のみのサポートです。次へをクリックします。

image.png

デプロイ先を選択して完了をクリックします。

image.png

実行プロファイルが作成されたら、ダイアログを閉じます。

image.png

ダイアログを閉じると、裏側で Azure Developer CLI によってプロジェクトが解析されて、デプロイ用のファイルが作成されます。どんなファイルが作成されるのか、ファイルはどういう意味なのかは Azure Developer CLI でデプロイする場合をこの下で書いていますのでご参照ください。処理が終わるとこのような画面になります。右上の発行ボタンをクリックします。

image.png

発行中です。しばらく待ちます。

image.png

デプロイの進行状況は Azure Portal から確認することができます。手順の最初で最初に環境名を入力しますが、環境名の前に rg- が付いたリソースグループが自動的に作成されますので、そのリソースグループを開いて左のメニューのデプロイを開くと、状況がわかります。

image.png

デプロイが終わったら、このような画面になります。 下に表示されている webfrontend のエンドポイントのリンクをクリックすると、いつもの画面が表示されて、天気予報データも表示されます。

image.png

image.png

言うまでもありませんが、この方法はあくまでも試しに Azure で動かしてみよう、という場合のためであって、本番運用後はVisual Studioからのデプロイは事故のもとなのでやめておきましょう。

Azure Developer CLI で Azure にデプロイする

CI/CD を見据えたデプロイを一気に行う場合は Azure Developer CLI によるデプロイが楽です。 Azure Developer CLI を使うと各プロジェクトのコンテナ化からデプロイ先の Azure Container Apps だけではなく、コンテナレジストリなど必要なすべてのリソースの作成、そしてイメージの Upload、デプロイまでを全て自動的にやってくれます。

Azure Developer CLI とは

Deploy a .NET Aspire app to Azure Container Apps

ただし Azure Developer CLI を使う場合、2024/5現在では Azure Container Apps へのデプロイしかサポートされていません。 Kubernetes へのデプロイはコミュニティベース作成された Asipirate というツールによる Manifest 作成サポートはありますが、公式なものではないことに注意が必要です。

Apirate

Aspirate は操作感が Terraform のようなコマンドで Kubernetes 用の Manifest を作成し、デプロイまで可能なツールです。詳しくはリンク先をご確認ください。

Azure Developer CLI を使わずに Azure CLI などを使って1ずつ手作業でデプロイすることも可能です。その場合は Azure Container Apps 以外にもデプロイが可能です。その際には環境変数の設定などにも注意してください。

1. 既存プロジェクトを解析する

では Azure Developer CLI を使って Azure にデプロイしてみましょう。まずはソリューションのルートに移動します。

image.png

その後に次のコマンドを叩きます。

> azd init

現在のディレクトリを解析するのか、テンプレートからデプロイするのかを選択するように聞かれます。
「Use code in the current directory」を選びます。
image.png

フォルダ内部を解析します。
image.png

AppHost プロジェクトが見つかることで、これは .NET Aspire 管理下のシステムであると認識されて
Azure Container Apps にデプロイするための Manifest を作ることが宣言されます。
「Confirm and continue initializing my app」を選択します。
image.png

環境名をつけることを求められます。これは Azure Developer CLI の作成した Manifest で認識されるものです。今回は deploytest としました。

image.png

azure.yml と next-steps.md という2つのファイルが作成されたことがわかります。
image.png

実はこの2つ以外にも .azure というフォルダ作られていて、その中にいくつかファイルが作成されます。この中のあるファイルは azd init コマンドで入力と選択した値が格納されます。つまり、環境変数名(上で入力した deploytest)を保持しています。

azure.yaml ファイルを見てみる

生成された azure.yaml を見てみましょう。

azure.yaml
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json

name: BlazorApp1
services:  
  app:
    language: dotnet
    project: .\BlazorApp1.AppHost\BlazorApp1.AppHost.csproj
    host: containerapp

このファイルには AppHost プロジェクトの場所が記載してあるだけです。てっきり ARMテンプレートや Bicep ファイルが生成されるのかと思いきや、記載してあるのはこれだけです。どういうことなのでしょうか。

next-steps.md ファイルを見てみる

戸惑いつつ、 next-steps.md ファイルを見てみましょう。中は4つのセクションに分かれています。

  1. Next Steps
  2. What was added
  3. Billing
  4. Troubleshooting
1.Next Steps

image.png

次に何をすればいいか、です。 azd up コマンドを叩くと、インフラが用意されてデプロイまでワンステップで実行してくれる、と書いてあります。そして、GitHub Action と Azure Pipelines 用の Starter Yaml ファイルの用意があることがわかりますね

azd pipeline config -e を起動すると、デプロイ用パイプラインがAzureにセキュアに接続するための設定をする。と書いてあります。要するにサービスプリンシパルを生成して、シークレット情報をパイプラインにセットアップしてくれる訳です。本番や検証など複数のデプロイ先に応じて enveriontname で切り替えることができるわけです。

2. What was added

image.png

azure.yaml ファイルにインフラとアプリケーションの構成について記載してある、と書いてあるようです。でも azure.yaml には AppHost プロジェクトへの参照しか含まれていない、とも書いてあります。azd コマンドは必要なインフラを必要な時にメモリ内にコード生成して使用する、とのことです。だから ARM テンプレートも Bicep ファイルもなかったという訳なんですね。

もし azd コマンドが使用する構成を見たい、もしくは修正したいなら azd infra synth コマンドを叩けば次の2つのファイルを生成する、と書いてあります。 

  • infra/main.bicep
  • infra/resources.bicep

さらに、アプリホストから参照されるプロジェクトリソースごとに、プロジェクト ファイルの階層に manifests という名前のディレクトリが作成され、その中に containerApp.tmpl.yaml ファイルが作成されます。との書いてあります。そしてこのファイルには、Azure Container Apps 上でプロジェクトを実行するためのインフラストラクチャがコードとして含まれているそうです。

この説明は古いものなので注意してください。 Azure Developer CLI の1.9.3以降ではプロジェクトリソースごとの設定 yaml ファイルは AppHostプロジェクトの中に infra フォルダが作成され、そこにすべてのプロジェクトごとの yaml ファイルが作成されるようになっています。

では実際にソリューションディレクトリで azd infra synth コマンドを叩いてみましょう。

> azd infra synth

次のような警告が出る場合があります。
image.png

次のコマンドを叩いて機能を有効化します。

azd config set alpha.infraSynth on

image.png

この機能はまだアルファ版である、と警告が表示されて生成が完了します。

説明にあった通り、ソリューションファイルのあるフォルダに infra というフォルダが作成されます。

image.png

infra フォルダを覗くと、ファイルは2つではなく3つできていました。
image.png

ファイルの中身を掲載すると無駄に長くなってしまいますのでやめておきますが、main.bicep でリソースグループを作成し、 resources.bicep を呼び出しています。resources.bicep の中を見てみると、 Azure Container Registry、 Log Analytics Workspace、Azure Container Environment、Redisコンテナを作成していることがわかります。

さて、では既存の.NET アプリケーションを Azure Container Apps にデプロイするための yaml ファイルについてみてみましょう。上にも注意として記載しましたが、Azure Developer CLI のバージョンによって yaml ファイルの置き場所が違います。2024/5現在、Azure Developer CLI 1.9.3の場合は AppHostプロジェクトの infra フォルダ内部に全てのプロジェクト用の yaml ファイルは作成されます。以前のバージョンの Azure Developer CLI の場合、個々のプロジェクトの中に manifests フォルダが作成され、その中に yaml ファイルが作成されます。

AppHostプロジェクト見てみると、infra フォルダ作成されています。

image.png

infra フォルダの中には Container アプリとしてホスティングする対象のアプリケーションのための yaml ファイルが作成されています。今回は Blaozer アプリと WebApi アプリ、そして Redis Cashce もコンテナとしてデプロイするため、3つの yaml ファイルが作成されています。

image.png

Blazor アプリは webfrontend.temp.yamlファイルですね。中を見てみましょう。

AppHost\infra\webfrontend.tmpl.yaml
api-version: 2024-02-02-preview
location: {{ .Env.AZURE_LOCATION }}
identity:
  type: UserAssigned
  userAssignedIdentities:
    ? "{{ .Env.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID }}"
    : {}
properties:
  environmentId: {{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_ID }}
  configuration:
    activeRevisionsMode: single
    runtime:
      dotnet:
        autoConfigureDataProtection: true
    ingress:
      external: true
      targetPort: {{ targetPortOrDefault 8080 }}
      transport: http
      allowInsecure: false
    registries:
      - server: {{ .Env.AZURE_CONTAINER_REGISTRY_ENDPOINT }}
        identity: {{ .Env.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID }}
    secrets:
      - name: connectionstrings--cache
        value: cache:6379
  template:
    containers:
      - image: {{ .Image }}
        name: webfrontend
        env:
          - name: AZURE_CLIENT_ID
            value: {{ .Env.MANAGED_IDENTITY_CLIENT_ID }}
          - name: ASPNETCORE_FORWARDEDHEADERS_ENABLED
            value: "true"
          - name: OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES
            value: "true"
          - name: OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES
            value: "true"
          - name: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY
            value: in_memory
          - name: services__apiservice__http__0
            value: http://apiservice.internal.{{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN }}
          - name: services__apiservice__https__0
            value: https://apiservice.internal.{{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN }}
          - name: ConnectionStrings__cache
            secretRef: connectionstrings--cache
    scale:
      minReplicas: 1
tags:
  azd-service-name: webfrontend
  aspire-resource-name: webfrontend

Azure Container Apps にデプロイするためのマニフェストであることがわかります。環境変数で OpenTelemetry用の設定値が OTEL_ を接頭辞として設定されていたり、Redisコンテナへの接続文字列や、WebAPIである backend に接続するためのホスト名が設定されていることがわかります。

ここで改めて What was added を見てみましょう。下に Note として注意が記載されています。

image.png

インフラストラクチャをディスクに同期(保存)すると、AppHostプロジェクトに加えた変更はインフラストラクチャに反映されない、と書かれています。変更を反映するためには azd infra synth を再度実行することで、インフラストラクチャを再生成することができる、とのことなので注意しましょう。

3. Billing, 4. Troubleshooting

image.png

Billing は課金の話、トラブルシューティングは問題発生時の一般的な解決方法が雑に記載されています。

2. 既存プロジェクトを Azure にデプロイする

ソリューションファイルのある階層で azd up コマンドを叩きます。

azd up

サブスクリプションの選択画面になります。タイプするとフィルタできます。

image.png

リージョンを選択します。タイプするとフィルタできます。この画像は J と入力した状態です。

image.png

しばらく待つと、最後に SUCCESS と表示されてコマンドが終了します。
image.png

Azure Portalからデプロイ結果を確認します。 rg- という接頭辞をつけた環境名のリソースグループが作成されて、その中に Azure Container Registry、Azure Container Envrionment, Azure Container Apps, Log Analytics Workspace, Managed ID が作成されていることがわかります。

image.png

webfrontend を開いてエンドポイントを開いてみます。ちゃんと出力キャッシュが効いていることが確認できるでしょう。
image.png

また、ダッシュボードも自動的にデプロイされます。Azure Container Appsは.NET Aspire ダッシュボードを正式にサポートしています。Container Environment を開くとダッシュボードへのリンクがあります。こちらをクリックするとダッシュボードが表示されます。

image.png

image.png

事前に作成しておいた Redis Cache を使用する

今回、.NET Aspire Starter アプリケーションを作成してから何も設定せずにデプロイしました。気になるのは Redis Cache がコンテナとして作成された点です。ストレージや Database などはコンテナでホストするのではなくクラウドのマネージドリソースを使う場合がほとんどでしょう。Azure であれば、 Azure Blob Storage や Azure CosmosDB, Azure Cahce for Redis や MySQL、PosgreSQL、もちろん SQL Server も マネージド PaaS を使った方が圧倒的に簡単で運用も楽です。

今回、ローカルで Redis を稼働する時には Docker Desktop でコンテナ化されたものが使用され、Azureにデプロイすると、こちらもコンテナ化された Redis がデプロイされました。どちらにせよ、Redis を使う側からしてみれば接続文字列を使用して Redis に接続し、そして使用します。つまり、デプロイする時にはリソースを作成しないで、既に作成された Redis ヘの接続文字列を使うように指示できれば良い、ということになります。

ローカルではDockerDesktopを使用し、本番では既存の Redis を使う、という環境別の設定はとても簡単に行うことができます。

AppHost プロジェクトの Program.cs を開いて次のように修正します。

AppHostプロジェクト/Program.cs
var builder = DistributedApplication.CreateBuilder(args);

- var cache = builder.AddRedis("cache");

+ var cache = builder.ExecutionContext.IsPublishMode
+     ? builder.AddConnectionString("cache")
+     : builder.AddRedis("cache");

var apiService = builder.AddProject<Projects.BlazorApp1_ApiService>("apiservice");

builder.AddProject<Projects.BlazorApp1_Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithReference(cache)
    .WithReference(apiService);

builder.Build().Run();

ローカルで実行時には今まで通り AddRedis を使って Docker Desktop で Redis コンテナが稼働しますが、本番へ Publish する時は接続文字列を渡すようにしています。接続文字列は、Azure Developer CLI でデプロイする時にシークレットの入力を求められます。事前に Azure Cache for Redis を作成しておき、その接続文字列を入力します。

image.png

すると、Azureには Redis コンテナが作成されません。
image.png

Redis を出力キャッシュとして使用している Webプロジェクトがデプロイされた結果のコンテナアプリを見てみましょう。ConnectionStrings__cache という Key の値がシークレット参照になっていることがわかります。
image.png

シークレットを見てみると、シークレットに値があります。この値を開くと、 azd up コマンド実行に入力した接続文字列が埋め込まれています。
image.png

まとめ

Visual Studioから、またAzure Developer CLI を直接使って簡単に Azure Container Apps にデプロイできることがわかりました。上記では説明していませんが、Visual Studio でデプロイした場合でも.NET Aspire ダッシュボードはデプロイされますし、既存の Azure Redis Cache を使うデプロイも Visual Studio から問題なく可能ですので安心してください。

ちなみにAzure Container Apps にデプロイされた.NET Aspireダッシュボードは認証がかかっていますので、誰でもアクセスできるようにはなっていません。

Azure 以外にデプロイするシナリオはまだ Azure Developer CLI ではサポートされていませんので、Azure App Service など他のリソースにデプロイする場合は手動でデプロイすることになります。その場合、OpenTelemtery や Service Discovery用の環境変数を自分で設定しなければなりませんのでご注意ください。

これから少しずつ他のリソースへのデプロイもサポートされると思いますので期待したいですね。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3