Upgrade to Pro — share decks privately, control downloads, hide ads and more …

分解して理解する Aspire

neno
February 22, 2025

分解して理解する Aspire

.NET ラボ 2025/02/22 での発表資料

neno

February 22, 2025
Tweet

More Decks by neno

Other Decks in Technology

Transcript

  1. 自己紹介 1 • 所属: NTTコミュニケーションズ イノベーションセンター • Microsoft MVP for

    Developer Technologies (2024~) • .NET / Web Development • 趣味: C#, OSS, ドール, 一眼(α7 IV), シーシャ • 執心領域 • C# ⇔ TypeScript • SignalR • Observability / OpenTelemetry 何縫ねの。 nenoNaninu nenoMake ブログ https://blog.neno.dev その他 https://neno.dev
  2. OSS 紹介 2 属性を付与するだけ Tapper • C# の型定義から TypeScript の型定義を生成する

    .NET Tool/ library • JSON / MessagePack 対応! https://github.com/nenoNaninu/Tapper
  3. OSS 紹介 3 • C# の SignalR Client を強く型付けするための Source

    Generator TypedSignalR.Client Before After (using TypedSignalR.Client) こんな SignalR の Hub と Receiver の interface が あったとして… 脱文字列! 全てが強く型付け! https://github.com/nenoNaninu/TypedSignalR.Client
  4. 4 • TypeScript の SignalR Client を強く型付けするための .NET Tool /

    library TypedSignalR.Client.TypeScript Before After (using TypedSignalR.Client.TypeScript) 脱文字列! 全てが強く型付け! TypeScript 用の型を C# から自動生成 MessagePack Hub Protocol 対応! https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript 属性を付与するだけ! OSS 紹介
  5. 5 • SignalR 使ったアプリを快適に開発するための GUI を自動生成する library • 2 step

    で利用可能! • http pipeline に middleware の追加 • Hub と Receiver を定義してる interface に属性を付与 • JWT 認証 サポート • パラメータのユーザ定義型サポート • JSON で入力! SignalR 版 SwaggerUI TypedSignalR.Client.DevTools https://github.com/nenoNaninu/TypedSignalR.Client.DevTools OSS 紹介
  6. AspNetCore.SignalR.OpenTelemetry OSS 紹介 6 https://github.com/nenoNaninu/AspNetCore.SignalR.OpenTelemetry • トレースのための計装 • 最低限のログ •

    接続時 • Transport 層の情報も出力(WebSocket 等) • メソッド呼び出し時 • HubName.MethodName の素朴なログ • メソッド呼び出し毎にログのスコープを追加 • HubName, MethodName, InvocationId を 振っているのでログの検索性が向上 • Duration • 切断時 • 切断時に例外が発生していれば例外もログに出力 Inspired by HttpLogging SignalR のメソッド呼び出し毎に スパンが切られるように https://github.com/nenoNaninu/AspNetCore.SignalR.OpenTelemetry
  7. お品書き 7 • Aspire とは (公式の言) • Aspire とは (分かりやすく)

    • 最小構成で Aspire を使う (not 必要最低限) • Aspire を最低限活用する • ServiceDefaults • Aspire を使ったテスト • Microsoft Developer Control Plane
  8. Aspire とは (公式の言) 15 AppHost Aspire 8 時代は Component と

    呼ばれていたモノ https://youtu.be/fiePiEc1qcU?si=C3OYpfubori2Aj8F
  9. Aspire とは (分かりやすく) 19 Aspire が提供してくれる事は主に3つ 分散アプリケーションの開発のためのローカル開発環境 • 現時点においてはこれが主な価値 •

    実は(?)分散アプリケーションの開発ではなくても十分利用する価値がある 分散アプリケーションのテスト • 分散アプリケーションのテストがだいぶ書きやすくなる
  10. Aspire とは (分かりやすく) 20 Aspire が提供してくれる事は主に3つ 分散アプリケーションの開発のためのローカル開発環境 • 現時点においてはこれが主な価値 •

    実は(?)分散アプリケーションの開発ではなくても十分利用する価値がある 分散アプリケーションのテスト • 分散アプリケーションのテストがだいぶ書きやすくなる クラウドへのデプロイ • 現時点においてこれを目的で Aspire 使うのはあまりおススメしない
  11. Aspire とは (分かりやすく) 21 Aspire を使うと前述の3つ以外にも いろいろな機能を提供してくれるらしいけど、それはどこへ…? • 例えば以下のような機能 •

    Observability • Resiliency • Health check • Service discovery Aspire を使う上では全て必須な要素ではない (パッケージ的には Aspire が提供している機能ではない)
  12. 最小構成で Aspire を使う (not 必要最低限) 23 最小構成でAspire を使う手順 1. AppHost

    を作成する • $ dotnet new aspire-apphost -n “MyAppHost” 2. AppHost の csproj にアプリケーションの project reference を追加 3. AppHost の Program.cs で AddProject する 4. 以上! 自分たちのアプリケーションの プロジェクト
  13. 最小構成で Aspire を使う (not 必要最低限) 24 実はこれだけで Aspire は起動する •

    Q: この最小構成で Aspire を使う意味あるの? • A: あまりありません • あくまで「Aspire を使う上で余計なものは必要ない」という事を伝えたい
  14. 最小構成で Aspire を使う (not 必要最低限) 25 実はこれだけで Aspire は起動する •

    Q: この最小構成で Aspire を使う意味あるの? • A: あまりありません • あくまで「Aspire を使う上で余計なものは必要ない」という事を伝えたい 現時点ではコンソールログが ここで見えるだけ
  15. 最小構成で Aspire を使う (not 必要最低限) 26 実はこれだけで Aspire は起動する •

    Q: この最小構成で Aspire を使う意味あるの? • A: あまりありません • あくまで「Aspire を使う上で余計なものは必要ない」という事を伝えたい 現時点ではコンソールログが ここで見えるだけ 下3つは現状機能しない
  16. 最小構成で Aspire を使う (not 必要最低限) 27 Aspire を使う上では AddServiceDefaults() とかいうのを

    アプリケーション側で呼び出す必要があるらしいじゃん? 呼び出さなくていいの? • AddServiceDefaults() を呼び出す事は必須ではない
  17. 最小構成で Aspire を使う (not 必要最低限) 28 Aspire を使う上では AddServiceDefaults() とかいうのを

    アプリケーション側で呼び出す必要があるらしいじゃん? 呼び出さなくていいの? • AddServiceDefaults() を呼び出す事は必須ではない 実際自分は使ってない
  18. Aspire を最低限活用する 32 Aspire をローカル開発環境で使って嬉しいポイント(TOP 3) アプリケーションに必要な各種コンポーネントを一括で起動 • C# Project

    (w/ debugger) だけでなく PostgreSQL, Redis 等も起動してくれる • 接続文字列も良い感じに面倒みてくれる 今まで docker compose とかで 整備していたそれらが不要に…!
  19. Aspire を最低限活用する 33 Aspire をローカル開発環境で使って嬉しいポイント(TOP 3) アプリケーションに必要な各種コンポーネントを一括で起動 • C# Project

    (w/ debugger) だけでなく PostgreSQL, Redis 等も起動してくれる • 接続文字列も良い感じに面倒みてくれる 開発用ダッシュボードで OpenTelemetry のテレメトリを漁れる • 構造化ログ • トレース • メトリック 今まで docker compose とかで 整備していたそれらが不要に…!
  20. Aspire を最低限活用する 34 Aspire をローカル開発環境で使って嬉しいポイント(TOP 3) アプリケーションに必要な各種コンポーネントを一括で起動 • C# Project

    (w/ debugger) だけでなく PostgreSQL, Redis 等も起動してくれる • 接続文字列も良い感じに面倒みてくれる 開発用ダッシュボードで OpenTelemetry のテレメトリを漁れる • 構造化ログ • トレース • メトリック OpenTelemetry 依存 今まで docker compose とかで 整備していたそれらが不要に…!
  21. Aspire を最低限活用する 35 Aspire をローカル開発環境で使って嬉しいポイント(TOP 3) アプリケーションに必要な各種コンポーネントを一括で起動 • C# Project

    (w/ debugger) だけでなく PostgreSQL, Redis 等も起動してくれる • 接続文字列も良い感じに面倒みてくれる 開発用ダッシュボードで OpenTelemetry のテレメトリを漁れる • 構造化ログ • トレース • メトリック アプリケーション間の HTTP 通信の構成が容易に • C# コード内で URI を文字列でべた書き可能に OpenTelemetry 依存 今まで docker compose とかで 整備していたそれらが不要に…!
  22. Aspire を最低限活用する 36 Aspire をローカル開発環境で使って嬉しいポイント(TOP 3) アプリケーションに必要な各種コンポーネントを一括で起動 • C# Project

    (w/ debugger) だけでなく PostgreSQL, Redis 等も起動してくれる • 接続文字列も良い感じに面倒みてくれる 開発用ダッシュボードで OpenTelemetry のテレメトリを漁れる • 構造化ログ • トレース • メトリック アプリケーション間の HTTP 通信の構成が容易に • C# コード内で URI を文字列でべた書き可能に OpenTelemetry 依存 これはローカル開発環境 以外でも嬉しい 今まで docker compose とかで 整備していたそれらが不要に…!
  23. Aspire を最低限活用する 37 Aspire を活用する上で 最低限アプリケーション側に追加するべきパッケージ • OpenTelemetry • 必須

    • Microsoft.Extensions.ServiceDiscovery • アプリケーション間の HTTP 通信を容易にするために必要なパッケージ • アプリケーション間で HTTP 通信しないならこのパッケージは不要
  24. Aspire を最低限活用する 40 Aspire が OpenTelemetry 関連でやってくれる事 WebApi OpenTelemetry Protocol

    (OTLP) を 用いたテレメトリの送信先は OTEL_EXPORTER_OTLP_ENDPOINT という環境変数で渡すのが標準的
  25. Aspire を最低限活用する 41 Aspire が OpenTelemetry 関連でやってくれる事 WebApi Aspire はアプリケーションに

    OTEL_EXPORTER_OTLP_ENDPOINT という環境変数を自動で渡す OpenTelemetry Protocol (OTLP) を 用いたテレメトリの送信先は OTEL_EXPORTER_OTLP_ENDPOINT という環境変数で渡すのが標準的 やってくれる事①
  26. Aspire を最低限活用する 42 Aspire が OpenTelemetry 関連でやってくれる事 WebApi Aspire はアプリケーションに

    OTEL_EXPORTER_OTLP_ENDPOINT という環境変数を自動で渡す OpenTelemetry Protocol (OTLP) を 用いたテレメトリの送信先は OTEL_EXPORTER_OTLP_ENDPOINT という環境変数で渡すのが標準的 アプリケーション側は OTLP でテレメトリを飛ばすよう 構成しておく必要がある やってくれる事①
  27. Aspire を最低限活用する 43 Aspire が OpenTelemetry 関連でやってくれる事 WebApi OTLP Aspire

    はアプリケーションに OTEL_EXPORTER_OTLP_ENDPOINT という環境変数を自動で渡す OpenTelemetry Protocol (OTLP) を 用いたテレメトリの送信先は OTEL_EXPORTER_OTLP_ENDPOINT という環境変数で渡すのが標準的 アプリケーション側は OTLP でテレメトリを飛ばすよう 構成しておく必要がある やってくれる事①
  28. Aspire を最低限活用する 44 Aspire が OpenTelemetry 関連でやってくれる事 WebApi OTLP Aspire

    Aspire はアプリケーションに OTEL_EXPORTER_OTLP_ENDPOINT という環境変数を自動で渡す OpenTelemetry Protocol (OTLP) を 用いたテレメトリの送信先は OTEL_EXPORTER_OTLP_ENDPOINT という環境変数で渡すのが標準的 アプリケーション側は OTLP でテレメトリを飛ばすよう 構成しておく必要がある やってくれる事①
  29. Aspire を最低限活用する 45 Aspire が OpenTelemetry 関連でやってくれる事 WebApi OTLP Aspire

    Aspire はアプリケーションに OTEL_EXPORTER_OTLP_ENDPOINT という環境変数を自動で渡す OpenTelemetry Protocol (OTLP) を 用いたテレメトリの送信先は OTEL_EXPORTER_OTLP_ENDPOINT という環境変数で渡すのが標準的 アプリケーション側は OTLP でテレメトリを飛ばすよう 構成しておく必要がある Aspire は OTLP で投げられた テレメトリを受け取ってくれる (OpenTelemetry backend) やってくれる事① やってくれる事②
  30. Aspire を最低限活用する 46 Aspire が OpenTelemetry 関連でやってくれる事 WebApi OTLP Aspire

    Aspire はアプリケーションに OTEL_EXPORTER_OTLP_ENDPOINT という環境変数を自動で渡す OpenTelemetry Protocol (OTLP) を 用いたテレメトリの送信先は OTEL_EXPORTER_OTLP_ENDPOINT という環境変数で渡すのが標準的 アプリケーション側は OTLP でテレメトリを飛ばすよう 構成しておく必要がある テレメトリを ダッシュボードで 可視化 やってくれる事① やってくれる事③ Aspire は OTLP で投げられた テレメトリを受け取ってくれる (OpenTelemetry backend) やってくれる事②
  31. Aspire を最低限活用する 47 Aspire が OpenTelemetry 関連でやってくれる事 WebApi OTLP Aspire

    Aspire はアプリケーションに OTEL_EXPORTER_OTLP_ENDPOINT という環境変数を自動で渡す OpenTelemetry Protocol (OTLP) を 用いたテレメトリの送信先は OTEL_EXPORTER_OTLP_ENDPOINT という環境変数で渡すのが標準的 アプリケーション側は OTLP でテレメトリを飛ばすよう 構成しておく必要がある テレメトリを ダッシュボードで 可視化 やってくれる事① やってくれる事③ Aspire は OTLP で投げられた テレメトリを受け取ってくれる (OpenTelemetry backend) やってくれる事② Aspire が無い時代はローカル用に OpenTelemetry backend 用の config を 書いて動かさないとだった…
  32. • アプリケーション側で環境変数を元に BaseAddress 設定して云々 • 環境変数設定する際、正しい値は何かとか把握するの地味に面倒 • そして設定漏れ… Aspire を最低限活用する

    49 アプリケーション間の HTTP 通信の構成って地味に面倒ですよね… WebApi WebApi2 HTTPS WebApi から WebApi2 への HTTP 通信の構成は 地味に面倒 環境変数とかポートとか 気にする事が地味そこそこある
  33. • 以下のようにベタ書きでエンドポイントを指定できる • だたし所定のフォーマットで環境変数が渡っている必要がある • services__webapi2__http • services__webapi2__https • services__webapi2__http__0

    (配列形式) Aspire を最低限活用する 51 そこで Microsoft.Extensions.ServiceDiscovery http+https:// と書くことによって 環境変数次第で http と https を切り替えられる
  34. • 以下のようにベタ書きでエンドポイントを指定できる • だたし所定のフォーマットで環境変数が渡っている必要がある • services__webapi2__http • services__webapi2__https • services__webapi2__http__0

    (配列形式) Aspire を最低限活用する 52 そこで Microsoft.Extensions.ServiceDiscovery ServiceDiscovery を 使うために必要な構成 http+https:// と書くことによって 環境変数次第で http と https を切り替えられる
  35. • Aspire が Ms.Ex.ServiceDiscovery 絡みでやってくれる事 • Ms.Ex.ServiceDiscovery に適した環境変数を渡してくれる (これだけ!) •

    WithReference でアプリケーション間の参照関係を 明示する事によってAspire は services__webapi2__http 形式の環境変数をアプリケーションに設定 Aspire を最低限活用する 53 Aspire と Microsoft.Extensions.ServiceDiscovery の関係
  36. • Aspire が Ms.Ex.ServiceDiscovery 絡みでやってくれる事 • Ms.Ex.ServiceDiscovery に適した環境変数を渡してくれる (これだけ!) •

    WithReference でアプリケーション間の参照関係を 明示する事によってAspire は services__webapi2__http 形式の環境変数をアプリケーションに設定 Aspire を最低限活用する 54 Aspire と Microsoft.Extensions.ServiceDiscovery の関係 これだけ!
  37. • Aspire が Ms.Ex.ServiceDiscovery 絡みでやってくれる事 • Ms.Ex.ServiceDiscovery に適した環境変数を渡してくれる (これだけ!) •

    WithReference でアプリケーション間の参照関係を 明示する事によってAspire は services__webapi2__http 形式の環境変数をアプリケーションに設定 Aspire を最低限活用する 55 Aspire と Microsoft.Extensions.ServiceDiscovery の関係 これだけ! ここに渡す名前次第で 環境変数が決まる
  38. • http+https:// みたいな書き方は Grpc.Net.Client では使えない • Ms.Ex.ServiceDiscovery は DelegatingHandler を挟みこみ

    そこでエンドポイントを環境変数で渡された値で扱うようになる • Grpc.Net.Client は HttpMessageHandler 内で Uri を処理するより先に、 自前でプロトコルを判定している • Grpc.Net.Client では client-side load balancing のため, http://, https:// 以外にも dns://, static:// 等を書くことが可能 • http+https:// はサポート外の謎プロトコルとして判定され死ぬ Aspire を最低限活用する 56 Grpc.Net.Client と Microsoft.Extensions.ServiceDiscovery
  39. Aspire を最低限活用する 57 HTTP 通信しないエンドポイントに対する接続文字列 • 例えば以下のように WithReference しているのが database

    の場合 • WebApi の環境変数として ConnectionStrings__mydatabase が Aspire から渡されるようになる • アプリケーション側は接続文字列を ConfigurationExtensions.GetConnectionString() で簡単に取得できる
  40. Aspire を最低限活用する 58 Aspire がやってくれることとを大雑把に整理すると… • 各リソース (C# Project, PostgreSQL,

    Redis, etc.) の管理 • up/down/restart • OpenTelemetry backend / dashboard の提供 • アプリケーションに対してやってくれる事 • 環境変数の追加 (これだけ!) Aspire を導入するとアプリケーションに追加されると 宣伝されている機能の全ては AddServiceDefaults() した際に追加される別パッケージ由来の機能
  41. ServiceDefaults 64 AddServiceDefaults の中身 【C#】.NET 8 世代で追加された ConfigureHttpClientDefaults について。 https://blog.neno.dev/entry/2024/07/12/175331

    【C#】StandardResilienceHandler で HTTP リクエストの回復力を高める。 https://blog.neno.dev/entry/2024/08/08/171524
  42. Aspire を使ったテスト 66 分散アプリケーションの結合テスト書きづらい • WebApi が WebApi2 を叩くような WEB

    API のテスト書くには、 事前に両方のサーバを立ち上げてからテストを実行する必要がある • いろいろ実行に必要なコンポーネント一式立ち上げる必要がある • WebApplicationFactory によるアプリケーション単体の WEB API のテストに比べると正直かなりめんどくさい
  43. Aspire を使ったテスト 67 分散アプリケーションの結合テスト書きづらい • WebApi が WebApi2 を叩くような WEB

    API のテスト書くには、 事前に両方のサーバを立ち上げてからテストを実行する必要がある • いろいろ実行に必要なコンポーネント一式立ち上げる必要がある • WebApplicationFactory によるアプリケーション単体の WEB API のテストに比べると正直かなりめんどくさい Aspire を使うと かなりテストを書きやすくなる
  44. Aspire を使ったテスト 72 WebApplicationFactory と DistributedApplicationFactory の違い • WebApplicationFactory は

    ConfigureServices で DI コンテナをカスタムできる • しかし DistributedApplicationFactory から各プロジェクトに対する ConfigureServices は無さそう。
  45. Aspire を使ったテスト 73 WebApplicationFactory と DistributedApplicationFactory の違い • WebApplicationFactory は

    ConfigureServices で DI コンテナをカスタムできる • しかし DistributedApplicationFactory から各プロジェクトに対する ConfigureServices は無さそう。 このあたりがすこし不便
  46. Microsoft Developer Control Plane 79 Aspire と port launchSettings.json 次第

    なんかポート違うぞ…? どっち叩いても繋がるぞ…?
  47. Microsoft Developer Control Plane 80 Aspire と port launchSettings.json 次第

    Aspire が動的にバインドした port なんかポート違うぞ…? どっち叩いても繋がるぞ…?
  48. Microsoft Developer Control Plane 83 Aspire と port なんかポート違うぞ…? どっち叩いても繋がるぞ…?

    launchSettings.json 次第 Aspire が動的にバインドした port わかる
  49. Microsoft Developer Control Plane 84 Aspire と port なんかポート違うぞ…? どっち叩いても繋がるぞ…?

    launchSettings.json 次第 Aspire が動的にバインドした port お前は誰だ? わかる
  50. Microsoft Developer Control Plane 93 Reverse Proxy 的な役割をしてるのがひっそり存在する dcpctrl (https://localhost:7023)

    https WebApi (https://localhost:53584) dcpctrl (https://localhost:7023) WebApi (https://localhost:55204) https WebApi (https://localhost:55207) WebApi (https://localhost:55209) WithReplicas あり WithReplicas なし
  51. Microsoft Developer Control Plane 95 よもやま話: Ms.AspNetCore.OpenApi と Aspire の食い合わせが絶妙に悪い

    Microsoft.AspNetCore.OpenApi が吐き出す JSON には Servers が入っている
  52. Microsoft Developer Control Plane 96 よもやま話: Ms.AspNetCore.OpenApi と Aspire の食い合わせが絶妙に悪い

    Microsoft.AspNetCore.OpenApi が吐き出す JSON には Servers が入っている Aspire のダッシュボード上の エンドポイントから開くと 当然 dcpctrl が動いている port に繋がる
  53. Microsoft Developer Control Plane 97 よもやま話: Ms.AspNetCore.OpenApi と Aspire の食い合わせが絶妙に悪い

    Microsoft.AspNetCore.OpenApi が吐き出す JSON には Servers が入っている dcpctrl の port 宛てではなく アプリケーションの port を 直に叩きに行くので CORS で機能しない Aspire のダッシュボード上の エンドポイントから開くと 当然 dcpctrl が動いている port に繋がる
  54. Microsoft Developer Control Plane 98 よもやま話: Ms.AspNetCore.OpenApi と Aspire の食い合わせが絶妙に悪い

    Microsoft.AspNetCore.OpenApi が吐き出す JSON には Servers が入っている Aspire のダッシュボード上の エンドポイントから開くと 当然 dcpctrl が動いている port に繋がる 結局未だに Swashbuckle 使ってる dcpctrl の port 宛てではなく アプリケーションの port を 直に叩きに行くので CORS で機能しない
  55. Microsoft Developer Control Plane 99 dcpctrl ってなに? • Microsoft Developer

    Control Plane (dcp) Control の事 (ぽい) • Microsoft Developer Control Plane については • ドキュメントなし • OSS でもない
  56. Microsoft Developer Control Plane 100 dcpctrl ってなに? • Microsoft Developer

    Control Plane (dcp) Control の事 (ぽい) • Microsoft Developer Control Plane については • ドキュメントなし • OSS でもない
  57. Microsoft Developer Control Plane 101 dcpctrl ってなに? • Microsoft Developer

    Control Plane (dcp) Control の事 (ぽい) • Microsoft Developer Control Plane については • ドキュメントなし • OSS でもない dcpctrl だけでなく dcp も存在する
  58. Microsoft Developer Control Plane 102 dcpctrl ってなに? • Microsoft Developer

    Control Plane (dcp) Control の事 (ぽい) • Microsoft Developer Control Plane については • ドキュメントなし • OSS でもない なので「ぽい」としか いいようがない dcpctrl だけでなく dcp も存在する
  59. Microsoft Developer Control Plane 103 dcpctrl ってなに? • Microsoft Developer

    Control Plane (dcp) Control の事 (ぽい) • Microsoft Developer Control Plane については • ドキュメントなし • OSS でもない https://github.com/dotnet/aspire/blob/v9.0.0/eng/dcppack/Common.projitems#L38-L46 なので「ぽい」としか いいようがない dcpctrl だけでなく dcp も存在する
  60. Microsoft Developer Control Plane 121 kubectl で service を確認 dcpctrl

    は service 相当 の reverse proxy …? ただの reverse proxy に こんな名前与えるかなぁ…?? 他の事もやってそう…
  61. Microsoft Developer Control Plane 122 Microsoft Developer Control Plane の仕事

    • .NET プロジェクト起動したり、コンテナを起動したりしているのは Microsoft Developer Control Plane ぽい • Aspire は C# の k8s client 経由で Microsoft Developer Control Plane を叩いている Aspire dcp kubectl dcpctrl (reverse proxy ?)
  62. まとめ 123 Aspire を必要最低限使うには • OpenTelemetry は必須 • Microsoft.Extensions.ServiceDiscovery が次点で必要

    • AddServiceDefaults() は不要 Aspire を用いたテスト • 基本は DistributedApplicationTestingBuilder • WebApplicationFactory と DistributedApplicationFactory の違い Microsoft Developer Control Plane • Port の挙動はこのあたりうっすらと知っていると理解が容易 • ただしドキュメントもないし OSS でもない • kubectl で叩ける