From d3867b59a8ff827f8a90aecaba499c2ed80e5b78 Mon Sep 17 00:00:00 2001 From: Takashi Uesaka Date: Fri, 15 May 2026 23:39:40 +0900 Subject: [PATCH 1/3] Translate documents into Japanese using "Skill" --- .../ja/app-host/certificate-configuration.mdx | 749 ++++++++++++++++ .../docs/ja/app-host/configuration.mdx | 190 ++++ .../docs/ja/app-host/container-files.mdx | 434 +++++++++ .../docs/ja/app-host/container-registry.mdx | 592 ++++++++++++ .../docker-compose-to-apphost-reference.mdx | 181 ++++ .../src/content/docs/ja/app-host/eventing.mdx | 432 +++++++++ .../docs/ja/app-host/executable-resources.mdx | 355 ++++++++ .../docs/ja/app-host/hot-reload-and-watch.mdx | 193 ++++ .../app-host/migrate-from-docker-compose.mdx | 711 +++++++++++++++ .../ja/app-host/persistent-containers.mdx | 191 ++++ .../docs/ja/app-host/typescript-apphost.mdx | 291 ++++++ .../docs/ja/app-host/withdockerfile.mdx | 365 ++++++++ .../ja/extensibility/custom-resources.mdx | 292 ++++++ .../ja/extensibility/interaction-service.mdx | 586 ++++++++++++ .../multi-language-integration-authoring.mdx | 614 +++++++++++++ .../fundamentals/custom-resource-commands.mdx | 848 ++++++++++++++++++ .../ja/fundamentals/custom-resource-urls.mdx | 108 +++ .../docs/ja/fundamentals/http-commands.mdx | 255 ++++++ .../docs/ja/get-started/aspire-mcp-server.mdx | 317 +++++++ .../src/content/docs/ja/get-started/faq.mdx | 191 ++++ .../ja/get-started/resource-mcp-servers.mdx | 135 +++ .../docs/ja/get-started/troubleshooting.mdx | 210 +++++ .../docs/ja/languages-and-runtimes/index.mdx | 110 +++ 23 files changed, 8350 insertions(+) create mode 100644 src/frontend/src/content/docs/ja/app-host/certificate-configuration.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/configuration.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/container-files.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/container-registry.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/docker-compose-to-apphost-reference.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/eventing.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/executable-resources.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/hot-reload-and-watch.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/persistent-containers.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/typescript-apphost.mdx create mode 100644 src/frontend/src/content/docs/ja/app-host/withdockerfile.mdx create mode 100644 src/frontend/src/content/docs/ja/extensibility/custom-resources.mdx create mode 100644 src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx create mode 100644 src/frontend/src/content/docs/ja/extensibility/multi-language-integration-authoring.mdx create mode 100644 src/frontend/src/content/docs/ja/fundamentals/custom-resource-commands.mdx create mode 100644 src/frontend/src/content/docs/ja/fundamentals/custom-resource-urls.mdx create mode 100644 src/frontend/src/content/docs/ja/fundamentals/http-commands.mdx create mode 100644 src/frontend/src/content/docs/ja/get-started/aspire-mcp-server.mdx create mode 100644 src/frontend/src/content/docs/ja/get-started/faq.mdx create mode 100644 src/frontend/src/content/docs/ja/get-started/resource-mcp-servers.mdx create mode 100644 src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx create mode 100644 src/frontend/src/content/docs/ja/languages-and-runtimes/index.mdx diff --git a/src/frontend/src/content/docs/ja/app-host/certificate-configuration.mdx b/src/frontend/src/content/docs/ja/app-host/certificate-configuration.mdx new file mode 100644 index 000000000..122f21b98 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/certificate-configuration.mdx @@ -0,0 +1,749 @@ +--- +title: 証明書の設定 +description: Aspire でリソースの HTTPS エンドポイントと証明書の信頼を設定して、安全な通信を実現する方法について説明します。 +--- + +import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; + +Aspire は、2 つの補完的な証明書 API セットを提供します: + +1. **HTTPS エンドポイント API**: リソースが自身の HTTPS エンドポイントで使用する証明書を設定します(サーバー認証) +2. **証明書信頼 API**: リソースが送信 HTTPS 接続を行う際に信頼する証明書を設定します(クライアント認証) + +これらの API セットはともに動作し、ローカル開発中に安全な HTTPS 通信を実現します。たとえば、Vite フロントエンドは `WithHttpsDeveloperCertificate` を使用して HTTPS トラフィックを提供しながら、`WithDeveloperCertificateTrust` を使用してダッシュボードの OTLP エンドポイント証明書を信頼することもできます。 + + + +### HTTPS が重要な理由 + +HTTPS はサービス間で送信されるデータのセキュリティとプライバシーを保護するために不可欠です。トラフィックを暗号化して盗聴、改ざん、中間者攻撃を防ぎます。本番環境では、HTTPS は基本的なセキュリティ要件です。 + +ただし、本番環境の構成に合わせてローカル開発中に HTTPS を有効にするには、固有の課題があります。開発環境では通常、ブラウザやアプリケーションがデフォルトで信頼しない自己署名証明書が使用されます。複数のサービス、コンテナ、異なる言語ランタイムにわたってこれらの証明書を管理するのは複雑で時間がかかり、開発ワークフローに摩擦を生じさせることがよくあります。 + +Aspire は、次の API を提供することでローカル開発の HTTPS 設定を簡素化します: + +- サーバー認証に適した証明書で HTTPS エンドポイントを設定する +- リソースが自己署名証明書を使用するサービスと通信できるよう証明書の信頼を管理する +- 開発証明書(ローカルドメインにのみ有効なユーザーごとの自己署名証明書)をさまざまなリソースタイプにわたって自動的に処理する + +## 開発証明書の信頼 + +Aspire の多くの証明書機能は開発証明書に依存しています。これらの機能を使用する前に、信頼された開発証明書がマシンにインストールされていることを確認する必要があります。 + +### Aspire CLI を使用する(推奨) + +開発証明書を管理するための推奨方法は、[Aspire CLI](/ja/get-started/install-cli/) を使用することです。`aspire run` を実行すると、CLI は開発証明書が作成・信頼されていることを自動的に確認します。追加の手動手順は必要ありません。 + +Aspire CLI を使用して証明書を明示的に管理することもできます: + +```bash title="開発証明書を信頼する" +aspire certs trust +``` + +```bash title="削除して再信頼する(更新)" +aspire certs clean +aspire certs trust +``` + + + + + +### DCP 通信用の開発者証明書(Windows) + +デフォルトでは、Aspire の内部 Developer Control Plane (DCP) サーバーは TLS 用に自身で生成する一時的なローカルホスト証明書を使用します。Windows では、代わりに信頼された Aspire 開発者証明書を DCP 通信に使用することを選択できます。これにより、一時的な証明書がシステム信頼ストアにないことで発生する信頼の問題を回避できます。 + +AppHost の `launchSettings.json` またはシステム/ユーザー環境変数として `ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE` 環境変数を `true` に設定します: + +```json title="Properties/launchSettings.json" +{ + "profiles": { + "https": { + "commandName": "Project", + "environmentVariables": { + "ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE": "true" + } + } + } +} +``` + +この設定が有効な場合: + +- Aspire は信頼された開発者証明書を確認します。 +- 信頼された証明書が見つかった場合、それを使用して DCP サーバーをセキュリティで保護します。 +- 信頼された証明書が見つからない場合、Aspire は DCP が生成する一時的な証明書にフォールバックします。 +- この設定は Windows でのみサポートされています。他のプラットフォームでは、警告がログに記録され、DCP はデフォルトの一時的な証明書にフォールバックします。 + + + +## HTTPS エンドポイントの設定 + +HTTPS エンドポイントの設定は、リソースが HTTPS トラフィックを提供する際に提示する証明書を決定します。これは HTTPS/TLS エンドポイントをホストするリソースのサーバー側証明書設定です。 + +### デフォルトの動作 + +`WithHttpsCertificateConfiguration` で証明書設定が定義されているリソースの場合、Aspire は利用可能であれば開発証明書を使用するように設定しようとします。この自動設定は、YARP、Redis、Keycloak コンテナ、Vite ベースの JavaScript アプリ、Uvicorn を使用する Python アプリなど、多くの一般的なリソースタイプで機能します。 + +この動作は、以下で説明する HTTPS エンドポイント API を使用して制御できます。 + +### 開発証明書を使用する + +リソースの HTTPS エンドポイントに開発証明書を使用するよう明示的に設定するには: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// 開発者証明書を明示的に使用する +var nodeApp = builder.AddViteApp("frontend", "../frontend") + .WithHttpsDeveloperCertificate(); + +// 暗号化された秘密キーを持つ開発者証明書を使用する +var certPassword = builder.AddParameter("cert-password", secret: true); +var pythonApp = builder.AddUvicornApp("api", "../api", "app:main") + .WithHttpsDeveloperCertificate(certPassword); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// 開発者証明書を明示的に使用する +const nodeApp = await builder.addViteApp("frontend", "../frontend") + .withHttpsDeveloperCertificate(); + +// 暗号化された秘密キーを持つ開発者証明書を使用する +const certPassword = await builder.addParameter("cert-password", { secret: true }); +const pythonApp = await builder.addUvicornApp("api", "../api", "app:main") + .withHttpsDeveloperCertificate({ password: certPassword }); + +await builder.build().run(); +``` + + + +`WithHttpsDeveloperCertificate` メソッドは: + +- リソースを開発証明書を使用するよう設定する +- 実行モード(ローカル開発)にのみ適用される +- 必要に応じて、暗号化された証明書の秘密キー用のパスワードパラメーターを受け取る +- コンテナ、Node.js、Python、その他のリソースタイプで動作する + +### カスタム証明書を使用する + +HTTPS エンドポイントに特定の X.509 証明書を使用するようにリソースを設定するには: + + + +```csharp title="AppHost.cs" +using System.Security.Cryptography.X509Certificates; + +var builder = DistributedApplication.CreateBuilder(args); + +// 証明書を読み込む +var certificate = new X509Certificate2("path/to/certificate.pfx", "password"); + +// HTTPS エンドポイントに証明書を使用する +builder.AddContainer("api", "my-api:latest") + .WithHttpsCertificate(certificate); + +// パスワードパラメーターを使用して証明書を使用する +var certPassword = builder.AddParameter("cert-password", secret: true); +builder.AddNpmApp("frontend", "../frontend") + .WithHttpsCertificate(certificate, certPassword); + +builder.Build().Run(); +``` + + + + + + +証明書の要件: + +- 秘密キーが含まれていること +- 有効な X.509 証明書であること +- サーバー認証に適していること + +### HTTPS 証明書設定を無効にする + +リソースに対して Aspire が HTTPS 証明書を設定しないようにするには: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// HTTPS 証明書の自動設定を無効にする +var redis = builder.AddRedis("cache") + .WithoutHttpsCertificate(); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// HTTPS 証明書の自動設定を無効にする +const redis = await builder.addRedis("cache") + .withoutHttpsCertificate(); + +await builder.build().run(); +``` + + + +`WithoutHttpsCertificate` を使用するケース: + +- リソースが HTTPS をサポートしていない場合 +- 手動で証明書を設定したい場合 +- リソースが独自の証明書管理を持っている場合 + +### 証明書設定をカスタマイズする + +カスタム証明書設定ロジックが必要なリソースの場合、`WithHttpsCertificateConfiguration` を使用して証明書ファイルをリソースに渡す方法を指定します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddContainer("api", "my-api:latest") + .WithHttpsCertificateConfiguration(ctx => + { + // 証明書パスをコマンドライン引数として渡す + ctx.Arguments.Add("--tls-cert"); + ctx.Arguments.Add(ctx.CertificatePath); + ctx.Arguments.Add("--tls-key"); + ctx.Arguments.Add(ctx.KeyPath); + + // または環境変数を設定する + ctx.EnvironmentVariables["TLS_CERT_FILE"] = ctx.CertificatePath; + ctx.EnvironmentVariables["TLS_KEY_FILE"] = ctx.KeyPath; + + // リソースが必要とする場合は PFX 形式を使用する + ctx.EnvironmentVariables["TLS_PFX_FILE"] = ctx.PfxPath; + + // 必要な場合はパスワードを含める + if (ctx.Password is not null) + { + ctx.EnvironmentVariables["TLS_KEY_PASSWORD"] = ctx.Password; + } + + return Task.CompletedTask; + }); + +builder.Build().Run(); +``` + + + + + + +コールバックは `HttpsCertificateConfigurationCallbackAnnotationContext` を受け取り、以下を提供します: + +- `CertificatePath`: PEM 形式の証明書ファイルへのパス +- `KeyPath`: PEM 形式の秘密キーファイルへのパス +- `PfxPath`: PFX/PKCS#12 形式の証明書へのパス +- `Password`: 設定されている場合、秘密キーのパスワード +- `Arguments`: 変更するコマンドライン引数のリスト +- `EnvironmentVariables`: 変更する環境変数のディクショナリ +- `ExecutionContext`: 現在の実行コンテキスト +- `Resource`: 設定対象のリソース + +## 証明書信頼の設定 + +証明書信頼の設定は、リソースが送信 HTTPS 接続を行う際に信頼する証明書を決定します。これはクライアント側の証明書設定です。 + +### 証明書信頼を使用するケース + +証明書信頼のカスタマイズが有効なケース: + +- リソースがローカル HTTPS 通信のために開発証明書を信頼する必要がある場合 +- コンテナ化されたサービスが HTTPS 経由でダッシュボードと通信する必要がある場合 +- Python または Node.js アプリケーションがカスタム証明機関を信頼する必要がある場合 +- 特定の証明書信頼要件を持つサービスを扱っている場合 +- リソースが Aspire ダッシュボードへの安全なテレメトリ接続を確立する必要がある場合 + +### 開発証明書の信頼 + +デフォルトでは、Aspire は開発証明書を信頼しないリソースに対して、開発証明書の信頼を追加しようとします。これにより、リソースは HTTPS 経由でダッシュボード OTLP コレクターエンドポイントや、開発証明書で保護されたその他の HTTPS エンドポイントと通信できます。 + +この動作は、`WithDeveloperCertificateTrust` API または AppHost 設定を通じてリソースごとに制御できます。 + +#### リソースごとに開発証明書の信頼を設定する + +特定のリソースの開発証明書の信頼を明示的に有効または無効にするには: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// 開発証明書の信頼を明示的に有効にする +var nodeApp = builder.AddNpmApp("frontend", "../frontend") + .WithDeveloperCertificateTrust(trust: true); + +// 開発証明書の信頼を無効にする +var pythonApp = builder.AddPythonApp("api", "../api", "main.py") + .WithDeveloperCertificateTrust(trust: false); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// 開発証明書の信頼を明示的に有効にする +const nodeApp = await builder.addNodeApp("frontend", "../frontend", "index.js") + .withDeveloperCertificateTrust(true); + +// 開発証明書の信頼を無効にする +const pythonApp = await builder.addPythonApp("api", "../api", "main.py") + .withDeveloperCertificateTrust(false); + +await builder.build().run(); +``` + + + +### 証明機関コレクション + +証明機関コレクションを使用すると、カスタム証明書をバンドルしてリソースで利用できるようになります。`AddCertificateAuthorityCollection` メソッドを使用してコレクションを作成し、それらの証明書を信頼する必要があるリソースから参照します。 + +#### 証明機関コレクションを作成して使用する + +```csharp title="AppHost.cs" +using System.Security.Cryptography.X509Certificates; + +var builder = DistributedApplication.CreateBuilder(args); + +// カスタム証明書を読み込む +var certificates = new X509Certificate2Collection(); +certificates.ImportFromPemFile("path/to/certificate.pem"); + +// 証明機関コレクションを作成する +var certBundle = builder.AddCertificateAuthorityCollection("my-bundle") + .WithCertificates(certificates); + +// 証明書バンドルをリソースに適用する +builder.AddNpmApp("my-project", "../myapp") + .WithCertificateAuthorityCollection(certBundle); + +builder.Build().Run(); +``` + + + +上記の例では、カスタム証明書で証明書バンドルを作成し、Node.js アプリケーションに適用してそれらの証明書を信頼できるようにしています。 + +### 証明書信頼スコープ + +証明書信頼スコープは、カスタム証明書がリソースのデフォルト信頼証明書とどのように連携するかを制御します。スコープごとに異なる設定により、アプリケーションの要件に応じた証明書信頼の管理が柔軟に行えます。 + +`WithCertificateTrustScope` API は、信頼動作を指定する `CertificateTrustScope` 値を受け取ります。 + +#### 利用可能な信頼スコープ + +Aspire がサポートする証明書信頼スコープは以下のとおりです: + +- **Append**: カスタム証明書をデフォルトの信頼済み証明書に追加する +- **Override**: デフォルトの信頼済み証明書を設定された証明書のみに置き換える +- **System**: カスタム証明書とシステムルート証明書を組み合わせてデフォルトを上書きする +- **None**: すべてのカスタム証明書信頼設定を無効にする + +#### Append モード + +指定されたリソースのデフォルト信頼済み証明書にカスタム証明書を追加しようとします。このモードは、システムのデフォルト証明書の信頼を維持しながら、追加の証明書の信頼を加えたい場合に便利です。 + +ほとんどのリソースのデフォルトスコープです。Python リソースでは、このモードでは OTEL 信頼設定のみが適用されます。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddNodeApp("api", "../api") + .WithCertificateTrustScope(CertificateTrustScope.Append); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder, CertificateTrustScope } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +await builder.addNodeApp("api", "../api", "index.js") + .withCertificateTrustScope(CertificateTrustScope.Append); + +await builder.build().run(); +``` + + + + + +#### Override モード + +リソースを設定された証明書のみを信頼するよう上書きしようとし、デフォルトの信頼済み証明書を完全に置き換えます。このモードは、信頼する証明書を厳密に制御する必要がある場合に便利です。 + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var certBundle = builder.AddCertificateAuthorityCollection("custom-certs") + .WithCertificates(myCertificates); + +builder.AddPythonModule("api", "./api", "uvicorn") + .WithCertificateAuthorityCollection(certBundle) + .WithCertificateTrustScope(CertificateTrustScope.Override); + +builder.Build().Run(); +``` + + + +#### System モード + +設定された証明書とデフォルトのシステムルート証明書を組み合わせて、リソースのデフォルト信頼済み証明書を上書きしようとします。このモードは、Append モードとうまく動作しない Python や類似のランタイムをサポートするために設計されています。 + +Python は証明書信頼を完全に上書きするメカニズムしか持っていないため、Python プロジェクトのデフォルトスコープです。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddPythonApp("worker", "../worker", "main.py") + .WithCertificateTrustScope(CertificateTrustScope.System); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder, CertificateTrustScope } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +await builder.addPythonApp("worker", "../worker", "main.py") + .withCertificateTrustScope(CertificateTrustScope.System); + +await builder.build().run(); +``` + + + +#### None モード + +リソースのすべてのカスタム証明書信頼を無効にし、デフォルトの証明書信頼動作のみに依存させます。 + +デフォルトのシステムストアのソースを自動的に変更する方法がないため、Windows 上の .NET プロジェクトのデフォルトスコープです。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddContainer("service", "myimage") + .WithCertificateTrustScope(CertificateTrustScope.None); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder, CertificateTrustScope } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +await builder.addContainer("service", "myimage") + .withCertificateTrustScope(CertificateTrustScope.None); + +await builder.build().run(); +``` + + + +### カスタム証明書信頼の設定 + +高度なシナリオでは、コールバック API を使用してカスタム証明書信頼動作を指定できます。このコールバックにより、さまざまなリソースタイプの証明書信頼設定に必要なコマンドライン引数と環境変数をカスタマイズできます。 + +#### コールバックを使用して証明書信頼を設定する + +`WithCertificateTrustConfiguration` を使用して、リソースの証明書信頼の設定方法をカスタマイズします: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddContainer("api", "myimage") + .WithCertificateTrustConfiguration(ctx => + { + // コマンドライン引数を追加する + ctx.Arguments.Add("--use-system-ca"); + + // 証明書パスを含む環境変数を設定する + // CertificateBundlePath はカスタム証明書バンドルファイルのパスに解決される + ctx.EnvironmentVariables["MY_CUSTOM_CERT_VAR"] = ctx.CertificateBundlePath; + + // CertificateDirectoriesPath は個別の証明書を含むパスに解決される + ctx.EnvironmentVariables["CERTS_DIR"] = ctx.CertificateDirectoriesPath; + + return Task.CompletedTask; + }); + +builder.Build().Run(); +``` + + + + + + +コールバックは `CertificateTrustConfigurationCallbackAnnotationContext` を受け取り、以下を提供します: + +- `Scope`: リソースの `CertificateTrustScope`。 +- `Arguments`: リソースのコマンドライン引数。値は文字列または `CertificateBundlePath`、`CertificateDirectoriesPath` などのパスプロバイダーを指定できます。 +- `EnvironmentVariables`: 証明書信頼を設定するための環境変数。ディクショナリキーは環境変数名で、値は文字列またはパスプロバイダーを指定できます。デフォルトでは `SSL_CERT_DIR` が含まれ、Override または System スコープが設定されている場合は `SSL_CERT_FILE` も含まれることがあります。 +- `CertificateBundlePath`: カスタム証明書バンドルファイルのパスに解決される値プロバイダー。 +- `CertificateDirectoriesPath`: 個別の証明書を含むパスに解決される値プロバイダー。 + +Node.js、Python、コンテナリソース用のデフォルト実装が提供されています。コンテナリソースは標準の OpenSSL 設定オプションに依存しており、デフォルト値は大多数の一般的な Linux ディストリビューションをサポートしています。 + +#### コンテナ証明書パスを設定する + +コンテナリソースでは、`WithContainerCertificatePaths` を使用して証明書の保存場所とアクセス場所をカスタマイズできます: + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddContainer("api", "myimage") + .WithContainerCertificatePaths( + customCertificatesDestination: "/custom/certs/path", + defaultCertificateBundlePaths: ["/etc/ssl/certs/ca-certificates.crt"], + defaultCertificateDirectoryPaths: ["/etc/ssl/certs"]); + +builder.Build().Run(); +``` + + + +`WithContainerCertificatePaths` API は 3 つのオプションパラメーターを受け取ります: + +- `customCertificatesDestination`: カスタム証明書ファイルが配置されるコンテナ内のベースパスを上書きします。設定しないか `null` に設定した場合、デフォルトパス `/usr/lib/ssl/aspire` が使用されます。 +- `defaultCertificateBundlePaths`: デフォルトの証明機関バンドルファイルが格納されているコンテナ内のパスを上書きします。`CertificateTrustScope` が Override または System の場合、カスタム証明書バンドルはこれらのパスにも追加書き込みされます。設定しないか `null` に設定した場合、一般的な Linux ディストリビューション用のデフォルト証明書パスが使用されます。 +- `defaultCertificateDirectoryPaths`: 個別の信頼済み証明書ファイルが格納されているコンテナ内のパスを上書きします。`CertificateTrustScope` が Append の場合、これらのパスはアップロードされた証明書アーティファクトのパスと連結されます。設定しないか `null` に設定した場合、一般的な Linux ディストリビューション用のデフォルト証明書パスが使用されます。 + + + +## 一般的なシナリオ + +このセクションでは、HTTPS エンドポイントと証明書信頼を一緒に設定するための一般的なパターンを示します。 + +### HTTPS を持つサービスの設定とダッシュボードテレメトリの有効化 + +典型的なシナリオは、Node.js サービスが HTTPS トラフィックを提供しながら、ダッシュボードにテレメトリを送信できるように設定することです: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// HTTPS エンドポイントに開発者証明書を使用するようにサービスを設定する +// また、送信接続(ダッシュボードテレメトリなど)のために開発者証明書を信頼する +var frontend = builder.AddNpmApp("frontend", "../frontend") + .WithHttpsDeveloperCertificate() // HTTPS エンドポイント用サーバー証明書 + .WithDeveloperCertificateTrust(true); // ダッシュボード用クライアント信頼 + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// HTTPS エンドポイントに開発者証明書を使用するようにサービスを設定する +// また、送信接続(ダッシュボードテレメトリなど)のために開発者証明書を信頼する +const frontend = await builder.addNodeApp("frontend", "../frontend", "index.js") + .withHttpsDeveloperCertificate() // HTTPS エンドポイント用サーバー証明書 + .withDeveloperCertificateTrust(true); // ダッシュボード用クライアント信頼 + +await builder.build().run(); +``` + + + +### カスタム証明書を使用した HTTPS の有効化 + +企業またはカスタム CA 証明書を使用する場合、サーバーとクライアントの両方の証明書を設定できます: + +```csharp title="AppHost.cs" +using System.Security.Cryptography.X509Certificates; + +var builder = DistributedApplication.CreateBuilder(args); + +// カスタム証明書を読み込む +var serverCert = new X509Certificate2("server-cert.pfx", "password"); +var customCA = new X509Certificate2Collection(); +customCA.Import("corporate-ca.pem"); + +var caBundle = builder.AddCertificateAuthorityCollection("corporate-certs") + .WithCertificates(customCA); + +// カスタムサーバー証明書と CA 信頼でサービスを設定する +builder.AddContainer("api", "my-api:latest") + .WithHttpsCertificate(serverCert) // HTTPS 用サーバー証明書 + .WithCertificateAuthorityCollection(caBundle); // 企業 CA を信頼する + +builder.Build().Run(); +``` + + + +### Redis を TLS で設定する + +Redis リソースは、安全な接続のために HTTPS (TLS) を使用するよう設定できます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// TLS に開発者証明書を使用するよう Redis を設定する +var redis = builder.AddRedis("cache") + .WithHttpsDeveloperCertificate(); + +// または TLS を完全に無効にする +var redisNoTls = builder.AddRedis("cache-notls") + .WithoutHttpsCertificate(); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// TLS に開発者証明書を使用するよう Redis を設定する +const redis = await builder.addRedis("cache") + .withHttpsDeveloperCertificate(); + +// または TLS を完全に無効にする +const redisNoTls = await builder.addRedis("cache-notls") + .withoutHttpsCertificate(); + +await builder.build().run(); +``` + + + +### 特定のリソースの証明書設定を無効にする + +独自の証明書を管理するリソースに対して、HTTPS エンドポイント設定と証明書信頼の両方を無効にするには: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// すべての自動証明書設定を無効にする +builder.AddPythonModule("api", "./api", "uvicorn") + .WithoutHttpsCertificate() // サーバー証明書設定なし + .WithCertificateTrustScope(CertificateTrustScope.None); // クライアント信頼設定なし + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder, CertificateTrustScope } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// すべての自動証明書設定を無効にする +await builder.addPythonModule("api", "./api", "uvicorn") + .withoutHttpsCertificate() // サーバー証明書設定なし + .withCertificateTrustScope(CertificateTrustScope.None); // クライアント信頼設定なし + +await builder.build().run(); +``` + + + +## 制限事項 + +証明書設定には次の制限事項があります: + +- 現在、実行モードのみサポートされており、発行モードではサポートされていない +- すべての言語とランタイムがすべての信頼スコープモードをサポートしているわけではない +- Python アプリケーションは証明書信頼の Append モードをネイティブにサポートしていない +- カスタム証明書設定にはリソース内での適切なランタイムサポートが必要 +- HTTPS エンドポイント API は試験的(`ASPIRECERTIFICATES001`)としてマークされている diff --git a/src/frontend/src/content/docs/ja/app-host/configuration.mdx b/src/frontend/src/content/docs/ja/app-host/configuration.mdx new file mode 100644 index 000000000..b489616c7 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/configuration.mdx @@ -0,0 +1,190 @@ +--- +title: AppHost 設定 +description: Aspire AppHost 設定オプションについて学習します。 +--- + +import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import { Image } from 'astro:assets'; +import PivotSelector from '@components/PivotSelector.astro'; +import Pivot from '@components/Pivot.astro'; +import dashboardUpdateNotification from '@assets/whats-new/dashboard-update-notification.png'; + +AppHost プロジェクトは、分散アプリケーションを設定して起動します。設定には、リソースサービス、[Aspire ダッシュボード](/ja/dashboard/overview/)、および統合によって使用される内部設定が含まれます。 + +AppHost 設定は起動プロファイルを通じて提供されます: + + + +C# AppHost では、プロファイルは `launchSettings.json` に存在します: + +```json title="launchSettings.json" +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:17134;http://localhost:15170", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21030", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22057" + } + } + } +} +``` + + +TypeScript AppHost では、プロファイルは `aspire.config.json` に存在します: + +```json title="aspire.config.json" +{ + "appHost": { + "path": "apphost.ts", + "language": "typescript/nodejs" + }, + "profiles": { + "https": { + "applicationUrl": "https://localhost:17134;http://localhost:15170", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21030", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22057" + } + } + } +} +``` + + + + +## 共通設定 + +| オプション | 既定値 | 詳細 | +| ---------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ASPIRE_ALLOW_UNSECURED_TRANSPORT` | `false` | AppHost との HTTPS なし通信を許可します。`ASPNETCORE_URLS`(ダッシュボードアドレス)と `ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL`(AppHost リソースサービスアドレス)は、true でない限り HTTPS で保護する必要があります。 | +| `ASPIRE_CONTAINER_RUNTIME` | `docker` | コンテナでサポートされているリソースに対して、代替コンテナランタイムの使用を許可します。可能な値は `docker`(既定値)または `podman` です。 | +| `ASPIRE_DCP_USE_DEVELOPER_CERTIFICATE` | `false` | `true` に設定すると、Aspire は DCP によって生成されたエフェメラル証明書の代わりに、信頼されたデベロッパー証明書を使用して内部 DCP サーバーをセキュアします。これにより、開発証明書がすでに信頼されている場合、証明書信頼の問題を回避できます。信頼されたデベロッパー証明書が見つからない場合、Aspire は DCP によって生成されたエフェメラル証明書にフォールバックします。Windows でのみサポートされています。詳細については、[証明書設定](/ja/app-host/certificate-configuration/)を参照してください。 | +| `ASPIRE_ENVIRONMENT` | `null` | より高い優先度の環境ソースが設定されていない場合、AppHost 環境を設定します。環境が設定されていない場合、AppHost は `Production` を使用します。 | +| `ASPIRE_VERSION_CHECK_DISABLED` | `false` | `true` に設定すると、Aspire は起動時に新しいバージョンをチェックしません。 | + +## AppHost 環境 + +`ASPIRE_ENVIRONMENT` を使用して、アプリケーションモデルを評価する際に AppHost によって使用される環境名を設定します。優先度は `--environment`、`DOTNET_ENVIRONMENT`、`ASPIRE_ENVIRONMENT`、その後 `Production` です。これはダッシュボードの `ASPNETCORE_ENVIRONMENT` を設定したり、自動的に子リソースにフローしたりしません。必要に応じて、リソース上でフレームワーク固有の変数を設定してください。詳細については、[Aspire 環境](/ja/deployment/environments/)を参照してください。 + +## バージョン更新通知 + +Aspire アプリが起動すると、新しいバージョンの Aspire が NuGet で利用可能かどうかがチェックされます。新しいバージョンが見つかった場合、ダッシュボードに最新のバージョン番号、[アップグレード手順へのリンク](https://aka.ms/dotnet/aspire/update-latest)、および今後そのバージョンを無視するボタンを含む通知が表示されます。 + +バージョン更新通知とアップグレードオプションを示すダッシュボードのスクリーンショット。 + +バージョンチェックは、以下の場合にのみ実行されます: + +- ダッシュボードが有効(相互作用サービスが利用可能) +- 最後のチェック以来少なくとも 2 日が経過している +- チェックが `ASPIRE_VERSION_CHECK_DISABLED` 設定を通じて無効になっていない +- アプリが発行モードで実行されていない + +更新は手動です。Aspire SDK およびパッケージバージョンをアップグレードするには、プロジェクトファイルを編集する必要があります。 + +## リソースサービス + +リソースサービスは AppHost によってホストされています。リソースサービスは、Aspire によってオーケストレーションされているリソースに関する情報を取得するためにダッシュボードによって使用されます。 + +| オプション | 既定値 | 詳細 | +| ----------------------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL` | `null` | AppHost でホストされているリソースサービスのアドレスを設定します。_launchSettings.json_ で自動生成され、localhost 上のランダムなポートを使用します。例: `https://localhost:17037`。 | +| `ASPIRE_DASHBOARD_RESOURCESERVICE_APIKEY` | 自動生成された 128 ビットエントロピートークン。 | AppHost のリソースサービスに対して行われた要求を認証するために使用される API キー。AppHost が実行モード、ダッシュボードが無効でなく、ダッシュボードが `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS` で匿名アクセスを許可するように設定されていない場合、API キーが必要です。 | + +## ダッシュボード + +既定では、ダッシュボードは AppHost によって自動的に起動されます。ダッシュボードは[独自の設定セット](/ja/dashboard/configuration/)をサポートし、一部の設定は AppHost から設定できます。 + +| オプション | 既定値 | 詳細 | +| ------------------------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ASPNETCORE_URLS` | `null` | ダッシュボードアドレス。`ASPIRE_ALLOW_UNSECURED_TRANSPORT` または `DistributedApplicationOptions.AllowUnsecuredTransport` が true でない限り、`https` である必要があります。_launchSettings.json_ で自動生成され、localhost 上のランダムなポートを使用します。起動設定の値は `applicationUrls` プロパティに設定されます。 | +| `ASPNETCORE_ENVIRONMENT` | `Production` | ダッシュボードが実行される環境を設定します。詳細については、[ASP.NET Core で複数の環境を使用する](https://learn.microsoft.com/ja-jp/aspnet/core/fundamentals/environments)を参照してください。 | +| `ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL` | gRPC エンドポイントが設定されていない場合は `http://localhost:18889`。 | ダッシュボード OTLP gRPC アドレスを設定します。ダッシュボードが OTLP 経由でテレメトリを受信するために使用されます。リソース上で `OTEL_EXPORTER_OTLP_ENDPOINT` 環境変数として設定されます。`OTEL_EXPORTER_OTLP_PROTOCOL` 環境変数は `grpc` です。_launchSettings.json_ で自動生成され、localhost 上のランダムなポートを使用します。 | +| `ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL` | `null` | ダッシュボード OTLP HTTP アドレスを設定します。ダッシュボードが OTLP 経由でテレメトリを受信するために使用されます。`ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL` のみが設定されている場合、リソース上で `OTEL_EXPORTER_OTLP_ENDPOINT` 環境変数として設定されます。`OTEL_EXPORTER_OTLP_PROTOCOL` 環境変数は `http/protobuf` です。 | +| `ASPIRE_DASHBOARD_CORS_ALLOWED_ORIGINS` | `null` | ダッシュボードで設定された CORS 許可オリジンをオーバーライドします。この設定は、リソースエンドポイントに基づいて許可オリジンを計算する既定の動作に代わります。 | +| `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS`| `false` | ダッシュボードが認証を使用しないように設定し、匿名アクセスを受け入れます。フロントエンド、OTLP、MCP、および API 認証モードを `Unsecured` に設定します。 | +| `ASPIRE_DASHBOARD_FRONTEND_BROWSERTOKEN` | 自動生成された 128 ビットエントロピートークン。 | フロントエンドブラウザトークンを設定します。これは、認証モードが BrowserToken である場合にダッシュボードにアクセスするために入力する必要がある値です。ブラウザトークンが指定されていない場合、AppHost が起動されるたびに新しいトークンが生成されます。 | +| `ASPIRE_DASHBOARD_TELEMETRY_OPTOUT` | `false` | ダッシュボードが[使用テレメトリ](/ja/dashboard/microsoft-collected-dashboard-telemetry/)を送信しないように設定します。 | +| `ASPIRE_DASHBOARD_AI_DISABLED` | `true` | 将来の使用のために予約されています。ダッシュボード内の GitHub Copilot UI は Aspire 13.3 で削除されました。AI コーディングエージェントは、[Aspire CLI および MCP サーバー](/ja/dashboard/ai-coding-agents/)を通じてテレメトリデータにアクセスできます。 | +| `ASPIRE_DASHBOARD_API_ENABLED` | `true` | ダッシュボード[テレメトリ API](/ja/dashboard/configuration/#api)(`/api/telemetry/*`)エンドポイントを有効にします。AppHost は常にこれを `true` に設定します。 | +| `ASPIRE_DASHBOARD_FORWARDEDHEADERS_ENABLED` | `false` | `X-Forwarded-Proto` および `X-Forwarded-Host` ヘッダーから来ている値を使用して、Request コンテキストのスキーマとホスト値を置き換える転送ヘッダーミドルウェアを有効にします。 | + +## 内部 + +内部設定は AppHost と統合によって使用されます。内部設定は直接設定するように設計されていません。 + +| オプション | 既定値 | 詳細 | +| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `AppHost:Directory` | プロジェクトがない場合のコンテンツルート。 | AppHost が置かれているプロジェクトのディレクトリ。`IDistributedApplicationBuilder.AppHostDirectory` からアクセス可能。 | +| `AppHost:Path` | ディレクトリとアプリケーション名を組み合わせたもの。 | AppHost へのパス。ディレクトリをアプリケーション名と組み合わせます。 | +| `AppHost:Sha256` | AppHost が発行モード時に AppHost 名から作成されます。それ以外の場合は AppHost パスから作成されます。 | 現在のアプリケーションの 16 進エンコードハッシュ。ハッシュは現在のマシン上のアプリケーションの場所に基づいているため、AppHost の起動間で安定しています。 | +| `AppHost:OtlpApiKey` | 自動生成された 128 ビットエントロピートークン。 | ダッシュボード OTLP サービスに送信された要求を認証するために使用される API キー。値は必要な場合に存在します: AppHost が実行モード、ダッシュボードが無効でなく、ダッシュボードが `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS` で匿名アクセスを許可するように設定されていません。 | +| `AppHost:DashboardApiKey` | 自動生成された 128 ビットエントロピートークン。 | ダッシュボードテレメトリ API への要求を認証するために使用される API キー。`AppHost:McpApiKey` が設定されていない場合、MCP 認証のフォールバックとしても使用されます。値は必要な場合に存在します: AppHost が実行モード、ダッシュボードが無効でなく、ダッシュボードが匿名アクセスを許可するように設定されていません。 | +| `AppHost:BrowserToken` | 自動生成された 128 ビットエントロピートークン。 | AppHost によって起動される場合にダッシュボードへのブラウジングを認証するために使用されるブラウザトークン。ブラウザトークンは `ASPIRE_DASHBOARD_FRONTEND_BROWSERTOKEN` によって設定できます。値は必要な場合に存在します: AppHost が実行モード、ダッシュボードが無効でなく、ダッシュボードが `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS` で匿名アクセスを許可するように設定されていません。 | +| `AppHost:ResourceService:AuthMode` | `ApiKey`。`ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS` が true の場合、値は `Unsecured` です。 | リソースサービスへのアクセスに使用される認証モード。値は必要な場合に存在します: AppHost が実行モードで、ダッシュボードが無効でなく。 | +| `AppHost:ResourceService:ApiKey` | 自動生成された 128 ビットエントロピートークン。 | AppHost のリソースサービスに対して行われた要求を認証するために使用される API キー。API キーは `ASPIRE_DASHBOARD_RESOURCESERVICE_APIKEY` によって設定できます。値は必要な場合に存在します: AppHost が実行モード、ダッシュボードが無効でなく、ダッシュボードが `ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS` で匿名アクセスを許可するように設定されていません。 | + +## 高度なオーケストレーションプロパティ + + + +### DcpCliPath + +`DcpCliPath` プロパティは、**開発者制御プレーン (DCP)** 実行可能ファイルへのパスを指定します。DCP は、Aspire が開発中にローカルで分散アプリケーションリソースを実行および管理するために使用するコアオーケストレーションエンジンです。 + +#### 動作方法 + +[Aspire SDK](/ja/get-started/aspire-sdk/) を使用する場合、ビルドシステムは自動的に: + +1. プラットフォーム固有の `Aspire.Hosting.Orchestration` NuGet パッケージ(例: `Aspire.Hosting.Orchestration.win-x64`)をインポートします。 +2. `DcpCliPath` をそのパッケージ内の `dcp` 実行可能ファイルを指すように設定します。 +3. このパスをコンパイル済みの AppHost にアセンブリメタデータとして埋め込みます。 + +実行時に、AppHost はこのメタデータを読み取り、DCP プロセスを見つけて起動し、アプリケーションのリソースをオーケストレーションします。 + +#### オーバーライドオプション + +まれな場合、既定の DCP パスをオーバーライドする必要があります: + +| メソッド | 例 | +| ------ | ------- | +| MSBuild プロパティ | `C:\path\to\dcp.exe` | +| コマンドライン引数 | `--dcp-cli-path /path/to/dcp` | +| 設定 | `DcpPublisher:CliPath` | + +#### どういう時に使用するか + +これらのシナリオで `DcpCliPath` をオーバーライドすることができます: + +- **Aspire 貢献者**: Aspire 自体を開発する際に、DCP のカスタムまたはデバッグビルドでテストします。 +- **CI/CD パイプライン**: 自動検出が機能しない非標準 SDK レイアウト。 +- **トラブルシューティング**: 特定の DCP バージョンを一時的に指す際に問題を診断します。 + + diff --git a/src/frontend/src/content/docs/ja/app-host/container-files.mdx b/src/frontend/src/content/docs/ja/app-host/container-files.mdx new file mode 100644 index 000000000..d769f4da2 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/container-files.mdx @@ -0,0 +1,434 @@ +--- +title: コンテナー ファイル +description: Aspire のコンテナー ファイル API を使用して、開発時と発行時にファイルやディレクトリをコンテナーへ挿入する方法を学びます。 +--- + +import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; + +Aspire には、ファイルやディレクトリをコンテナーへ挿入する API が用意されており、カスタムの構成ファイル、スクリプト、証明書、その他のアセットを使用してコンテナー化されたリソースを構成できます。相補的な API が 2 つあります: + +- **`WithContainerFiles`**: `aspire run` 実行時に、コンテナーの起動時点で開発用のファイルをコンテナーへ挿入します。 +- **`PublishWithContainerFiles`**: `aspire publish` 実行時に、発行用のビルド成果物として、あるリソースのコンテナーから別のリソースのコンテナーへファイルをコピーします。 + +## 開発時にファイルを挿入する + +`WithContainerFiles` 拡張メソッドは、指定した宛先パスにあるコンテナー内のファイルやディレクトリを作成または更新します。ニーズに応じて、宣言的にファイルを定義するインライン エントリ、ホスト ファイル システムからコピーするためのソース パス、動的にファイルを生成する非同期コールバックという 3 つの方法をサポートします。 + + + +### インライン エントリ + +インライン エントリのオーバーロードを使用すると、`ContainerFileSystemItem` オブジェクトを使ってファイルやディレクトリを宣言的に定義できます。これは、ファイル内容がビルド時点で分かっている場合や、文字列リテラルとして表現できる場合に便利です。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddContainer("myapp", "myapp:latest") + .WithContainerFiles("/app/config", [ + new ContainerFile + { + Name = "appsettings.json", + Contents = """ + { + "Logging": { + "LogLevel": { + "Default": "Information" + } + } + } + """ + }, + new ContainerDirectory + { + Name = "scripts", + Entries = [ + new ContainerFile + { + Name = "init.sh", + Contents = "#!/bin/bash\necho 'Initializing...'", + Mode = UnixFileMode.UserRead + | UnixFileMode.UserWrite + | UnixFileMode.UserExecute + } + ] + } + ]); + +builder.Build().Run(); +``` + + +:::note +`withContainerFiles` API は、TypeScript AppHost SDK ではまだ利用できません。 +::: + + + +前の例では: + +- 指定した内容を持つ JSON 構成ファイルが `/app/config/appsettings.json` に作成されます。 +- 実行可能なシェル スクリプトを含む入れ子の `scripts` ディレクトリが `/app/config/scripts/` に作成されます。 + +### ソース パス + +ソース パスのオーバーロードを使用すると、ホスト マシン上のディレクトリからコンテナーへファイルをコピーできます。これは、既存の構成ファイルやアセットがディスク上にある場合に便利です。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddContainer("myapp", "myapp:latest") + .WithContainerFiles("/app/config", "./config-files"); + +builder.Build().Run(); +``` + + +:::note +`withContainerFiles` API は、TypeScript AppHost SDK ではまだ利用できません。 +::: + + + +ソース パスがルート化された絶対パスでない限り、AppHost プロジェクト ディレクトリからの相対パスとして解釈されます。ソース ディレクトリ内のすべてのファイルは、起動時にコンテナー内の宛先パスへコピーされます。 + +### 非同期コールバック + +コールバック オーバーロードを使用すると、コンテナーの起動時に動的にファイルを生成できます。このコールバックは `ContainerFileSystemCallbackContext` を受け取り、`IServiceProvider` とリソースの `IResource` モデルにアクセスできるため、サービスを解決したりアプリ モデルを検査したりできます。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddContainer("worker", "worker:latest") + .WithContainerFiles("/app/config", + async (context, cancellationToken) => + { + var config = new + { + MachineName = Environment.MachineName, + Timestamp = DateTime.UtcNow + }; + + return + [ + new ContainerFile + { + Name = "runtime-config.json", + Contents = JsonSerializer.Serialize(config) + } + ]; + }); + +builder.Build().Run(); +``` + + +:::note +`withContainerFiles` API は、TypeScript AppHost SDK ではまだ利用できません。 +::: + + + +このコールバックはコンテナーが起動するたびに呼び出されるため、生成されるファイルには常に現在の状態が反映されます。 + +## ファイルの種類 + +`WithContainerFiles` API は、抽象 `ContainerFileSystemItem` クラスを基底とする型階層を使用します。各型は、異なる種類のファイル システム エントリを表します。 + +### ContainerFile + +`ContainerFile` は標準的なファイルを表します。ファイル データを指定するには、`Contents` (文字列) または `SourcePath` (ホスト上の絶対パス) のいずれかを設定します。両方を同時に設定することはできません。 + +```csharp title="AppHost.cs" +// インライン内容を持つファイル +var configYaml = new ContainerFile +{ + Name = "config.yaml", + Contents = "key: value" +}; + +// ホスト ファイル システムから取得するファイル +var dataCsv = new ContainerFile +{ + Name = "data.csv", + SourcePath = "/path/to/data.csv" +}; +``` + +この特定のファイルの作成に失敗してもコンテナーを起動できるようにするには、`ContinueOnError` を `true` に設定します: + +```csharp title="AppHost.cs" +var optionalJson = new ContainerFile +{ + Name = "optional-config.json", + Contents = "{}", + ContinueOnError = true +}; +``` + +### ContainerDirectory + +`ContainerDirectory` は、入れ子にした `ContainerFileSystemItem` エントリを含められるディレクトリを表し、任意のディレクトリ ツリーを構築できます。 + +```csharp title="AppHost.cs" +var certsDir = new ContainerDirectory +{ + Name = "certs", + Entries = [ + new ContainerFile + { + Name = "ca.pem", + SourcePath = "/path/to/ca.pem" + }, + new ContainerDirectory + { + Name = "private", + Entries = [ + new ContainerFile + { + Name = "server.key", + SourcePath = "/path/to/server.key", + Mode = UnixFileMode.UserRead + } + ] + } + ] +}; +``` + +静的な `GetFileSystemItemsFromPath` メソッドを使用して、ディスク上のファイルから `ContainerDirectory` を構築することもできます: + +```csharp title="AppHost.cs" +var assetsDir = new ContainerDirectory +{ + Name = "assets", + Entries = ContainerDirectory.GetFileSystemItemsFromPath( + "/path/to/assets", + searchOptions: SearchOption.AllDirectories) +}; +``` + +### ContainerOpenSSLCertificateFile + +`ContainerOpenSSLCertificateFile` は、PEM エンコードされた公開証明書を表します。Aspire は、証明書ファイルをコンテナーへ配置するだけでなく、同じディレクトリ内に OpenSSL 互換のシンボリック リンク (`[subject hash].[n]`) も自動で作成します。これは `openssl rehash` の実行と同等です。これにより、証明書の検証に OpenSSL を使用するコンテナーが、この証明書を自動的に検出できるようになります。 + + + +```csharp title="AppHost.cs" +builder.AddContainer("myapp", "myapp:latest") + .WithContainerFiles("/certs", [ + new ContainerOpenSSLCertificateFile + { + Name = "ca-cert.pem", + Contents = pemCertificateString + } + ]); +``` + + +:::note +`withContainerFiles` API は、TypeScript AppHost SDK ではまだ利用できません。 +::: + + + +## ファイルのアクセス許可と所有者 + +`WithContainerFiles` のすべてのオーバーロードは、ファイルの所有者とアクセス許可を制御するための省略可能なパラメーターを受け取ります。 + +### 所有者とグループ + +`defaultOwner` と `defaultGroup` パラメーターは、作成されるすべてのファイルとディレクトリに適用される既定の UID と GID を設定します。どちらも指定しない場合は `0` (root) が既定値です。任意の `ContainerFileSystemItem` にある `Owner` および `Group` プロパティを使用して、個々の項目の所有者を上書きできます。 + + + +```csharp title="AppHost.cs" +builder.AddContainer("myapp", "myapp:latest") + .WithContainerFiles("/app/data", + [ + new ContainerFile + { + Name = "shared.txt", + Contents = "shared data" + }, + new ContainerFile + { + Name = "user-only.txt", + Contents = "private data", + Owner = 1000, + Group = 1000 + } + ], + defaultOwner: 33, // www-data + defaultGroup: 33); +``` + + +:::note +`withContainerFiles` API は、TypeScript AppHost SDK ではまだ利用できません。 +::: + + + +この例では、`shared.txt` は既定の owner/group である `33` を継承し、`user-only.txt` は UID/GID `1000` で上書きします。 + +### Umask + +`umask` パラメーターは、既定の権限から権限ビットを差し引くことで、既定のアクセス許可を制御します。項目に明示的な `Mode` が設定されていない場合は次のようになります: + +- **ディレクトリ**: `0777` (全員に読み取り、書き込み、実行) から開始し、そこから umask が差し引かれます +- **ファイル**: `0666` (全員に読み取り、書き込み) から開始し、そこから umask が差し引かれます + +既定の umask は `0022` で、結果は次のとおりです: + +- ディレクトリ: `0755` (owner: rwx、group: r-x、others: r-x) +- ファイル: `0644` (owner: rw-、group: r--、others: r--) + +umask ベースの既定値を上書きするには、個々の項目で `Mode` を直接設定できます: + + + +```csharp title="AppHost.cs" +builder.AddContainer("myapp", "myapp:latest") + .WithContainerFiles("/app/scripts", + [ + new ContainerFile + { + Name = "run.sh", + Contents = "#!/bin/bash\necho 'Running'", + Mode = UnixFileMode.UserRead + | UnixFileMode.UserWrite + | UnixFileMode.UserExecute + } + ], + umask: UnixFileMode.OtherRead + | UnixFileMode.OtherWrite + | UnixFileMode.OtherExecute); +``` + + +:::note +`withContainerFiles` API は、TypeScript AppHost SDK ではまだ利用できません。 +::: + + + +### 永続コンテナー + +`ContainerLifetime.Persistent` を持つコンテナーでは、コンテナー ファイル エントリの内容を変更するとコンテナーが再作成されます。意図しないコンテナー再起動を避けるため、`WithContainerFiles` で書き込まれるデータは、特定のアプリ モデル構成に対して冪等になるようにしてください。 + +## 発行時にファイルを挿入する + +`PublishWithContainerFiles` メソッドは、`aspire publish` の実行中に、あるリソースのコンテナーから別のリソースのコンテナーへファイルをコピーします。これは、発行時にコンテナーへファイルを挿入するための推奨アプローチです。 + +代表的なユース ケースは、シングルページ アプリケーション (SPA) や静的な JavaScript フロントエンドを、本番デプロイ用のリバース プロキシまたは Web サーバー コンテナーに埋め込むことです。開発時には、Vite や React のようなフロントエンド アプリは通常、スタンドアロンの開発サーバーとして実行されます。一方、本番環境では、コンパイル済みの静的アセットはバックエンド API や Nginx のような専用 Web サーバーから配信されることが一般的です。`PublishWithContainerFiles` は、ビルド済みのフロントエンド出力を発行プロセスの一部として配信先コンテナーへコピーすることで、このギャップを埋めます。手動でのファイル コピーやマルチステージ Dockerfile は不要です。 + +### バックエンドにフロントエンドを埋め込む + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var frontend = builder.AddViteApp("frontend", "../frontend"); + +var api = builder.AddProject("api") + .PublishWithContainerFiles(frontend, "./wwwroot"); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const frontend = await builder.addViteApp("frontend", "../frontend"); + +const api = await builder.addProject("api", "./Api/Api.csproj", "https") + .publishWithContainerFiles(frontend, "./wwwroot"); + +await builder.build().run(); +``` + + + +この例では: + +1. `frontend` リソースはコンテナー内でビルドされ、コンパイル済みの JavaScript、CSS、HTML を生成します。 +2. 発行時に、Aspire はそれらのファイルを `frontend` コンテナーから `api` コンテナー内の `./wwwroot` へコピーします。 +3. 結果として得られる `api` コンテナーには API コードとフロントエンドの静的アセットの両方が含まれ、アプリケーション全体を配信する準備が整います。 + +### YARP からフロントエンドを配信する + +フロントエンド アセットを専用のリバース プロキシ コンテナーへ埋め込むこともできます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var frontend = builder.AddViteApp("frontend", "../frontend"); + +var nginx = builder.AddYarp("gateway") + .PublishWithStaticFiles(frontend); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const frontend = await builder.addViteApp("frontend", "../frontend"); + +const nginx = await builder.addYarp("gateway") + .publishWithStaticFiles(frontend); + +await builder.build().run(); +``` + + + +これにより、外部ボリューム マウントや実行時のファイル コピーを必要としない、フロントエンド アプリケーションを配信する自己完結型の Nginx コンテナーが生成されます。 + +`PublishWithContainerFiles` は発行モードでのみ適用され、`aspire run` 中は効果がありません。宛先リソースは `IContainerFilesDestinationResource` (例: `ProjectResource`) を実装し、ソース リソースは `IResourceWithContainerFiles` を実装している必要があります。 + +### ソース パスをカスタマイズする + +既定では、ソース リソースは構成済みの出力パスに基づいて、自身のコンテナーからファイルをエクスポートします。ソース コンテナー内のどのパスからコピーするかを指定するには、`WithContainerFilesSource` を使用します: + + + +```csharp title="AppHost.cs" +var frontend = builder.AddViteApp("frontend", "../frontend") + .WithContainerFilesSource("/app/dist"); + +var api = builder.AddProject("api") + .PublishWithContainerFiles(frontend, "./wwwroot"); +``` + + +:::note +`withContainerFiles` API は、TypeScript AppHost SDK ではまだ利用できません。 +::: + + + +以前に構成したソース パスを削除してから新しいものを追加するには、`ClearContainerFilesSources` を使用します。 + +## 関連項目 + +- [証明書の設定](/ja/app-host/certificate-configuration/) +- [アプリモデルに Dockerfile を追加する](/ja/app-host/withdockerfile/) +- [コンテナの永続的なライフタイム](/ja/app-host/persistent-containers/) diff --git a/src/frontend/src/content/docs/ja/app-host/container-registry.mdx b/src/frontend/src/content/docs/ja/app-host/container-registry.mdx new file mode 100644 index 000000000..b5126dfc0 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/container-registry.mdx @@ -0,0 +1,592 @@ +--- +title: コンテナーレジストリの設定 +description: Aspire アプリケーションのコンテナーレジストリを設定する方法について説明します。汎用レジストリと Azure Container Registry を対象としています。 +--- + +import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + +Aspire 13.1 では明示的なコンテナーレジストリ設定が導入され、デプロイ時にコンテナーイメージをどこへいつプッシュするかを開発者が制御できるようになりました。この記事では、Aspire アプリケーションのコンテナーレジストリを設定する方法について説明します。 + +## コンテナーレジストリの設定 + +Aspire アプリケーションを本番環境にデプロイする際、コンテナー化されたサービスをコンテナーレジストリにプッシュする必要があります。Aspire 13.1 以前は、レジストリ設定が暗黙的であることが多く、デプロイプロセスの制御や把握が困難でした。新しい `ContainerRegistryResource` では、次の項目を明示的に設定できます: + +- **汎用コンテナーレジストリ** — DockerHub、GitHub Container Registry (GHCR)、Harbor、またはその他の Docker 互換レジストリ +- **Azure Container Registry** — 自動認証情報管理による第一級サポート +- **パイプライン統合** — `aspire do push` を使用してイメージのビルドとプッシュのタイミングを制御 +- **認証** — レジストリの認証情報を安全に設定 + +## 汎用コンテナーレジストリ + + + +`AddContainerRegistry` メソッドを使用して、アプリケーションの汎用コンテナーレジストリを設定します。DockerHub、GitHub Container Registry、Harbor、プライベートレジストリなど、あらゆる Docker 互換レジストリで使用できます。 + +### 基本的な使い方 + +次の例では、コンテナーレジストリを設定し、プロジェクトリソースに関連付けます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// コンテナーレジストリを追加する +var registry = builder.AddContainerRegistry("myregistry", "registry.example.com"); + +// レジストリをプロジェクトに関連付ける +var api = builder.AddProject("api") + .WithContainerRegistry(registry); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// コンテナーレジストリを追加する +const registry = await builder.addContainerRegistry("myregistry", "registry.example.com"); + +// レジストリをプロジェクトに関連付ける +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withContainerRegistry(registry); + +await builder.build().run(); +``` + + + +上記のコードについて: + +- `registry.example.com` を指すコンテナーレジストリリソースを作成します。 +- レジストリを `api` プロジェクトに関連付けます。 +- デプロイ時に、`api` プロジェクトはコンテナーイメージとしてビルドされ、指定されたレジストリにプッシュされます。 + +### DockerHub の例 + +DockerHub にイメージをプッシュするには、レジストリエンドポイントとして `docker.io` を指定します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var registry = builder.AddContainerRegistry("dockerhub", "docker.io"); + +var api = builder.AddProject("api") + .WithContainerRegistry(registry); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const registry = await builder.addContainerRegistry("dockerhub", "docker.io"); + +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withContainerRegistry(registry); +``` + + + +### GitHub Container Registry の例 + +GitHub Container Registry (GHCR) にイメージをプッシュするには: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var registry = builder.AddContainerRegistry("ghcr", "ghcr.io"); + +var api = builder.AddProject("api") + .WithContainerRegistry(registry); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const registry = await builder.addContainerRegistry("ghcr", "ghcr.io"); + +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withContainerRegistry(registry); +``` + + + +### プライベートレジストリの例 + +プライベートレジストリの場合は、完全なレジストリ URL を指定します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var registry = builder.AddContainerRegistry( + "private-registry", + "registry.mycompany.com:5000"); + +var api = builder.AddProject("api") + .WithContainerRegistry(registry); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const registry = await builder.addContainerRegistry( + "private-registry", + "registry.mycompany.com:5000"); + +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withContainerRegistry(registry); +``` + + + +## 認証と認証情報 + +コンテナーレジストリには通常、イメージをプッシュするための認証が必要です。パラメーターとシークレットを使用して認証情報を設定できます。 + +### パラメーターを使用したレジストリ認証情報の設定 + +パラメーターを使用すると、レジストリ設定を動的に提供できます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var registryEndpoint = builder.AddParameter("registry-endpoint"); +var registryRepository = builder.AddParameter("registry-repository"); + +var registry = builder.AddContainerRegistry( + "myregistry", + registryEndpoint, + registryRepository); + +var api = builder.AddProject("api") + .WithContainerRegistry(registry); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const registryEndpoint = await builder.addParameter("registry-endpoint"); +const registryRepository = await builder.addParameter("registry-repository"); + +const registry = await builder.addContainerRegistry( + "myregistry", + registryEndpoint, + registryRepository); + +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withContainerRegistry(registry); +``` + + + + + パラメーターの詳細については、[外部パラメーター](/ja/fundamentals/external-parameters/) を参照してください。 + + +### 認証情報の設定 + +レジストリの認証情報は、デプロイ環境を通じて設定する必要があります: + +#### Docker ログイン + +イメージをプッシュする前に、レジストリへの認証を確認してください: + +```bash title="Bash — Docker ログイン" +docker login registry.example.com +``` + +DockerHub の場合: + +```bash title="Bash — DockerHub ログイン" +docker login docker.io -u username +``` + +GitHub Container Registry の場合: + +```bash title="Bash — GHCR ログイン" +echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin +``` + +#### CI/CD の設定 + +CI/CD 環境 (GitHub Actions、Azure Pipelines など) では、シークレットを使用して認証情報を設定します: + +```yaml title="YAML — GitHub Actions の例" +- name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + +- name: Push images + run: aspire do push +``` + +## Azure Container Registry + +Azure Container Registry (ACR) は、自動認証情報管理と並列プロビジョニングにより、Aspire との第一級の統合を提供します。 + +### 明示的な ACR 設定 + +Aspire 13.1 では、Azure Container Apps 環境向けの明示的なコンテナーレジストリ設定が導入されました: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var environment = builder.AddAzureContainerAppEnvironment("myenv"); + +var api = builder.AddProject("api") + .WithContainerRegistry(environment); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const environment = await builder.addAzureContainerAppEnvironment("myenv"); + +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withContainerRegistry(environment); + +await builder.build().run(); +``` + + + +上記の例について: + +- コードは ACR が関連付けられた Azure Container Apps 環境を作成します。 +- ACR はその環境と並列にプロビジョニングされます。 +- レジストリが使用可能になるとすぐにイメージがプッシュされます。 +- 認証情報は Azure 認証を通じて自動的に管理されます。 + + + + + 詳細については、[Azure Container Registry 統合](/ja/integrations/cloud/azure/azure-container-registry/azure-container-registry-get-started/) を参照してください。 + + +### 既存の ACR を使用する + +既存の Azure Container Registry を使用するには、ACR を追加する際に `PublishAsExisting` メソッドを呼び出します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var registryName = builder.AddParameter("registryName"); +var rgName = builder.AddParameter("rgName"); + +var acr = builder.AddAzureContainerRegistry("my-acr") + .PublishAsExisting(registryName, rgName); + +builder.AddAzureContainerAppEnvironment("env") + .WithAzureContainerRegistry(acr); + +var api = builder.AddProject("api") + .WithContainerRegistry(acr); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const registryName = await builder.addParameter("registryName"); +const rgName = await builder.addParameter("rgName"); + +const acr = await builder.addAzureContainerRegistry("my-acr"); +await acr.publishAsExisting(registryName, rgName); + +const environment = await builder.addAzureContainerAppEnvironment("env"); +await environment.withAzureContainerRegistry(acr); + +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withContainerRegistry(acr); +``` + + + +## パイプライン統合 + +Aspire のデプロイパイプラインには、コンテナーイメージをレジストリにプッシュするための専用の `push` ステップが含まれています。 + +### aspire do push の使い方 + +`aspire do push` コマンドは、コンテナーイメージをビルドし、設定されたレジストリにプッシュします: + +```bash title="Aspire CLI — イメージのプッシュ" +aspire do push +``` + +このコマンドは以下を実行します: + + + +1. コンピューティングリソースのすべてのコンテナーイメージをビルドします +2. 適切なレジストリとリポジトリ名でイメージにタグを付けます +3. 設定されたレジストリにイメージをプッシュします + + + +出力例: + +```plaintext title="出力" data-disable-copy +16:03:38 (pipeline-execution) → Starting pipeline-execution... +16:03:38 (build-api) → Starting build-api... +16:03:43 (push-api) → Starting push-api... +16:03:43 (push-api) → Pushing api to container-registry +16:03:44 (push-api) i [INF] Docker tag for api -> docker.io/username/api:latest succeeded. +16:04:05 (push-api) i [INF] Docker push for docker.io/username/api:latest succeeded. +16:04:05 (push-api) ✓ Successfully pushed api to docker.io/username/api:latest (21.3s) +16:04:05 (push-api) ✓ push-api completed successfully +``` + + + パイプラインコマンドの詳細については、[`aspire do` コマンド](/ja/reference/cli/commands/aspire-do/) を参照してください。 + + +### パイプラインステップの依存関係 + +`push` ステップは依存関係を自動的に処理します: + +- **`build-prereq`** — ビルド前に前提条件を確認します +- **`build-`** — 各リソースのコンテナーイメージをビルドします +- **`push-`** — レジストリにイメージをプッシュします + +個々のステップまたはパイプライン全体を実行できます: + +```bash title="Aspire CLI — ビルドのみ" +aspire do build +``` + +```bash title="Aspire CLI — 完全デプロイ" +aspire do deploy +``` + +`deploy` ステップには、すべてのリソースのビルド、プッシュ、デプロイが含まれます。 + +## 完全な例 + +### マルチレジストリデプロイ + +リソースごとに異なるレジストリを設定できます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var publicRegistry = builder.AddContainerRegistry("dockerhub", "docker.io"); +var privateRegistry = builder.AddContainerRegistry( + "private", + "registry.company.com"); + +var publicApi = builder.AddProject("public-api") + .WithContainerRegistry(publicRegistry); + +var internalApi = builder.AddProject("internal-api") + .WithContainerRegistry(privateRegistry); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const publicRegistry = await builder.addContainerRegistry("dockerhub", "docker.io"); +const privateRegistry = await builder.addContainerRegistry( + "private", + "registry.company.com"); + +const publicApi = await builder.addProject("public-api", "../PublicApi/PublicApi.csproj"); +await publicApi.withContainerRegistry(publicRegistry); + +const internalApi = await builder.addProject("internal-api", "../InternalApi/InternalApi.csproj"); +await internalApi.withContainerRegistry(privateRegistry); +``` + + + +### パラメーター化されたレジストリ設定 + +環境をまたいで柔軟なデプロイが必要な場合にパラメーターを使用できます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var registryEndpoint = builder.AddParameter("registry-endpoint"); +var registryRepository = builder.AddParameter("registry-repository"); + +var registry = builder.AddContainerRegistry( + "container-registry", + registryEndpoint, + registryRepository); + +var api = builder.AddProject("api") + .WithContainerRegistry(registry); + +var worker = builder.AddProject("worker") + .WithContainerRegistry(registry); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const registryEndpoint = await builder.addParameter("registry-endpoint"); +const registryRepository = await builder.addParameter("registry-repository"); + +const registry = await builder.addContainerRegistry( + "container-registry", + registryEndpoint, + registryRepository); + +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withContainerRegistry(registry); + +const worker = await builder.addProject("worker", "../Worker/Worker.csproj"); +await worker.withContainerRegistry(registry); + +await builder.build().run(); +``` + + + +AppHost の設定でパラメーターを設定します: + +```json title="JSON — appsettings.json" +{ + "Parameters": { + "registry-endpoint": "ghcr.io", + "registry-repository": "myorg" + } +} +``` + +または、環境変数を使用して設定することもできます: + +```bash title="Bash — 環境変数" +export Parameters__registry_endpoint="ghcr.io" +export Parameters__registry_repository="myorg" +``` + +### ACR を使用した Azure デプロイ + +次のコードは、Azure Container Apps と ACR を使用した完全な AppHost の例です: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// ACR を含む Azure Container Apps 環境を作成する +var acaEnv = builder.AddAzureContainerAppEnvironment("production"); + +// Redis キャッシュを追加する +var cache = builder.AddRedis("cache"); + +// レジストリ設定付きで API を追加する +var api = builder.AddProject("api") + .WithReference(cache) + .WithContainerRegistry(acaEnv); + +// レジストリ設定付きでフロントエンドを追加する +var web = builder.AddProject("web") + .WithReference(api) + .WithContainerRegistry(acaEnv); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// ACR を含む Azure Container Apps 環境を作成する +const environment = await builder.addAzureContainerAppEnvironment("production"); + +// Redis キャッシュを追加する +const cache = await builder.addRedis("cache"); + +// レジストリ設定付きで API を追加する +const api = await builder.addProject("api", "../Api/Api.csproj"); +await api.withReference(cache); +await api.withContainerRegistry(environment); + +// レジストリ設定付きでフロントエンドを追加する +const web = await builder.addProject("web", "../Web/Web.csproj"); +await web.withReference(api); +await web.withContainerRegistry(environment); + +await builder.build().run(); +``` + + + +## 明示的な設定のメリット + +Aspire 13.1 で導入された明示的なコンテナーレジストリ設定には、次のようなメリットがあります: + +- **可視性** — イメージのプッシュ先を明確に把握できます +- **制御性** — レジストリエンドポイントと認証情報を明示的に設定できます +- **並列処理** — レジストリのプロビジョニングが他のリソースと並列で実行されます +- **早期フィードバック** — レジストリが準備でき次第イメージがプッシュされ、デプロイが高速化されます +- **柔軟性** — あらゆる Docker 互換レジストリをサポートします + + + コンテナーレジストリの改善についての詳細は、[Safia Abdalla のブログ投稿「Aspire のイメージ問題を修正する」](https://blog.safia.rocks/2025/12/15/aspire-image-push/) を参照してください。 + + +## 関連項目 + +- [Azure Container Registry 統合](/ja/integrations/cloud/azure/azure-container-registry/azure-container-registry-get-started/) +- [Azure Container Apps 環境の設定](/ja/integrations/cloud/azure/configure-container-apps/) +- [`aspire do` コマンド](/ja/reference/cli/commands/aspire-do/) +- [外部パラメーター](/ja/fundamentals/external-parameters/) +- [パイプラインとアプリトポロジー](/ja/deployment/pipelines/) diff --git a/src/frontend/src/content/docs/ja/app-host/docker-compose-to-apphost-reference.mdx b/src/frontend/src/content/docs/ja/app-host/docker-compose-to-apphost-reference.mdx new file mode 100644 index 000000000..aa2787511 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/docker-compose-to-apphost-reference.mdx @@ -0,0 +1,181 @@ +--- +title: Docker Compose から Aspire AppHost への変換 +description: Docker Compose の YAML 構文を Aspire AppHost API 呼び出しに変換するためのクイックリファレンス。 +--- + +import LearnMore from '@components/LearnMore.astro'; + +このリファレンスは、Docker Compose の YAML 構文から同等の Aspire AppHost API 呼び出しへの体系的なマッピングを提供します。既存の Docker Compose ファイルを Aspire アプリケーション ホスト構成に変換する場合のクイックリファレンスとして、これらのテーブルを使用してください。 + +## サービス定義 + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `services:` | `var builder = DistributedApplication.CreateBuilder(args)` | リソースの追加と表現に使用されるルート アプリケーション ビルダー | +| `service_name:` | `builder.Add*("service_name")` | サービス名がリソース名になります | + + +詳細については、[Docker Compose サービス](https://docs.docker.com/compose/compose-file/05-services/) をご覧ください。 + + +## イメージとビルド + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `image: nginx:latest` | `builder.AddContainer("name", "nginx", "latest")` | 直接イメージ参照 | +| `build: .` | `builder.AddDockerfile("name", ".")` | Dockerfile からビルドします | +| `build: ./path` | `builder.AddDockerfile("name", "./path")` | 特定のパスからビルドします | +| `build.context: ./app` | `builder.AddDockerfile("name", "./app")` | ビルド コンテキスト | +| `build.dockerfile: Custom.dockerfile` | `builder.Add*("name").WithDockerfile("Custom.dockerfile")` | カスタム Dockerfile 名 | +| 生成された Dockerfile | `builder.AddDockerfileBuilder("name", "./app", callback, stage: "runtime")` | AppHost コードから Dockerfile を生成します | + + +詳細については、[Docker Compose ビルド リファレンス](https://docs.docker.com/compose/compose-file/build/) および [WithDockerfile](/ja/app-host/withdockerfile/) をご覧ください。 + + +## プル ポリシー + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `pull_policy: always` | `.WithImagePullPolicy(ImagePullPolicy.Always)` | 常にイメージをプルします | +| `pull_policy: missing` | `.WithImagePullPolicy(ImagePullPolicy.Missing)` | ローカルに存在しない場合のみプルします | +| `pull_policy: never` | `.WithImagePullPolicy(ImagePullPolicy.Never)` | レジストリからプルしません | + + +詳細については、[Docker Compose pull_policy](https://docs.docker.com/reference/compose-file/services/#pull_policy) および [イメージ プル ポリシー](/ja/integrations/compute/docker/#configure-image-pull-policy) をご覧ください。 + + +## .NET プロジェクト + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `build: ./MyApi` (.NET の場合) | `builder.AddProject("myapi")` | 直接 .NET プロジェクト参照 | + + +詳細については、[.NET プロジェクトの追加](/ja/get-started/app-host/) をご覧ください。 + + +## ポート マッピング + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `ports: ["8080:80"]` | `.WithHttpEndpoint(port: 8080, targetPort: 80)` | HTTP エンドポイント マッピング。ポートはオプションです。省略した場合は動的ポートが使用されます | +| `ports: ["443:443"]` | `.WithHttpsEndpoint(port: 443, targetPort: 443)` | HTTPS エンドポイント マッピング。ポートはオプションです。省略した場合は動的ポートが使用されます | +| `expose: ["8080"]` | `.WithEndpoint(port: 8080)` | 内部ポート公開。ポートはオプションです。省略した場合は動的ポートが使用されます | + + +詳細については、[Docker Compose ポート](https://docs.docker.com/compose/compose-file/05-services/#ports) および [エンドポイント構成](/ja/fundamentals/networking-overview/) をご覧ください。 + + +## 環境変数 + +| Docker Compose | Aspire / 注記 | +|----------------|-------------| +| `environment: KEY=value` | `.WithEnvironment("KEY", "value")`
静的環境変数 | +| `environment: KEY=${HOST_VAR}` | `.WithEnvironment(context => context.EnvironmentVariables["KEY"] = hostVar)`
コールバック コンテキスト付き環境変数 | +| `environment: KEY=${PARAM}` | `.AsEnvironmentPlaceholder(resource)` inside `.PublishAsDockerComposeService(...)`
Compose 環境変数プレースホルダー | +| `env_file: .env` | `.ConfigureEnvFile(env => { ... })`
環境ファイルのカスタマイズ(13.1 以降で利用可能) | + + +詳細については、[Docker Compose 環境](https://docs.docker.com/compose/compose-file/05-services/#environment) および [外部パラメータ](/ja/fundamentals/external-parameters/) をご覧ください。 + + +## ボリュームとストレージ + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `volumes: ["data:/app/data"]` | `.WithVolume("data", "/app/data")` | 名前付きボリューム | +| `volumes: ["./host:/container"]` | `.WithBindMount("./host", "/container")` | バインド マウント | +| `volumes: ["./config:/app:ro"]` | `.WithBindMount("./config", "/app", isReadOnly: true)` | 読み取り専用バインド マウント | + + +詳細については、[Docker Compose ボリューム](https://docs.docker.com/compose/compose-file/05-services/#volumes) および [コンテナ データの永続化](/ja/fundamentals/persist-data-volumes/) をご覧ください。 + + +## 依存関係と順序付け + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `depends_on: [db]` | `.WithReference(db)` | 接続文字列インジェクション付きサービス依存関係 | +| `depends_on: db: condition: service_started` | `.WaitFor(db)` | サービス開始を待機します | +| `depends_on: db: condition: service_healthy` | `.WaitForCompletion(db)` | 正常性チェックの成功を待機します | + + +詳細については、[Docker Compose depends_on](https://docs.docker.com/compose/compose-file/05-services/#depends_on) および [起動プロファイル](/ja/integrations/dotnet/launch-profiles/) をご覧ください。 + + +## ネットワーク + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `networks: [backend]` | 自動 | Aspire がネットワークを自動的に処理します | +| Compose ネットワーク上のサービス ホスト名 | `.GetHostAddressExpression(endpoint)` | エンドポイントに対して生成された Docker Compose サービス ホスト名を生成します | +| カスタム ネットワーク | `.ConfigureComposeFile(file => { ... })` | 自動ネットワーキングが不十分な場合は、生成された Compose ファイルをカスタマイズします | + + +詳細については、[Docker Compose ネットワーク](https://docs.docker.com/compose/compose-file/05-services/#networks) および [サービス検出](/ja/fundamentals/service-discovery/) をご覧ください。 + + +## リソース制限 + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `deploy.resources.limits.memory: 512m` | サポートされていません | リソース制限は Aspire でサポートされていません | +| `deploy.resources.limits.cpus: 0.5` | サポートされていません | リソース制限は Aspire でサポートされていません | + + +詳細については、[Docker Compose デプロイ リファレンス](https://docs.docker.com/compose/compose-file/deploy/) をご覧ください。 + + +## 正常性チェック + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `healthcheck.test: ["CMD", "curl", "http://localhost/health"]` | 統合に組み込まれている | Aspire 統合には正常性チェックが含まれています | +| `healthcheck.interval: 30s` | 統合で設定可能 | 正常性チェック構成はリソースの種類によって異なります | + + +詳細については、[Docker Compose healthcheck](https://docs.docker.com/compose/compose-file/05-services/#healthcheck) および [正常性チェック](/ja/fundamentals/health-checks/) をご覧ください。 + + +## 再起動ポリシー + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `restart: unless-stopped` | `.PublishAsDockerComposeService((resource, service) => service.Restart = "unless-stopped")` | 生成された Docker Compose サービスをカスタマイズします | +| `restart: always` | `.PublishAsDockerComposeService((resource, service) => service.Restart = "always")` | 生成された Docker Compose サービスをカスタマイズします | +| `restart: no` | デフォルト | 再起動ポリシーなし | + + +詳細については、[Docker Compose 再起動](https://docs.docker.com/compose/compose-file/05-services/#restart) をご覧ください。 + + +## ログ + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `logging.driver: json-file` | 組み込み | Aspire は統合ログを提供します | +| `logging.options.max-size: 10m` | ダッシュボード構成 | Aspire ダッシュボード経由で管理されます | + + +詳細については、[Docker Compose ログ](https://docs.docker.com/compose/compose-file/05-services/#logging) および [テレメトリ](/ja/fundamentals/telemetry/) をご覧ください。 + + +## データベース サービス + +| Docker Compose | Aspire | 注記 | +|----------------|-------------|-------| +| `image: postgres:15` | `builder.AddPostgres("name")` | 自動構成を使用した PostgreSQL | +| `image: mysql:8` | `builder.AddMySql("name")` | 自動構成を使用した MySQL | +| `image: redis:7` | `builder.AddRedis("name")` | 自動構成を使用した Redis | +| `image: mongo:latest` | `builder.AddMongoDB("name")` | 自動構成を使用した MongoDB | + + +詳細については、[Docker Compose サービス](https://docs.docker.com/compose/compose-file/05-services/) および [データベース統合](/ja/integrations/gallery/?search=database) をご覧ください。 + + +## 関連項目 + +- [Docker Compose から Aspire への移行](/ja/app-host/migrate-from-docker-compose/) +- [AppHost の概要](/ja/get-started/app-host/) +- [WithDockerfile](/ja/app-host/withdockerfile/) diff --git a/src/frontend/src/content/docs/ja/app-host/eventing.mdx b/src/frontend/src/content/docs/ja/app-host/eventing.mdx new file mode 100644 index 000000000..b6de529cf --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/eventing.mdx @@ -0,0 +1,432 @@ +--- +title: AppHost イベント API +description: ライフサイクルイベント、カスタムイベントの発行、イベント駆動リソースオーケストレーションのための Aspire AppHost イベント機能の使い方を学びます。 +--- + +import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + +Aspire のイベント機能を使うと、様々な AppHost ライフサイクルでイベントを発行・購読できます。イベント機能はライフサイクルイベントより柔軟性が高く、どちらもイベントコールバック内で任意のコードを実行できますが、イベント機能はイベントのタイミング、発行、カスタムイベントのサポートをより細かく制御できます。 + +## AppHost イベント + +AppHost で利用可能なイベントは、以下の順序で発生します: + + + +1. `BeforeStartEvent`: AppHost が起動する前に発生するイベントです。 +1. `ResourceEndpointsAllocatedEvent`: エンドポイントが割り当てられた後に、リソースごとに発生するイベントです。 +1. `AfterResourcesCreatedEvent`: AppHost がリソースを作成した後に発生するイベントです。 + + + +### AppHost イベントの購読 + +組み込み AppHost イベントを購読するには、ビルダーで便利な拡張メソッドを直接使用します。これらのメソッドは同じ `IDistributedApplicationBuilder` インスタンスを返すため、メソッドチェーンで呼び出せます: + + + +```csharp title="AppHost.cs" +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +var builder = DistributedApplication.CreateBuilder(args); + +builder.OnBeforeStart(static (@event, cancellationToken) => +{ + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("BeforeStartEvent"); + return Task.CompletedTask; +}); + +builder.Build().Run(); +``` + +AppHost イベントで使用可能なビルダーレベルの拡張メソッドを以下に示します: + +| メソッド | イベント | +|--------|-------| +| `OnBeforeStart` | `BeforeStartEvent` — AppHost が起動する前に発生 | +| `OnBeforePublish` | `BeforePublishEvent` — マニフェスト発行が開始する前に発生 | +| `OnAfterPublish` | `AfterPublishEvent` — マニフェスト発行が完了した後に発生 | + +`IDistributedApplicationEventing` を介して直接購読する必要がある場合 (たとえば、`IDistributedApplicationEventingSubscriber` 内など)、低レベルの `Eventing.Subscribe()` API を使用できます: + +```csharp title="AppHost.cs" +builder.Eventing.Subscribe( + static (@event, cancellationToken) => + { + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("BeforeStartEvent"); + return Task.CompletedTask; + }); + +builder.Eventing.Subscribe( + static (@event, cancellationToken) => + { + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("AfterResourcesCreatedEvent"); + return Task.CompletedTask; + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const cache = await builder.addRedis("cache"); + +await builder.subscribeBeforeStart(async (event) => { + console.log("BeforeStartEvent"); +}); + +await builder.subscribeAfterResourcesCreated(async (event) => { + console.log("AfterResourcesCreatedEvent"); +}); + +await builder.build().run(); +``` + + + +AppHost を実行すると、Aspire ダッシュボードが表示される頃までに、コンソールに次のログ出力が表示されるはずです: + +```plaintext {2,10,12,14,16,22} data-disable-copy +info: Program[0] + 1. BeforeStartEvent +info: Aspire.Hosting.DistributedApplication[0] + Aspire version: 13.1.0 +info: Aspire.Hosting.DistributedApplication[0] + Distributed application starting. +info: Aspire.Hosting.DistributedApplication[0] + Application host directory is: ../AspireApp/AspireApp.AppHost +info: Program[0] + 2. "cache" ResourceEndpointsAllocatedEvent +info: Program[0] + 2. "apiservice" ResourceEndpointsAllocatedEvent +info: Program[0] + 2. "webfrontend" ResourceEndpointsAllocatedEvent +info: Program[0] + 2. "aspire-dashboard" ResourceEndpointsAllocatedEvent +info: Aspire.Hosting.DistributedApplication[0] + Now listening on: https://localhost:17178 +info: Aspire.Hosting.DistributedApplication[0] + Login to the dashboard at https://localhost:17178/login?t= +info: Program[0] + 3. AfterResourcesCreatedEvent +info: Aspire.Hosting.DistributedApplication[0] + Distributed application started. Press Ctrl+C to shut down. +``` + +このログ出力から、イベントハンドラーが AppHost ライフサイクルイベントの順序で実行されることが確認できます。購読の順序は実行順序に影響しません。最初に `BeforeStartEvent` が発生し、次に各リソースの `ResourceEndpointsAllocatedEvent` が続き、最後に `AfterResourcesCreatedEvent` が発生します。 + +## リソースイベント + +AppHost イベントに加えて、リソースイベントを購読することもできます。リソースイベントは個々のリソースに固有のものです。リソースイベントは `IDistributedApplicationResourceEvent` インターフェイスの実装として定義されます。以下に示す順序で利用可能なリソースイベントがあります: + + + +1. `InitializeResourceEvent`: リソースが自身を初期化するようオーケストレーターからシグナルを送るために発生します。 +1. `ResourceEndpointsAllocatedEvent`: オーケストレーターがリソースのエンドポイントを割り当てたときに発生します。 +1. `ConnectionStringAvailableEvent`: リソースの接続文字列が利用可能になったときに発生します。 +1. `BeforeResourceStartedEvent`: オーケストレーターが新しいリソースを起動する前に発生します。 +1. `ResourceReadyEvent`: リソースが最初に準備完了状態に移行したときに発生します。 + + + +### リソースイベントの購読 + +リソースイベントを購読するには、便利な拡張メソッド (`On*`) を使用します。分散アプリケーションビルダーインスタンスとリソースビルダーを取得したら、そのインスタンスから目的の `On*` イベント API を呼び出してください。次のサンプル _AppHost.cs_ ファイルを参照してください: + +```csharp title="AppHost.cs" +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +var builder = DistributedApplication.CreateBuilder(args); + +var cache = builder.AddRedis("cache"); + +cache.OnResourceReady(static (resource, @event, cancellationToken) => + { + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("5. OnResourceReady"); + + return Task.CompletedTask; + }); + +cache.OnInitializeResource( + static (resource, @event, cancellationToken) => + { + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("1. OnInitializeResource"); + + return Task.CompletedTask; + }); + +cache.OnBeforeResourceStarted( + static (resource, @event, cancellationToken) => + { + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("4. OnBeforeResourceStarted"); + + + return Task.CompletedTask; + }); + +cache.OnResourceEndpointsAllocated( + static (resource, @event, cancellationToken) => + { + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("2. OnResourceEndpointsAllocated"); + + return Task.CompletedTask; + }); + +cache.OnConnectionStringAvailable( + static (resource, @event, cancellationToken) => + { + var logger = @event.Services.GetRequiredService>(); + logger.LogInformation("3. OnConnectionStringAvailable"); + + return Task.CompletedTask; + }); + +var apiService = builder.AddProject("apiservice"); + +builder.AddProject("webfrontend") + .WithExternalHttpEndpoints() + .WithReference(cache) + .WaitFor(cache) + .WithReference(apiService) + .WaitFor(apiService); + +builder.Build().Run(); +``` + +上記のコードは、`cache` リソースの `InitializeResourceEvent`、`ResourceReadyEvent`、`ResourceEndpointsAllocatedEvent`、`ConnectionStringAvailableEvent`、`BeforeResourceStartedEvent` イベントを購読しています。`AddRedis` を呼び出すと、`T` が `RedisResource` である `IResourceBuilder` が返されます。`On*` メソッドを呼び出してイベントを購読します。`On*` メソッドは同じ `IResourceBuilder` インスタンスを返すため、複数の呼び出しをチェーンできます: + +- `OnInitializeResource`: `InitializeResourceEvent` を購読します。 +- `OnResourceEndpointsAllocated`: `ResourceEndpointsAllocatedEvent` イベントを購読します。 +- `OnConnectionStringAvailable`: `ConnectionStringAvailableEvent` イベントを購読します。 +- `OnBeforeResourceStarted`: `BeforeResourceStartedEvent` イベントを購読します。 +- `OnResourceReady`: `ResourceReadyEvent` イベントを購読します。 + +AppHost を実行すると、Aspire ダッシュボードが表示される頃までに、コンソールに次のログ出力が表示されるはずです: + +```plaintext {8,10,12,14,20} data-disable-copy +info: Aspire.Hosting.DistributedApplication[0] + Aspire version: 13.1.0 +info: Aspire.Hosting.DistributedApplication[0] + Distributed application starting. +info: Aspire.Hosting.DistributedApplication[0] + Application host directory is: ../AspireApp/AspireApp.AppHost +info: Program[0] + 1. OnInitializeResource +info: Program[0] + 2. OnResourceEndpointsAllocated +info: Program[0] + 3. OnConnectionStringAvailable +info: Program[0] + 4. OnBeforeResourceStarted +info: Aspire.Hosting.DistributedApplication[0] + Now listening on: https://localhost:17222 +info: Aspire.Hosting.DistributedApplication[0] + Login to the dashboard at https://localhost:17222/login?t= +info: Program[0] + 5. OnResourceReady +info: Aspire.Hosting.DistributedApplication[0] + Distributed application started. Press Ctrl+C to shut down. +``` + + + +## イベントの発行 + +組み込みイベントを購読する場合、AppHost オーケストレーターが代わりに組み込みイベントを発行するため、自分でイベントを発行する必要はありません。ただし、イベント API を使用してカスタムイベントを発行することもできます。イベントを発行するには、まず `IDistributedApplicationEvent` または `IDistributedApplicationResourceEvent` インターフェイスの実装としてイベントを定義する必要があります。イベントがグローバルな AppHost イベントかリソース固有のイベントかに基づいて、実装するインターフェイスを決定します。 + +次に、以下の API のいずれかを呼び出してイベントを購読および発行できます: + +- `PublishAsync(T, CancellationToken)`: 特定のイベント型のすべての購読者にイベントを発行します。 +- `PublishAsync(T, EventDispatchBehavior, CancellationToken)`: 指定されたディスパッチ動作で、特定のイベント型のすべての購読者にイベントを発行します。 + +### `EventDispatchBehavior` の指定 + +イベントがディスパッチされる際、購読者へのディスパッチ方法を制御できます。イベントディスパッチ動作は `EventDispatchBehavior` 列挙型で指定します。以下の動作が利用可能です: + +- `EventDispatchBehavior.BlockingSequential`: イベントを順次発生させ、すべて処理されるまでブロックします。 +- `EventDispatchBehavior.BlockingConcurrent`: イベントを並行して発生させ、すべて処理されるまでブロックします。 +- `EventDispatchBehavior.NonBlockingSequential`: イベントを順次発生させますが、ブロックしません。 +- `EventDispatchBehavior.NonBlockingConcurrent`: イベントを並行して発生させますが、ブロックしません。 + +デフォルトの動作は `EventDispatchBehavior.BlockingSequential` です。この動作をオーバーライドするには、`PublishAsync` などの発行 API を呼び出す際に目的の動作を引数として渡します。 + +## イベントサブスクライバー + +拡張ライブラリなど、Aspire アプリケーションモデルから直接ではなく、サービスからライフサイクルイベントにアクセスする必要がある場合があります。`IDistributedApplicationEventingSubscriber` を実装し、`AddEventingSubscriber` (または重複登録を避けたい場合は `TryAddEventingSubscriber`) を使用してサービスを登録できます。 + +```csharp title="AppHost.cs" +using Aspire.Hosting.Eventing; +using Aspire.Hosting.Lifecycle; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +var builder = DistributedApplication.CreateBuilder(args); + +builder.Services.AddEventingSubscriber(); + +builder.Build().Run(); + +internal sealed class LifecycleLoggerSubscriber(ILogger logger) + : IDistributedApplicationEventingSubscriber +{ + public Task SubscribeAsync( + IDistributedApplicationEventing eventing, + DistributedApplicationExecutionContext executionContext, + CancellationToken cancellationToken) + { + eventing.Subscribe((@event, ct) => + { + logger.LogInformation("1. BeforeStartEvent"); + return Task.CompletedTask; + }); + + eventing.Subscribe((@event, ct) => + { + logger.LogInformation("2. {Resource} ResourceEndpointsAllocatedEvent", @event.Resource.Name); + return Task.CompletedTask; + }); + + eventing.Subscribe((@event, ct) => + { + logger.LogInformation("3. AfterResourcesCreatedEvent"); + return Task.CompletedTask; + }); + + return Task.CompletedTask; + } +} +``` + +このサブスクライバーアプローチにより、ビルダーのコードを最小限に保ちながら、インライン購読と同じライフサイクルの瞬間に応答できます: + +- `AddEventingSubscriber()` (または `TryAddEventingSubscriber()`) により、AppHost が起動するたびにサブスクライバーが参加することが保証されます。 +- `SubscribeAsync` は AppHost の実行ごとに 1 回呼び出され、`IDistributedApplicationEventing` と `DistributedApplicationExecutionContext` へのアクセスが提供されます (モデルまたは環境固有のデータが必要な場合に使用できます)。 +- 任意の組み込みイベント (AppHost またはリソース) や独自のカスタム `IDistributedApplicationEvent` 型のハンドラーを登録できます。 + +`IDistributedApplicationLifecycleHook` に以前依存していた場合は、このパターンを使用してください。ライフサイクルフック API は後方互換性のためにのみ残されており、将来のリリースで削除される予定です。 + +### ライフサイクルフックからの移行 + +非推奨の `IDistributedApplicationLifecycleHook` インターフェイスから移行する場合は、以下のマッピングを使用してください: + +| 旧パターン (非推奨) | 新パターン | +|--------------------------|-------------| +| `BeforeStartAsync()` | `BeforeStartEvent` を購読 | +| `AfterEndpointsAllocatedAsync()` | `ResourceEndpointsAllocatedEvent` を購読 | +| `AfterResourcesCreatedAsync()` | `AfterResourcesCreatedEvent` を購読 | +| `TryAddLifecycleHook()` | `TryAddEventingSubscriber()` | + +**移行前 (非推奨):** + +```csharp title="OldLifecycleHook.cs" +public class MyHook : IDistributedApplicationLifecycleHook +{ + public Task AfterResourcesCreatedAsync( + DistributedApplicationModel model, + CancellationToken cancellationToken) + { + // イベントを処理する + return Task.CompletedTask; + } +} + +// 登録 +builder.Services.TryAddLifecycleHook(); +``` + +**移行後 (推奨):** + +```csharp title="NewEventingSubscriber.cs" +public class MySubscriber : IDistributedApplicationEventingSubscriber +{ + public Task SubscribeAsync( + IDistributedApplicationEventing eventing, + DistributedApplicationExecutionContext context, + CancellationToken cancellationToken) + { + eventing.Subscribe((@event, ct) => + { + // context.Model を使用してイベントを処理する + return Task.CompletedTask; + }); + + return Task.CompletedTask; + } +} + +// 登録 +builder.Services.TryAddEventingSubscriber(); +``` + + + +## その他のイベント + +コアのライフサイクルイベント以外に、Aspire は特定のシナリオ向けに追加のイベントを提供しています: + +### 発行イベント + +アプリケーションの発行 (デプロイメントマニフェストの生成) 時に、次のイベントが発生します: + +| イベント | 発生時 | 目的 | +|-------|-------------|---------| +| `BeforePublishEvent` | 発行開始前 | マニフェスト生成前にリソースを検証または変更する | +| `AfterPublishEvent` | 発行完了後 | クリーンアップや発行後のアクションを実行する | + +```csharp title="AppHost.cs" +builder.OnBeforePublish((@event, ct) => +{ + // 発行前にリソースを検証する + return Task.CompletedTask; +}); + +builder.OnAfterPublish((@event, ct) => +{ + // 発行後のアクション + return Task.CompletedTask; +}); +``` + + +発行中に何が起こるかの詳細については、[発行とデプロイの概要](/ja/deployment/overview/)を参照してください。 + + +### リソース停止イベント + +`ResourceStoppedEvent` は、リソースの実行が停止したときに発生します: + +```csharp title="AppHost.cs" +builder.Eventing.Subscribe( + cache, + (@event, ct) => + { + logger.LogInformation("Resource {Name} stopped", @event.Resource.Name); + return Task.CompletedTask; + }); +``` + + + +## 関連項目 + +- [カスタムリソース](/ja/extensibility/custom-resources/) +- [リソースアノテーション](/ja/fundamentals/annotations-overview/) diff --git a/src/frontend/src/content/docs/ja/app-host/executable-resources.mdx b/src/frontend/src/content/docs/ja/app-host/executable-resources.mdx new file mode 100644 index 000000000..e2f871d2b --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/executable-resources.mdx @@ -0,0 +1,355 @@ +--- +title: Aspire で外部実行可能ファイルをホストする +description: AddExecutable を使用して Aspire AppHost で外部の実行可能アプリケーションをホストする方法を学びます。 +--- + +import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; + +Aspire では、`AddExecutable` メソッドを使用して、プロジェクトと一緒に外部の実行可能アプリケーションをホストできます。この機能は、Node.js アプリケーション、Python スクリプト、特殊な CLI ツールなどの実行可能アプリケーションやツールを分散アプリケーションに統合する必要がある場合に役立ちます。 + +## 実行可能リソースを使用する場合 + +実行可能リソースは、次のような場合に使用します: + +- コンテナーではなくホスト上でアプリケーションやツールを直接実行する。 +- コマンドライン ツールやユーティリティをアプリケーションに統合する。 +- 他のリソースが依存する外部プロセスを実行する。 +- ローカル開発サーバーを提供するツールを使って開発する。 + +一般的な例は次のとおりです: + +- **フロントエンド開発サーバー**: [Vercel CLI](https://vercel.com/docs/cli) や webpack dev server のようなツール。 +- **言語固有のアプリケーション**: Node.js アプリ、Python スクリプト、Go アプリケーション。 +- **データベース ツール**: マイグレーション ユーティリティやデータベース シーダー。 +- **ビルド ツール**: アセット プロセッサーやコード ジェネレーター。 + +## 基本的な使用方法 + +`AddExecutable` メソッドでは、リソース名、実行可能ファイルのパス、そして必要に応じてコマンドライン引数と作業ディレクトリが必要です: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// 引数なしの基本的な実行可能ファイル +var nodeApp = builder.AddExecutable("frontend", "node", ".", "server.js"); + +// コマンドライン引数付きの実行可能ファイル +var pythonApp = builder.AddExecutable( + "api", "python", ".", "-m", "uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// 引数なしの基本的な実行可能ファイル +const nodeApp = await builder.addExecutable("frontend", "node", ".", ["server.js"]); + +// コマンドライン引数付きの実行可能ファイル +const pythonApp = await builder.addExecutable("api", "python", ".", ["-m", "uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"]); + +await builder.build().run(); +``` + + + +このコードは、基本的な実行可能リソースの設定方法を示しています。最初の例は Node.js サーバー スクリプトを実行し、2 つ目の例は特定の構成オプションを `AddExecutable` メソッドに引数として直接渡して、Uvicorn を使用する Python アプリケーションを起動します。 + +## リソース依存関係と環境構成 + +コマンドライン引数は `AddExecutable` 呼び出しで直接指定でき、リソース依存関係の環境変数も構成できます。実行可能リソースは他のリソースを参照し、その接続情報にアクセスできます。 + +### AddExecutable 呼び出しで引数を指定する + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// 引数を AddExecutable で直接指定します +var app = builder.AddExecutable( + "vercel-dev", "vercel", ".", "dev", "--listen", "3000"); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// 引数を addExecutable で直接指定します +const app = await builder.addExecutable("vercel-dev", "vercel", ".", ["dev", "--listen", "3000"]); +``` + + + +### 環境変数を使ったリソース依存関係 + +他のリソースに依存する引数には、環境変数を使用します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var redis = builder.AddRedis("cache"); +var postgres = builder.AddPostgres("postgres").AddDatabase("appdb"); + +var app = builder.AddExecutable("worker", "python", ".", "worker.py") + .WithReference(redis) // ConnectionStrings__cache を提供します + .WithReference(postgres); // ConnectionStrings__appdb を提供します +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const redis = await builder.addRedis("cache"); +const postgres = (await builder.addPostgres("postgres")).addDatabase("appdb"); + +const app = await builder.addExecutable("worker", "python", ".", ["worker.py"]) + .withReference(redis) // ConnectionStrings__cache を提供します + .withReference(postgres); // ConnectionStrings__appdb を提供します +``` + + + +1 つのリソースが別のリソースに依存している場合、`WithReference` は依存先リソースの接続詳細を含む環境変数を渡します。たとえば、`worker` 実行可能ファイルが `redis` と `postgres` を参照すると、これらのリソースへの接続文字列を含む `ConnectionStrings__cache` および `ConnectionStrings__appdb` 環境変数が提供されます。 + +### 特定のエンドポイント情報にアクセスする + +実行可能ファイルに接続情報を渡す方法をさらに細かく制御するには、次のようにします: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var redis = builder.AddRedis("cache"); + +var app = builder.AddExecutable("app", "node", ".", "app.js") + .WithReference(redis) + .WithEnvironment(context => + { + // 個別の接続詳細を提供します + context.EnvironmentVariables["REDIS_HOST"] = redis.Resource.PrimaryEndpoint.Property(EndpointProperty.Host); + context.EnvironmentVariables["REDIS_PORT"] = redis.Resource.PrimaryEndpoint.Property(EndpointProperty.Port); + }); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder, EndpointProperty } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const redis = await builder.addRedis("cache"); +const redisEndpoint = await redis.getEndpoint("tcp"); +const redisHost = await redisEndpoint.property(EndpointProperty.Host); +const redisPort = await redisEndpoint.property(EndpointProperty.Port); + +const app = await builder.addExecutable("app", "node", ".", ["app.js"]) + .withReference(redis) + .withEnvironment("REDIS_HOST", redisHost) + .withEnvironment("REDIS_PORT", redisPort); +``` + + + +## 実践例: Vercel CLI + +次は、[Vercel CLI](https://vercel.com/docs/cli) を使用して、バックエンド API とともにフロントエンド アプリケーションをホストする完全な例です: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// バックエンド API +var api = builder.AddProject("api") + .WithExternalHttpEndpoints(); + +// Vercel CLI を使用するフロントエンド +var frontend = builder.AddExecutable( + "vercel-dev", "vercel", ".", "dev", "--listen", "3000") + .WithEnvironment("API_URL", api.GetEndpoint("http")) + .WithHttpEndpoint(port: 3000, name: "http"); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// バックエンド API +const api = await builder.addProject("api", "./Api/Api.csproj", "https") + .withExternalHttpEndpoints(); + +// Vercel CLI を使用するフロントエンド +const frontend = await builder.addExecutable("vercel-dev", "vercel", ".", ["dev", "--listen", "3000"]) + .withEnvironment("API_URL", api.getEndpoint("http")) + .withHttpEndpoint({ port: 3000, name: "http" }); + +await builder.build().run(); +``` + + + +## エンドポイントを構成する + +実行可能リソースは、他のリソースが参照できる HTTP エンドポイントを公開できます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var frontend = builder.AddExecutable( + "webpack-dev", "npx", ".", "webpack", "serve", "--port", "8080", "--host", "0.0.0.0") + .WithHttpEndpoint(port: 8080, name: "http"); + +// 別のサービスがフロントエンドを参照できます +var e2eTests = builder.AddExecutable("playwright", "npx", ".", "playwright", "test") + .WithEnvironment("BASE_URL", frontend.GetEndpoint("http")); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const frontend = await builder.addExecutable("webpack-dev", "npx", ".", ["webpack", "serve", "--port", "8080", "--host", "0.0.0.0"]) + .withHttpEndpoint({ port: 8080, name: "http" }); + +// 別のサービスがフロントエンドを参照できます +const e2eTests = await builder.addExecutable("playwright", "npx", ".", ["playwright", "test"]) + .withEnvironment("BASE_URL", frontend.getEndpoint("http")); +``` + + + +## 環境構成 + +実行可能ファイルの環境変数を構成します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var app = builder.AddExecutable( + "api", "uvicorn", ".", "main:app", "--reload", "--host", "0.0.0.0") + .WithEnvironment("DEBUG", "true") + .WithEnvironment("LOG_LEVEL", "info") + .WithEnvironment(context => + { + // 動的な環境変数 + context.EnvironmentVariables["START_TIME"] = DateTimeOffset.UtcNow.ToString(); + }); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const app = await builder.addExecutable("api", "uvicorn", ".", ["main:app", "--reload", "--host", "0.0.0.0"]) + .withEnvironment("DEBUG", "true") + .withEnvironment("LOG_LEVEL", "info") + .withEnvironment("START_TIME", new Date().toISOString()); +``` + + + +## PublishAsDockerFile を使った発行 + +本番環境へデプロイするには、実行可能リソースをコンテナー化する必要があります。実行可能ファイルをどのようにパッケージ化するかを指定するには、`PublishAsDockerFile` メソッドを使用します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var app = builder.AddExecutable( + "frontend", "npm", ".", "start", "--port", "3000") + .PublishAsDockerFile(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const app = await builder.addExecutable("frontend", "npm", ".", ["start", "--port", "3000"]) + .publishAsDockerFile(); +``` + + + +`PublishAsDockerFile()` を呼び出すと、Aspire は発行プロセス中に Dockerfile を生成します。独自の Dockerfile を指定して、この動作をカスタマイズすることもできます: + +### 発行用のカスタム Dockerfile + +実行可能ファイルの作業ディレクトリに `Dockerfile` を作成します: + +```dockerfile title="Dockerfile" +FROM node:22-alpine +WORKDIR /app +COPY package*.json ./ +RUN npm ci --only=production +COPY . . +EXPOSE 3000 +CMD ["npm", "start"] +``` + +次に、AppHost でそれを参照します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var app = builder.AddExecutable("frontend", "npm", ".", "start") + .PublishAsDockerFile([new DockerfileBuildArg("NODE_ENV", "production")]); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const app = await builder.addExecutable("frontend", "npm", ".", ["start"]) + .publishAsDockerFile(); +``` + + + +## ベスト プラクティス + +実行可能リソースを扱う際は、次の点を意識してください: + + + +1. **明示的なパスを使用する**: 信頼性を高めるため、可能な場合は実行可能ファイルへの完全パスを使用します。 +1. **依存関係を処理する**: `WithReference` を使用して適切な依存関係を確立します。 +1. **明示的な開始を構成する**: 自動的に開始すべきでない実行可能ファイルには `WithExplicitStart()` を使用します。 +1. **デプロイに備える**: 本番シナリオでは常に `PublishAsDockerFile()` を使用します。 +1. **環境を分離する**: 機密な構成にはコマンドライン引数ではなく環境変数を使用します。 +1. **リソース名を工夫する**: 実行可能ファイルの目的が明確に分かる説明的な名前を使用します。 + + diff --git a/src/frontend/src/content/docs/ja/app-host/hot-reload-and-watch.mdx b/src/frontend/src/content/docs/ja/app-host/hot-reload-and-watch.mdx new file mode 100644 index 000000000..715b73ba0 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/hot-reload-and-watch.mdx @@ -0,0 +1,193 @@ +--- +title: Hot Reload と watch +description: Aspire で hot reload がどのように機能するかを学びます。 +--- + +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import { Kbd } from 'starlight-kbd/components'; + +Aspire には、watch の動作に 2 つのレベルがあります: + +1. **AppHost watch** - AppHost 自体を監視し、アプリケーション モデルの変更によって AppHost 管理アプリケーションを再起動します。 +2. **リソース watch と hot reload** - 各リソースを支えるアプリケーションまたはフレームワークに依存します。 + +Aspire の CLI における watch サポートは AppHost を中心としています。Aspire は C# と TypeScript の 2 つの AppHost 言語をサポートしており、`defaultWatchEnabled` は、使用する AppHost 言語にかかわらず AppHost 管理アプリケーションに適用されます。 + +watch モードが有効な場合、Aspire は AppHost 管理アプリケーションのファイル監視ループを管理します。ファイル変更が発生すると、更新された AppHost モデルとリソースを適用するために、Aspire がアプリケーション トポロジを再起動します。 + +AppHost の変更に対して hot reload のような動作を求める場合、Aspire の watch モードが推奨される CLI ワークフローです。これは再起動ベースです: すべてのリソース プロセス内でランタイム固有の hot reload セマンティクスを適用するのではなく、変更後に Aspire が AppHost 管理アプリケーションを再起動します。 + +## Aspire の既定の動作 + +既定では、`aspire run` と `aspire start` は Aspire アプリケーションを 1 回起動します。AppHost やリソースのソース ファイルは監視しません。 + +AppHost コードを変更したら、Aspire アプリケーションを手動で再起動します: + +- `aspire run` の場合は、 でプロセスを停止し、再度 `aspire run` を実行します。 +- `aspire start` の場合は、再度 `aspire start` を実行します。このコマンドは前のデタッチ済みインスタンスを停止し、新しいインスタンスを開始します。 + +## 既定の watch モードを有効化する + +Aspire には、オプトインの `defaultWatchEnabled` 機能フラグがあります。有効にすると、Aspire は既定で watch モードを使用し、サポートされている AppHost またはリソース ファイルの変更後に Aspire アプリケーションを自動的に再起動します: + +```bash title="Aspire CLI" +aspire config set features.defaultWatchEnabled true +``` + +マシン上のすべての Aspire プロジェクトで watch モードを有効にするには、値をグローバルに設定します: + +```bash title="Aspire CLI" +aspire config set features.defaultWatchEnabled true --global +``` + +現在の値と利用可能な機能フラグを確認するには、次を実行します: + +```bash title="Aspire CLI" +aspire config list --all +``` + +watch モードは、AppHost の変更後に AppHost 管理アプリケーションを Aspire に再起動させたい場合に有用です。C# と TypeScript の両方の AppHost をサポートし、再起動ベースのワークフローであり、ランタイム固有または IDE 固有の hot reload と同じ体験ではありません。 + +## AppHost 言語ごとのガイダンス + + + + +C# の AppHost では、`defaultWatchEnabled` が AppHost プロジェクトを監視します。AppHost コードが変更されると、更新されたモデルを適用するために Aspire が AppHost 管理アプリケーションを再起動します。 + +現在は、C# プロジェクト リソースもこの設定によって制御されます。つまり、C# プロジェクト リソースの変更でも、Aspire による AppHost 管理アプリケーションの再起動がトリガーされる可能性があります。 + +このワークフローは、次の変更に影響する場合に使用します: + +- `AppHost.cs` 内の AppHost モデル。 +- AppHost の一部である C# プロジェクト リソース。 +- リソース構成、エンドポイント、パラメーター、または統合セットアップ。 +- Aspire のオーケストレーション配下で一緒に再起動する必要がある複数のサービス。 + +```bash title="Aspire CLI" +aspire config set features.defaultWatchEnabled true +aspire run +``` + + + + +TypeScript の AppHost では、`defaultWatchEnabled` が AppHost を監視します。AppHost コードが変更されると、更新されたモデルを適用するために Aspire が AppHost 管理アプリケーションを再起動します。 + +TypeScript の AppHost watch は、アプリケーション内のすべてのリソースに対して自動的に hot reload を提供するわけではありません。個々のリソース内の変更には、リソース固有の watch、reload、restart、または rebuild ワークフローを使用してください。 + +このワークフローは、次の変更に影響する場合に使用します: + +- `apphost.ts` 内の AppHost モデル。 +- リソース構成、エンドポイント、パラメーター、または統合セットアップ。 +- Aspire のオーケストレーション配下で一緒に再起動する必要がある複数のサービス。 + +```bash title="Aspire CLI" +aspire config set features.defaultWatchEnabled true +aspire run +``` + + + + +## Aspire リソースの hot reload + +AppHost watch とリソースの hot reload は別の関心事です。AppHost はアプリケーション トポロジを記述して起動しますが、各リソースはそれぞれ独自の開発ループを持つフレームワークまたはランタイムに支えられています。 + +一般には、個々のリソースを作業している間は AppHost を実行したままにします。1 つのリソースが変更されたという理由だけで AppHost を停止して再起動しないでください。リソースの再起動または再ビルドが必要な場合は、Aspire CLI または Aspire Dashboard からそのリソース個別に実行します。 + +CLI から個々のリソースを制御するには、`aspire resource` コマンドを使います: + +```bash title="Aspire CLI" +aspire resource stop +aspire resource start +``` + +C# プロジェクト リソースでは、プロジェクトの再ビルドが必要なときに個々のリソースを再ビルドします: + +```bash title="Aspire CLI" +aspire resource rebuild +``` + + + + +`dotnet watch` は C# の Aspire AppHost をネイティブにサポートし、アプリケーション内の .NET プロジェクトを推移的に監視します: + +- AppHost への変更は AppHost を再起動します。 +- 個々の .NET プロジェクト、またはその依存関係への変更は、そのプロジェクトを再起動します。 +- Rude edit はアプリケーションを再起動します。 + +AppHost とその C# プロジェクトに対して .NET SDK の watch ループを使いたい場合は、AppHost プロジェクトに対して `dotnet watch` を実行します: + +```bash title=".NET CLI" +dotnet watch --project './src/MyApp.AppHost/MyApp.AppHost.csproj' +``` + +:::note[Important] +この体験には、現時点でいくつかの癖があります。変更が適用されても明示的な再起動が必要になる場合があり、それが起きたかどうかを常に判断しやすいとは限りません。期待した変更が反映されない場合は、`aspire resource stop` と `aspire resource start` でリソースを再起動するか、`aspire resource rebuild` で C# プロジェクト リソースを再ビルドしてください。 +::: + +代わりに Aspire の watch モードを使用する場合、C# プロジェクト リソースは現在特別です: `defaultWatchEnabled` が C# の AppHost と C# プロジェクト リソースの両方を制御します。 + + + + +Vite リソースは Vite の開発サーバー動作を使用します。Vite はフロントエンド アプリケーションに対してブラウザー更新や Hot Module Replacement を提供できますが、その動作は AppHost watch とは別です。 + +変更が AppHost モデルに影響する場合は Aspire watch を使用してください。変更がフロントエンド アプリケーションに影響し、Vite のブラウザー更新や Hot Module Replacement の動作が必要な場合は、Vite の開発ループを使用してください。 + +Vite リソースの再起動が必要な場合は、AppHost を再起動するのではなく、Aspire CLI またはダッシュボードから Vite リソースを再起動してください。 + + + + +その他の Aspire リソースは、そのリソースを支えるランタイムまたはフレームワークの watch、reload、または restart の動作に従います。たとえば、コンテナー リソース、実行可能ファイルリソース、またはフレームワーク固有のリソースは、hot reload をまったくサポートしない場合や、独自の watch コマンドを必要とする場合があります。 + +AppHost モデルを再評価すべき変更には Aspire watch を使用してください。リソースに対して最短のインナーループが必要な場合は、そのリソースのネイティブ開発コマンドを使用してください。リソースの再起動または再ビルドが必要な場合は、Aspire CLI またはダッシュボードからそのリソースを個別に再起動または再ビルドします。 + + + + +## 推奨ワークフロー + +編集対象に応じて次のワークフローを使用します: + +| 目的 | 推奨コマンド | +| ------------------------------------------------------- | ------------------------------------------------------------------------------------------ | +| 分散アプリ全体を 1 回実行する | `aspire run` | +| 分散アプリ全体をバックグラウンドで実行する | `aspire start` | +| CLI から C# または TypeScript の AppHost を watch する | `aspire config set features.defaultWatchEnabled true` を設定し、`aspire run` または `aspire start` を実行 | +| Aspire 経由で C# プロジェクト リソースを watch する | `aspire config set features.defaultWatchEnabled true` を設定し、`aspire run` または `aspire start` を実行 | +| 1 つのリソースを再起動する | `aspire resource stop` を実行し、その後 `aspire resource start` を実行 | +| 1 つの C# プロジェクト リソースを再ビルドする | `aspire resource rebuild` | +| 1 つのリソースにランタイム固有の hot reload ループを使う | そのリソースのネイティブな watch、reload、または開発サーバー コマンド | + +Aspire CLI は現在、AppHost 管理の分散アプリケーション全体に対して各ランタイムの hot reload セマンティクスを適用する単一の hot reload コマンドを提供していません。Aspire の既定の watch は、AppHost 変更後に AppHost 管理アプリケーションを再起動することで、両方の AppHost 言語をサポートします。現在は C# プロジェクト リソースもこの設定で制御されます。その他のリソースについては、AppHost を実行したまま、リソース固有の reload、restart、rebuild には、そのリソースのフレームワーク、ランタイム、CLI アクション、またはダッシュボード アクションを使用してください。 + +## IDE の hot reload とデバッグ + +Visual Studio、Visual Studio Code、JetBrains Rider は、それぞれ独自の hot reload とデバッグ体験を提供します。これらの IDE のいずれかで AppHost をデバッガー下で実行すると、Aspire はデバッグと IDE 管理の hot reload 動作をその IDE に委ねます。これは Aspire の CLI による restart、rebuild、watch の動作とは統合されず、重複もしません。 + +:::note[Important] +サポート対象リソースに対して IDE にデバッグや hot reload を管理させたい場合は IDE ワークフローを使用します。AppHost 管理アプリケーションとそのリソースを Aspire で restart、rebuild、watch したい場合は、Aspire CLI とダッシュボード アクションを使用します。 +::: + +### Visual Studio Code + +Visual Studio Code で AppHost を開始し、デバッガーをアタッチし、サポート対象リソースのデバッグ体験を管理したい場合は、Aspire の Visual Studio Code 拡張機能を使用します。VS Code の hot reload やフレームワーク固有の更新動作は、依然としてデバッガーまたはリソースを支えるフレームワークに属し、Aspire の restart、rebuild、watch の動作には属しません。 + +### Visual Studio + +サポート対象リソースに対して Visual Studio の組み込みデバッグと hot reload 体験を使いたい場合は、Visual Studio を使用します。Visual Studio で Aspire アプリを実行してデバッグできますが、IDE の hot reload は依然として Aspire の restart、rebuild、watch の動作とは別です。 + +### JetBrains Rider + +サポート対象リソースに対して Rider のデバッグと hot reload 体験を使いたい場合は、JetBrains Rider を使用します。Rider の IDE 管理 hot reload 動作は、Aspire の restart、rebuild、watch の動作とは別です。 + +## 関連項目 + +- [`aspire run`](/ja/reference/cli/commands/aspire-run/) +- [`aspire start`](/ja/reference/cli/commands/aspire-start/) +- [`aspire config set`](/ja/reference/cli/commands/aspire-config-set/) +- [Aspire VS Code 拡張機能](/ja/get-started/aspire-vscode-extension/) diff --git a/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx b/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx new file mode 100644 index 000000000..626b8494b --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx @@ -0,0 +1,711 @@ +--- +title: Docker Compose から Aspire への移行 +description: Docker Compose アプリケーションを Aspire に移行する方法を学び、主要な概念的違いを理解します。 +--- + +import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + +本ガイドは、Docker Compose から Aspire へのアプリケーション移行方法を理解し、主要な概念的違いを強調し、一般的な移行シナリオに対する正確で実践的な例を提供します。 + +## 違いを理解する + +Docker Compose と Aspire は一見似ているかもしれませんが、異なる目的に対応し、異なる抽象化レベルで動作します。 + +### Docker Compose 対 Aspire + +| | Docker Compose | Aspire | +|--|--|--| +| **主な目的** | コンテナオーケストレーション | 開発時のオーケストレーションとアプリケーション構成 | +| **スコープ** | コンテナ中心 | マルチリソース (.NET プロジェクト、クラウドリソース) | +| **構成** | YAML ベース | C# ベース、強く型付けされた | +| **ターゲット環境** | あらゆる Docker ランタイム | 開発およびクラウドデプロイメント | +| **サービス検知** | DNS ベースのコンテナ検知 | 環境変数による組み込みサービス検知 | +| **開発体験** | 手動でのコンテナ管理 | 統合ツーリング、ダッシュボード、テレメトリー | + +### 主要な概念的シフト + +Docker Compose から Aspire に移行する際は、以下の概念的違いを検討してください: + +- **YAML から C# へ** — 構成が宣言的 YAML から命令的で強く型付けされた C# コードに移行します +- **コンテナからリソースへ** — Aspire はコンテナだけでなく、.NET プロジェクト、実行可能ファイル、パラメーター、クラウドリソースを管理します +- **手動ネットワークから自動サービス検知へ** — Aspire は自動的にサービス検知と接続文字列を構成します +- **開発ギャップから統合体験へ** — Aspire はダッシュボード、テレメトリー、デバッグ統合を提供します +- **スタートアップオーケストレーションの違い** — Docker Compose の `depends_on` はスタートアップ順序を制御しますが、Aspire の `WithReference` はサービス検知のみを構成します。スタートアップ順序には `WaitFor` を使用してください + + +詳細な API マッピングについては、[Docker Compose to Aspire AppHost API reference](/ja/app-host/docker-compose-to-apphost-reference/) を参照してください。 + + +## 一般的な移行パターン + +このセクションでは、Docker Compose から Aspire に移行する際に遭遇する可能性のある実際の移行シナリオを示します。各パターンは、完全な Docker Compose の例とそれに対応する正確な Aspire の例を示しています。 + +### マルチサービス Web アプリケーション + +この例は、フロントエンド、API、データベースを備えた典型的な 3 層アプリケーションを示しています。 + +**Docker Compose の例:** + +```yaml title="compose.yaml" +version: '3.8' +services: + frontend: + build: ./frontend + ports: + - "3000:3000" + depends_on: + api: + condition: service_healthy + environment: + - API_URL=http://api:5000 + + api: + build: ./api + ports: + - "5000:5000" + depends_on: + database: + condition: service_healthy + environment: + - ConnectionStrings__DefaultConnection=Host=database;Database=myapp;Username=postgres;Password=secret + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5000/health"] + interval: 10s + timeout: 3s + retries: 3 + + database: + image: postgres:15 + environment: + - POSTGRES_DB=myapp + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=secret + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 3s + retries: 3 + +volumes: + postgres_data: +``` + +**Aspire 相当:** + + + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// 明示的なバージョンと永続ストレージを備えた PostgreSQL を追加 +var database = builder.AddPostgres("postgres") + .WithImageTag("15") + .WithDataVolume() + .AddDatabase("myapp"); + +// 適切な依存関係を備えた API プロジェクトを追加 +var api = builder.AddProject("api") + .WithHttpEndpoint(port: 5000) + .WithHttpHealthCheck("/health") + .WithReference(database, "DefaultConnection") + .WaitFor(database); + +// 依存関係を備えたフロントエンドプロジェクトを追加 +var frontend = builder.AddProject("frontend") + .WithHttpEndpoint(port: 3000) + .WithReference(api) + .WithEnvironment("API_URL", api.GetEndpoint("http")) + .WaitFor(api); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// 明示的なバージョンと永続ストレージを備えた PostgreSQL を追加 +const database = (await builder.addPostgres("postgres") + .withImageTag("15") + .withDataVolume()) + .addDatabase("myapp"); + +// 適切な依存関係を備えた API プロジェクトを追加 +const api = await builder.addProject("api", "./MyApp.Api/MyApp.Api.csproj", "https") + .withHttpEndpoint({ port: 5000 }) + .withHttpHealthCheck("/health") + .withReference(database, "DefaultConnection") + .waitFor(database); + +// 依存関係を備えたフロントエンドプロジェクトを追加 +const frontend = await builder.addProject("frontend", "./MyApp.Frontend/MyApp.Frontend.csproj", "https") + .withHttpEndpoint({ port: 3000 }) + .withReference(api) + .withEnvironment("API_URL", api.getEndpoint("http")) + .waitFor(api); + +await builder.build().run(); +``` + + + + + +**主な違いの説明:** + +- **Build 対 プロジェクト** — Docker Compose の `build:` サービスは .NET アプリの `AddProject()` になり、コンテナ内ではなく直接実行します +- **ポート** — どちらの例もポート (3000 と 5000) を明示的にマップします +- **スタートアップ順序** — Docker Compose は正常性チェック条件付きの `depends_on` を使用します。Aspire はスタートアップ順序に `WaitFor()` を使用します +- **サービス検知** — `WithReference()` はサービス検知と接続文字列のみを構成します。スタートアップ順序を制御しません +- **接続文字列** — デフォルトでは、`WithReference(database)` は `AddDatabase()` のリソース名を使用して `ConnectionStrings__myapp` を提供します。`DefaultConnection` などの異なる名前に一致させるには、名前付き参照を使用します: `.WithReference(database, "DefaultConnection")` +- **ボリューム** — `WithDataVolume()` は明示的に呼び出す必要があります。自動的ではありません +- **イメージバージョン** — `WithImageTag("15")` は PostgreSQL をバージョン 15 にピン止めします + +### コンテナベースのサービス + +この例は、既存のコンテナイメージと Dockerfile ビルドサービスの混在をオーケストレーションしています。 + +**Docker Compose の例:** + +```yaml title="compose.yaml" +version: '3.8' +services: + web: + build: . + ports: + - "8080:8080" + depends_on: + redis: + condition: service_started + postgres: + condition: service_healthy + environment: + - REDIS_URL=redis://redis:6379 + - DATABASE_URL=postgresql://postgres:secret@postgres:5432/main + + redis: + image: redis:7 + ports: + - "6379:6379" + + postgres: + image: postgres:15 + environment: + POSTGRES_PASSWORD: secret + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready"] + interval: 10s + +volumes: + postgres_data: +``` + +**Aspire 相当:** + + + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// 明示的なバージョンを備えたバッキングサービスを追加 +var redis = builder.AddRedis("redis") + .WithImageTag("7") + .WithHostPort(6379); + +var postgres = builder.AddPostgres("postgres") + .WithImageTag("15") + .WithDataVolume() + .AddDatabase("main"); + +// Dockerfile から Web アプリをビルド (Docker Compose の "build: ." に対応) +var web = builder.AddDockerfile("web", ".") + .WithHttpEndpoint(port: 8080, targetPort: 8080) + .WithReference(redis) + .WithReference(postgres) + .WaitFor(redis) + .WaitFor(postgres); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// 明示的なバージョンを備えたバッキングサービスを追加 +const redis = await builder.addRedis("redis") + .withImageTag("7") + .withHostPort(6379); + +const postgres = (await builder.addPostgres("postgres") + .withImageTag("15") + .withDataVolume()) + .addDatabase("main"); + +// Dockerfile から Web アプリをビルド (Docker Compose の "build: ." に対応) +const web = await builder.addDockerfile("web", ".") + .withHttpEndpoint({ port: 8080, targetPort: 8080 }) + .withReference(redis) + .withReference(postgres) + .waitFor(redis) + .waitFor(postgres); + +await builder.build().run(); +``` + + + + + +**主な違いの説明:** + +- **イメージバージョン** — `WithImageTag()` で明示的に指定して Docker Compose と一致させます +- **Dockerfile ビルド** — Docker Compose の `build: .` は `AddDockerfile("web", ".")` にマップしており、Dockerfile からコンテナイメージをビルドします。Docker Compose で `image:` を使用する事前ビルドイメージには `AddContainer()` を使用します +- **ポート** — `WithHostPort()` は静的ホストポートにマップしており、なければ Aspire がランダムポートを割り当てます +- **ボリューム** — `WithDataVolume()` は明示的に呼び出す必要があります +- **スタートアップ順序** — `WaitFor()` はスタートアップ順序を制御し、Docker Compose の `depends_on` の条件に似ています +- **接続文字列** — `WithReference()` は Aspire フォーマットの接続文字列 (`ConnectionStrings__*`) を提供しており、URL フォーマットの変数ではありません + +### 環境変数と構成 + +この例は異なる構成管理アプローチを示しています。 + +**Docker Compose アプローチ:** + +```yaml title="compose.yaml" +services: + app: + image: myapp:latest + environment: + - DATABASE_URL=postgresql://user:pass@db:5432/myapp + - REDIS_URL=redis://cache:6379 + - API_KEY=${API_KEY} + - LOG_LEVEL=info +``` + +**Aspire アプローチ:** + + + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// シークレット用の外部パラメーターを追加 +var apiKey = builder.AddParameter("apiKey", secret: true); + +var database = builder.AddPostgres("db") + .AddDatabase("myapp"); + +var cache = builder.AddRedis("cache"); + +var app = builder.AddContainer("app", "myapp", "latest") + .WithReference(database) + .WithReference(cache) + .WithEnvironment("API_KEY", apiKey) + .WithEnvironment("LOG_LEVEL", "info"); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// シークレット用の外部パラメーターを追加 +const apiKey = builder.addParameter("apiKey", { secret: true }); + +const database = (await builder.addPostgres("db")) + .addDatabase("myapp"); + +const cache = await builder.addRedis("cache"); + +const app = await builder.addContainer("app", "myapp:latest") + .withReference(database) + .withReference(cache) + .withEnvironment("API_KEY", apiKey) + .withEnvironment("LOG_LEVEL", "info"); + +await builder.build().run(); +``` + + + + + + + +```csharp title="C# — AppHost.cs" +var dbPassword = builder.AddParameter("dbPassword", secret: true); + +var db = builder.AddPostgres("db", password: dbPassword) + .AddDatabase("myapp"); + +var app = builder.AddContainer("app", "myapp", "latest") + .WithReference(db) + .WithEnvironment(context => + { + context.EnvironmentVariables["DATABASE_URL"] = + ReferenceExpression.Create( + $"postgresql://postgres:{dbPassword}@db:5432/myapp"); + context.EnvironmentVariables["REDIS_URL"] = "redis://cache:6379"; + }); +``` + + +```typescript title="apphost.ts" +const dbPassword = builder.addParameter("dbPassword", { secret: true }); + +const db = (await builder.addPostgres("db", { password: dbPassword })) + .addDatabase("myapp"); + +const app = await builder.addContainer("app", "myapp:latest") + .withReference(db) + .withEnvironment("DATABASE_URL", + builder.createReferenceExpression`postgresql://postgres:${dbPassword}@db:5432/myapp`) + .withEnvironment("REDIS_URL", "redis://cache:6379"); +``` + + + +### カスタムボリュームとバインドマウント + +**Docker Compose の例:** + +```yaml title="compose.yaml" +version: '3.8' +services: + app: + image: myapp:latest + volumes: + - app_data:/data + - ./config:/app/config:ro + + worker: + image: myworker:latest + volumes: + - app_data:/shared + +volumes: + app_data: +``` + +**Aspire 相当:** + + + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// データ共有用の名前付きボリュームを作成 +var appData = builder.AddVolume("app-data"); + +var app = builder.AddContainer("app", "myapp", "latest") + .WithVolume(appData, "/data") + .WithBindMount("./config", "/app/config", isReadOnly: true); + +var worker = builder.AddContainer("worker", "myworker", "latest") + .WithVolume(appData, "/shared"); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const app = await builder.addContainer("app", "myapp:latest") + .withVolume("/data", { name: "app-data", isReadOnly: true }) + .withBindMount("./config", "/app/config", { isReadOnly: true }); + +const worker = await builder.addContainer("worker", "myworker:latest") + .withVolume("/shared", { name: "app-data" }); + +await builder.build().run(); +``` + + + +**主な違い:** + +- **名前付きボリューム** — `AddVolume()` で作成され、コンテナ間で共有されます +- **バインドマウント** — ホストディレクトリアクセス用に `WithBindMount()` を使用します + +### ネットワーキング + +Docker Compose は、サービスのグループを相互に分離するカスタムネットワークをサポートしています: + +```yaml title="compose.yaml" +services: + proxy: + build: ./proxy + networks: + - frontend + app: + build: ./app + networks: + - frontend + - backend + db: + image: postgres + networks: + - backend + +networks: + frontend: + backend: +``` + +Aspire にはカスタムネットワーク分離に相当するものがありません。代わりに、Aspire はすべてのコンテナリソース用の共有コンテナネットワークを自動的に作成し、サービス検知を使用してサービス間通信を管理します。Aspire AppHost 内のすべてのコンテナはリソース名でお互いに到達できます。.NET プロジェクトと実行可能ファイルはホスト上で実行され、注入されたホスト/ポートエンドポイントを通じてコンテナにアクセスします。 + + + +## 移行戦略 + +Docker Compose から Aspire への正常な移行には体系的なアプローチが必要です。 + + + +1. ### 現在のセットアップを評価する + + 移行前に、Docker Compose セットアップをインベントリします: + + - **サービス** — データベース、キャッシュ、API、Web アプリケーションを含むすべてのサービスを識別します + - **依存関係** — `depends_on` 宣言からサービス依存関係をマップします + - **データ永続性** — データストレージに使用されるすべてのボリュームとバインドマウントをカタログします + - **環境変数** — すべての構成変数とシークレットをリストします + - **正常性チェック** — カスタム正常性チェックコマンドを文書化します + - **イメージバージョン** — 本番環境で使用される特定のバージョンをメモします + +2. ### Aspire AppHost を作成する + + 新しい Aspire プロジェクトを作成することから始めます: + + ```bash + aspire new aspire-starter -o MyApp + ``` + +3. ### サービスを段階的に移行する + + バッキングサービスから始めて、サービスを 1 つずつ移行します: + + - **PostgreSQL、Redis などのバッキングサービスを追加** し、`WithImageTag()` で特定のバージョンを指定します + - **`WithDataVolume()` を使用して永続ストレージを追加** します (必要な場合) + - **.NET アプリケーションを変換** して、より優れた統合のために `AddProject()` でプロジェクト参照にします + - **Dockerfile ビルドコンテナを `AddDockerfile()` で変換** して `build:` ディレクティブと一致させます + - **事前ビルドイメージを `AddContainer()` で変換** して `image:` ディレクティブと一致させます + - **`WithReference()` で依存関係を構成** してサービス検知のために + - **`WaitFor()` でスタートアップ順序を追加** して `depends_on` の動作と一致させます + - **環境変数を設定** — 接続文字列フォーマットが異なることに注意してください + - **正常性チェックを移行** — `WithHttpHealthCheck()` またはカスタムチェック用 `WithHealthCheck()` を使用します + +4. ### データ移行を処理する + + 永続データについて: + + - `WithDataVolume()` をインテグレーションで自動ボリューム管理に使用します + - `WithVolume()` をデータを永続化する必要があるという名前付きボリュームに使用します + - `WithBindMount()` をホスト直接アクセスが必要な場合のホストディレクトリマウントに使用します + +5. ### テストと検証 + + - Aspire AppHost を開始し、すべてのサービスが正しく開始することを確認します + - ダッシュボードをチェックしてサービスの健全性と接続状態を確認します + - サービス間通信が期待どおりに機能することを検証します + - **接続文字列を検証** — アプリが特定の URL フォーマットを期待する場合、環境変数を調整する必要があるかもしれません + + + +## 移行のトラブルシューティング + +### 一般的な問題と解決策 + +#### 接続文字列フォーマットの不一致 + +Aspire は URL フォーマット (`postgresql://` または `redis://`) ではなく、.NET スタイルの接続文字列 (`ConnectionStrings__*`) を生成します。 + +**解決策**: アプリケーションが特定の URL フォーマットを期待する場合は、`WithEnvironment()` を使用して手動で構築してください: + + + +```csharp title="C# — AppHost.cs" +var dbPassword = builder.AddParameter("dbPassword", secret: true); + +var postgres = builder.AddPostgres("db", password: dbPassword) + .AddDatabase("myapp"); + +var app = builder.AddContainer("app", "myapp", "latest") + .WithReference(postgres) + .WithEnvironment(context => + { + context.EnvironmentVariables["DATABASE_URL"] = + ReferenceExpression.Create( + $"postgresql://postgres:{dbPassword}@db:5432/myapp"); + }); +``` + + +```typescript title="apphost.ts" +const dbPassword = builder.addParameter("dbPassword", { secret: true }); + +const postgres = (await builder.addPostgres("db", { password: dbPassword })) + .addDatabase("myapp"); + +const app = await builder.addContainer("app", "myapp:latest") + .withReference(postgres) + .withEnvironment("DATABASE_URL", + builder.createReferenceExpression`postgresql://postgres:${dbPassword}@db:5432/myapp`); +``` + + + +#### サービススタートアップ順序の問題 + +`WithReference()` はサービス検知のみを構成し、スタートアップ順序は構成しません。 + +**解決策**: 依存関係が準備できていることを確認するために `WaitFor()` を使用してください: + + + +```csharp title="C# — AppHost.cs" +var api = builder.AddProject("api") + .WithReference(database) // サービス検知 + .WaitFor(database); // スタートアップ順序 +``` + + +```typescript title="apphost.ts" +const api = await builder.addProject("api", "./Api/Api.csproj", "https") + .withReference(database) // サービス検知 + .waitFor(database); // スタートアップ順序 +``` + + + +#### ボリュームマウントの問題 + +- バインドマウントにはパス解決の問題を回避するため絶対パスを使用してください +- ホストディレクトリが存在し、適切なアクセス許可を持つことを確認してください +- データベースインテグレーション用に `WithDataVolume()` を使用してください — これは明示的に呼び出す必要があります + +#### ポート競合 + +Aspire はデフォルトでランダムポートを自動的に割り当てます。 + +**解決策**: 静的ポートマッピングに `WithHostPort()` または `WithHttpEndpoint(port:)` を使用してください: + + + +```csharp title="C# — AppHost.cs" +var redis = builder.AddRedis("cache") + .WithHostPort(6379); +``` + + +```typescript title="apphost.ts" +const redis = await builder.addRedis("cache") + .withHostPort(6379); +``` + + + +#### 正常性チェック移行 + +Docker Compose の正常性チェックはシェルコマンドを使用します。Aspire インテグレーション (PostgreSQL および Redis など) には組み込み正常性チェックが自動的に含まれています。カスタム正常性チェックについて、Aspire はリソースタイプに応じて異なるアプローチを提供します。 + +**解決策**: HTTP エンドポイント付きリソースについて、`WithHttpHealthCheck()` を使用してください: + + + +```csharp title="C# — AppHost.cs" +var api = builder.AddProject("api") + .WithHttpHealthCheck("/health"); +``` + + +```typescript title="apphost.ts" +const api = await builder.addProject("api", "./Api/Api.csproj", "https") + .withHttpHealthCheck("/health"); +``` + + + +シェルコマンドが必要なカスタムコンテナ正常性チェック (RabbitMQ など) については、カスタム正常性チェックを登録してリソースに関連付けてください: + + + +```csharp title="C# — AppHost.cs" +builder.Services.AddHealthChecks() + .AddCheck("rabbitmq-health", () => + { + // カスタム正常性チェックロジックをここに実装してください。 + // 例えば、サービスへの TCP 接続を試みます + return HealthCheckResult.Healthy(); + }); + +var rabbit = builder.AddContainer("rabbitmq", "rabbitmq", "4.1.4-management-alpine") + .WithHealthCheck("rabbitmq-health"); + +// WaitFor は登録された正常性チェックを使用してレディネスを決定します +var app = builder.AddProject("app") + .WaitFor(rabbit); +``` + + +```typescript title="apphost.ts" +const rabbit = await builder.addContainer("rabbitmq", "rabbitmq", "4.1.4-management-alpine") + .withHealthCheck("rabbitmq-health"); + +// WaitFor は登録された正常性チェックを使用してレディネスを決定します +const app = await builder.addProject("app", "./App/App.csproj", "https") + .waitFor(rabbit); +``` + + + + + +## 次のステップ + +Aspire への移行後: + +- [Aspire インテグレーション](/ja/integrations/overview/) を探索してカスタムコンテナ構成を置き換えます +- [正常性チェック](/ja/fundamentals/health-checks/) を設定してより良い監視を実現します +- 本番環境向けの [デプロイメントオプション](/ja/deployment/overview/) について学びます +- 分散アプリケーション [テスト](/ja/testing/overview/) を検討します +- [テレメトリー構成](/ja/fundamentals/telemetry/) をレビューして可観測性を実現します diff --git a/src/frontend/src/content/docs/ja/app-host/persistent-containers.mdx b/src/frontend/src/content/docs/ja/app-host/persistent-containers.mdx new file mode 100644 index 000000000..97b52ae27 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/persistent-containers.mdx @@ -0,0 +1,191 @@ +--- +title: コンテナの永続的なライフタイム +description: Aspire AppHost の実行をまたいでコンテナを永続化し再利用する方法を学びます。 +--- + +import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; +import { Image } from 'astro:assets'; +import persistentContainer from '@assets/whats-new/aspire-9/persistent-container.png'; +import persistentContainerDocker from '@assets/whats-new/aspire-9/persistent-container-docker-desktop.png'; + +Aspire では、コンテナは典型的なライフサイクルに従い、AppHost の起動時に作成され停止時に破棄されます。ただし、この標準ライフサイクルから外れる**永続コンテナ**を使用するよう指定できます。永続コンテナは Aspire オーケストレーターによって作成・起動されますが、AppHost の停止時に破棄されず、実行をまたいで存続できます。 + +この機能は、データベースなど起動時間が長いコンテナにとって特に有益で、AppHost を再起動するたびにサービスの初期化を待つ必要がなくなります。 + + + +## 永続コンテナを設定する + +永続的なライフタイムを持つコンテナリソースを設定するには、 `WithLifetime` メソッドを使用して `ContainerLifetime.Persistent` を渡します: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddPostgres("postgres") + .WithLifetime(ContainerLifetime.Persistent) + .WithDataVolume(); + +var db = postgres.AddDatabase("inventorydb"); + +builder.AddProject("inventory") + .WithReference(db); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder, ContainerLifetime } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const postgres = await builder.addPostgres("postgres") + .withLifetime(ContainerLifetime.Persistent) + .withDataVolume(); + +const db = postgres.addDatabase("inventorydb"); + +await builder.addProject("inventory", "./InventoryService/InventoryService.csproj", "https") + .withReference(db); + +await builder.build().run(); +``` + + + +上記の例では、 PostgreSQL コンテナが AppHost の実行をまたいで永続化されるよう設定されており、 `WithDataVolume()` によりデータベースのデータがコンテナ再作成後も存続する名前付きボリュームに保存されます。 `inventory` プロジェクトは通常どおりデータベースを参照します。 + +## ダッシュボードの視覚化 + +Aspire ダッシュボードでは、永続コンテナに特徴的なピンアイコン(📌)が表示され、識別しやすくなっています: + +ピンアイコン付きの永続コンテナを表示した Aspire ダッシュボードのスクリーンショット。 + +AppHost が停止した後も、永続コンテナは動作し続け、コンテナランタイム( Docker Desktop など)で確認できます: + +AppHost が停止した後も永続 RabbitMQ コンテナが動作している様子を示す Docker Desktop のスクリーンショット。 + +## 設定変更の検知 + +永続コンテナは、 AppHost が重要な設定変更を検知した際に自動的に再作成されます。 Aspire は各コンテナの作成に使用した設定のハッシュを追跡し、その後の実行で現在の設定と比較します。設定が異なる場合、コンテナは新しい設定で再作成されます。 + +このメカニズムにより、手動での操作を必要とせず、永続コンテナが AppHost の設定と同期し続けることが保証されます。 + +## コンテナの命名と一意性 + +デフォルトでは、永続コンテナは以下を組み合わせた命名パターンを使用します: + +- AppHost で指定したサービス名。 +- AppHost プロジェクトパスのハッシュに基づくポストフィックス。 + +この命名スキームにより、永続コンテナが各 AppHost プロジェクトに固有のものとなり、複数の Aspire プロジェクトが同じサービス名を使用する際の競合を防ぎます。 + +例えば、 `/path/to/MyApp.AppHost` にある AppHost プロジェクトで `"postgres"` という名前のサービスがある場合、コンテナ名は `postgres-abc123def` のようになります。 `abc123def` はプロジェクトパスのハッシュから導出されます。 + +### カスタムコンテナ名 + +高度なシナリオでは、 `WithContainerName` メソッドを使用してカスタムコンテナ名を設定できます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddPostgres("postgres") + .WithLifetime(ContainerLifetime.Persistent) + .WithContainerName("my-shared-postgres"); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder, ContainerLifetime } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const postgres = await builder.addPostgres("postgres") + .withLifetime(ContainerLifetime.Persistent) + .withContainerName("my-shared-postgres"); + +await builder.build().run(); +``` + + + +カスタムコンテナ名を指定した場合、 Aspire はまずその名前のコンテナが既に存在するかどうかを確認します。その名前のコンテナが存在し、 Aspire によって以前に作成されたものであれば、通常の永続コンテナの動作に従い、設定が変更された際に自動的に再作成されます。その名前のコンテナが存在するが Aspire によって作成されたものでない場合、 AppHost によって管理または再作成されません。カスタム名のコンテナが存在しない場合、 Aspire が新たに作成します。 + +## 手動クリーンアップ + + + +Docker CLI コマンドを使用して永続コンテナをクリーンアップできます: + +```bash +# コンテナを停止する +docker stop my-container-name + +# コンテナを削除する +docker rm my-container-name +``` + +または、 Docker Desktop やお好みのコンテナ管理ツールを使用して永続コンテナを停止・削除することもできます。 + +## ユースケースとメリット + +永続コンテナに最適なシナリオ: + +- **データベースサービス**: PostgreSQL、SQL Server、MySQL など、初期化とデータ読み込みに時間がかかるデータベース。 +- **メッセージブローカー**: RabbitMQ、Redis など、実行をまたいで状態を保持することで恩恵を受けるサービス。 +- **開発データ**: 開発の反復中に保持したいテストデータや設定を含むコンテナ。 +- **共有サービス**: 複数の AppHost または開発チームメンバーが共有できるサービス。 + +## コンテナのライフタイムとデータの永続性 + +`ContainerLifetime.Persistent` と `WithDataVolume()` はそれぞれ異なる目的を持ち、多くの場合組み合わせて使用されます。次の表は各組み合わせの動作をまとめたものです: + +| 設定 | コンテナの動作 | データの動作 | +|---|---|---| +| なし(デフォルト) | 起動時に作成、停止時に破棄 | AppHost が停止するたびに失われる | +| `WithLifetime(ContainerLifetime.Persistent)` のみ | AppHost の実行をまたいで動作し続ける | AppHost の再起動後も存続するが、**コンテナが再作成された場合は失われる**(設定変更、プルーニング、イメージ更新) | +| `WithDataVolume()` のみ | 起動時に作成、停止時に破棄 | 名前付きボリュームに永続化—**コンテナ再作成後も存続** | +| 両方(データベースに推奨) | AppHost の実行をまたいで動作し続ける | 名前付きボリュームに永続化—コンテナ再作成後も存続 | + +**データベースやその他のステートフルなサービス**では、高速な起動(コンテナが動作し続ける)_と_データの安全性(コンテナが再作成されてもボリュームがデータを保護する)を両立するために、両方の API を組み合わせて使用してください: + + + +```csharp title="AppHost.cs" +var postgres = builder.AddPostgres("postgres") + .WithLifetime(ContainerLifetime.Persistent) + .WithDataVolume(); +``` + + +```typescript title="apphost.ts" +const postgres = await builder.addPostgres("postgres") + .withLifetime(ContainerLifetime.Persistent) + .withDataVolume(); +``` + + + +**キャッシュやその他のエフェメラルな状態**の場合、コンテナ再作成時にデータが失われても問題ないため、 `WithLifetime(ContainerLifetime.Persistent)` 単独でも十分な場合があります。 + + diff --git a/src/frontend/src/content/docs/ja/app-host/typescript-apphost.mdx b/src/frontend/src/content/docs/ja/app-host/typescript-apphost.mdx new file mode 100644 index 000000000..ae5a42504 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/typescript-apphost.mdx @@ -0,0 +1,291 @@ +--- +title: TypeScript AppHost プロジェクト構造 +description: TypeScript AppHost プロジェクトを構成するファイルと設定について学習します。 +--- + +import { Aside, FileTree, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + +`aspire new` または `aspire init --language typescript` で TypeScript AppHost を作成すると、CLI は以下の構造でプロジェクトをスキャフォルドします: + + + +- my-apphost/ + - .modules/ 生成された TypeScript SDK(編集しないでください) + - aspire.ts + - base.ts + - transport.ts + - apphost.ts AppHost エントリポイント + - aspire.config.json Aspire 設定 + - package.json + - tsconfig.json + + + +## aspire.config.json + +`aspire.config.json` ファイルは AppHost にとって中核となる設定ファイルです。古い `.aspire/settings.json` と `apphost.run.json` ファイルに代わります。 + +```json title="aspire.config.json" +{ + "appHost": { + "path": "apphost.ts", + "language": "typescript/nodejs" + }, + "packages": { + "Aspire.Hosting.JavaScript": "13.3.0" + }, + "profiles": { + "https": { + "applicationUrl": "https://localhost:17127;http://localhost:15118", + "environmentVariables": { + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21169", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22260" + } + } + } +} +``` + +### 主要セクション + +| セクション | 説明 | +|---------|-------------| +| `appHost.path` | AppHost エントリポイント(`apphost.ts`)へのパス | +| `appHost.language` | 言語ランタイム(`typescript/nodejs`) | +| `packages` | ホスティング統合パッケージとそのバージョン。`aspire add` で自動的に追加されます。 | +| `profiles` | ダッシュボード URL と環境変数を含むローンチプロファイル | + +### 統合の追加 + +`aspire add` を実行すると、CLI はパッケージを `packages` セクションに追加し、TypeScript SDK を再生成します: + +```bash title="統合の追加" +aspire add redis +``` + +これにより `aspire.config.json` が更新されます: + +```json title="aspire.config.json" ins={4} +{ + "packages": { + "Aspire.Hosting.JavaScript": "13.3.0", + "Aspire.Hosting.Redis": "13.3.0" + } +} +``` + +### ローカル開発用のプロジェクト参照 + +バージョンの代わりに `.csproj` パスを使用することで、ローカルホスティング統合プロジェクトを参照できます: + +```json title="aspire.config.json" +{ + "packages": { + "MyIntegration": "../src/MyIntegration/MyIntegration.csproj" + } +} +``` + + + 詳細については、[マルチ言語統合](/ja/extensibility/multi-language-integration-authoring/)を参照してください。 + + +## .modules/ ディレクトリ + +`.modules/` ディレクトリには、生成された TypeScript SDK が含まれます。Aspire CLI によって自動的に作成および更新されます。**これらのファイルは編集しないでください**。 + +| ファイル | 目的 | +|------|---------| +| `aspire.ts` | インストール済みのすべての統合用に生成された型付け API | +| `base.ts` | 基本型とハンドルインフラストラクチャ | +| `transport.ts` | JSON-RPC トランスポート層 | + +SDK は以下の場合に再生成されます: + +- `aspire add` を実行して統合を追加または更新した場合 +- `aspire run` または `aspire start` を実行し、パッケージリストが変更されている場合 +- `aspire restore` を実行して手動で再生成した場合 + +`apphost.ts` はこの SDK からインポートします: + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; +``` + + + +## apphost.ts + +AppHost のエントリポイント。ここでアプリケーションのリソースとそれらの関係を定義します: + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const cache = await builder.addRedis("cache"); + +const api = await builder + .addNodeApp("api", "./api", "src/index.ts") + .withHttpEndpoint({ env: "PORT" }) + .withReference(cache); + +await builder.build().run(); +``` + +## パッケージマネージャー + +Aspire CLI はロックファイルと `package.json` の `packageManager` フィールドを調べることで、TypeScript AppHost が使用するパッケージマネージャーを自動的に検出します。以下のパッケージマネージャーがサポートされています: + +| パッケージマネージャー | 検出されるロックファイル | 注 | +|---|---|---| +| npm | `package-lock.json` | デフォルト。追加のセットアップは不要です | +| pnpm | `pnpm-lock.yaml` | | +| Yarn (v4+) | `yarn.lock` | Yarn 4 以降(Berry)である必要があります | +| Bun | `bun.lock` / `bun.lockb` | | + + + +## package.json + +スキャフォルドされた `package.json` は便利なスクリプトと必要な Node.js バージョンを含みます: + +```json title="package.json" +{ + "name": "my-apphost", + "private": true, + "type": "module", + "scripts": { + "dev": "aspire run", + "build": "tsc", + "lint": "eslint apphost.ts" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } +} +``` + +`dev` スクリプトは `npm run dev` で AppHost を起動することもできます(または、ツールチェーンと同等のもの、例えば `bun run dev` または `pnpm run dev`)。 + +## パッケージマネージャー ツールチェーン + +Aspire CLI はプロジェクトが使用する Node 互換パッケージマネージャーを自動的に検出し、インストール コマンドと実行コマンドを調整します。以下のツールチェーンがサポートされています:**npm**(デフォルト)、**Bun**、**Yarn**、および **pnpm**。 + +### ツールチェーン検出 + +CLI は AppHost ディレクトリと親ディレクトリ(最大 8 レベル)を検査してツールチェーンを解決します。以下の順序で確認します: + + + +1. `package.json` の `packageManager` フィールド(例:`"packageManager": "pnpm@9.0.0"`)。 +2. ロックファイル:`bun.lock` または `bun.lockb` → Bun、`pnpm-lock.yaml` → pnpm、`yarn.lock`、`.yarnrc.yml`、または `.yarn/` ディレクトリ → Yarn。 +3. 何も見つからない場合、npm がデフォルトとして使用されます。 + + + +検索は親ディレクトリを走査するため、ワークスペース レベルの `packageManager` 設定またはロックファイルはネストされた AppHost によって自動的に取得されます。 + +### ツールチェーンの宣言 + +ツールチェーンをピン留めするための推奨方法は、`package.json` の `packageManager` フィールドです。Aspire がツールチェーン検出に使用します。このフィールドは、Yarn や pnpm などのパッケージマネージャーの [Node.js Corepack](https://nodejs.org/api/corepack.html) でも使用されます: + + + + +追加の設定は不要です。npm がデフォルトです。 + + + + +```json title="package.json" ins={2} +{ + "packageManager": "pnpm@9.0.0", + "name": "my-apphost", + "private": true, + "type": "module" +} +``` + + + + +```json title="package.json" ins={2} +{ + "packageManager": "yarn@4.0.0", + "name": "my-apphost", + "private": true, + "type": "module" +} +``` + + + + +```json title="package.json" ins={2} +{ + "packageManager": "bun@1.1.0", + "name": "my-apphost", + "private": true, + "type": "module" +} +``` + + + + +別の方法として、ツールチェーン固有のロックファイル(`pnpm-lock.yaml`、`yarn.lock`、`bun.lock` など)をコミットするだけで、検出に十分です。 + +### ツールチェーン別のインストールおよび実行コマンド + +npm 以外のツールチェーンが検出されると、CLI は一致するコマンドを置き換えます: + +| ツールチェーン | インストールコマンド | 実行コマンド | ウォッチコマンド | +|-----------|----------------|-----------------|---------------| +| npm | `npm install` | `npx tsx ...` | `npx nodemon ...` | +| pnpm | `pnpm install` | `pnpm exec tsx ...` | `pnpm exec nodemon ...` | +| Yarn | `yarn install` | `yarn exec tsx ...` | `yarn exec nodemon ...` | +| Bun | `bun install` | `bun run {appHostFile}` | `bun --watch run {appHostFile}` | + +:::note +Bun には組み込み TypeScript サポートがあるため、`tsx` なしで `apphost.ts` を直接実行します。 +::: + +### aspire doctor チェック + +`aspire doctor` コマンドは、必要な JavaScript ツールチェーン実行可能ファイルが利用可能かどうかを確認します。Bun、Yarn、または pnpm が検出されているが、インストールされていない場合、コマンドはインストール ガイダンスでエラーを報告します。 + +```bash title="Aspire CLI" +aspire doctor +``` + +## スタートアップ前の TypeScript 検証 + +TypeScript AppHost を開始する前に、Aspire CLI は `tsc --noEmit` を実行して型エラーをチェックし、ダッシュボードとリソースが部分的に壊れた状態で開始されるのを防ぎます。AppHost に TypeScript コンパイル エラーがある場合、`aspire run` と `aspire publish` は AppHost が起動する前に停止し、診断出力を表示します: + +```text +apphost.ts(22,7): error TS2322: Type 'string' is not assignable to type 'number'. +``` + +### ウォッチモード動作 + +ウォッチモードで `aspire run` を使用する場合、TypeScript 検証は nodemon 再起動コマンドに組み込まれます。ウォッチャーは、初期の型エラーがあっても**開始できます**。エラーを修正するファイルを編集して保存すると、自動的に回復します。 + +## 関連項目 + +- [最初のアプリをビルドする](/ja/get-started/first-app/?lang=typescript) +- [AppHost の概要](/ja/get-started/app-host/) +- [マルチ言語アーキテクチャ](/ja/architecture/multi-language-architecture/) +- [aspire doctor コマンド](/ja/reference/cli/commands/aspire-doctor/) diff --git a/src/frontend/src/content/docs/ja/app-host/withdockerfile.mdx b/src/frontend/src/content/docs/ja/app-host/withdockerfile.mdx new file mode 100644 index 000000000..aa9e38135 --- /dev/null +++ b/src/frontend/src/content/docs/ja/app-host/withdockerfile.mdx @@ -0,0 +1,365 @@ +--- +title: アプリモデルに Dockerfile を追加する +description: アプリモデルに Dockerfile を追加する方法について説明します。 +--- + +import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; + +Aspire では、`AddDockerfile` または `WithDockerfile` 拡張メソッドを使用して、[AppHost](/ja/get-started/app-host/) の起動時にビルドする _Dockerfile_ を指定できます。 + +この 2 つのメソッドは異なる目的に使用します: + +- **`AddDockerfile`**: 既存の Dockerfile から新しいコンテナーリソースを作成します。カスタムのコンテナー化サービスをアプリモデルに追加したい場合に使用します。 +- **`WithDockerfile`**: 既存のコンテナーリソース (データベースやキャッシュなど) をカスタマイズして別の Dockerfile を使用するようにします。Aspire コンポーネントのデフォルトコンテナーイメージを変更したい場合に使用します。 + +いずれのメソッドも、指定したコンテキストパスに既存の Dockerfile があることを前提としています。どちらのメソッドも Dockerfile を新規作成しません。AppHost コードから Dockerfile を生成するには、代わりに [Dockerfile ビルダー API](#dockerfile-をプログラムで生成する) を使用してください。 + +## AddDockerfile と WithDockerfile の使い分け + +シナリオに応じて適切なメソッドを選択してください: + +**`AddDockerfile` を使用する場合:** + +- カスタムのコンテナー化サービスをアプリモデルに追加したい場合。 +- カスタムアプリケーションまたはサービス用の既存の Dockerfile がある場合。 +- Aspire コンポーネントが提供していない新しいコンテナーリソースを作成する必要がある場合。 + +**`WithDockerfile` を使用する場合:** + +- 既存の Aspire コンポーネント (PostgreSQL、Redis など) をカスタマイズしたい場合。 +- デフォルトのコンテナーイメージをカスタムのものに置き換える必要がある場合。 +- 厳密に型指定されたリソースビルダーとその拡張メソッドを引き続き使用したい場合。 +- デフォルトのコンテナーイメージでは対応できない要件がある場合。 + +## アプリモデルに Dockerfile を追加する + +次の例では、`AddDockerfile` 拡張メソッドを使用して、コンテナービルドのコンテキストパスを参照することでコンテナーを指定しています。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var container = builder.AddDockerfile( + "mycontainer", "relative/context/path"); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const container = await builder.addDockerfile( + "mycontainer", "relative/context/path"); +``` + + + +コンテキストパスの引数がルートパスでない場合、コンテキストパスは AppHost プロジェクトディレクトリからの相対パスとして解釈されます。 + +デフォルトでは使用される _Dockerfile_ の名前は `Dockerfile` であり、コンテキストパスディレクトリ内に存在することが期待されます。_Dockerfile_ の名前は絶対パスまたはコンテキストパスへの相対パスとして明示的に指定することもできます。 + +これは、ローカルで実行する場合や AppHost がデプロイする際に使用する特定の _Dockerfile_ を変更したい場合に便利です。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var container = builder.ExecutionContext.IsRunMode + ? builder.AddDockerfile( + "mycontainer", "relative/context/path", "Dockerfile.debug") + : builder.AddDockerfile( + "mycontainer", "relative/context/path", "Dockerfile.release"); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const container = (await builder.executionContext.isRunMode()) + ? await builder.addDockerfile( + "mycontainer", "relative/context/path", "Dockerfile.debug") + : await builder.addDockerfile( + "mycontainer", "relative/context/path", "Dockerfile.release"); +``` + + + +## 既存のコンテナーリソースをカスタマイズする + +`AddDockerfile` を使用する場合、戻り値は `IResourceBuilder` です。Aspire には `ContainerResource` から派生した多くのカスタムリソース型が含まれています。 + +`WithDockerfile` 拡張メソッドを使用すると、既存の Aspire コンポーネント (PostgreSQL、Redis、SQL Server など) のデフォルトコンテナーイメージを、独自の Dockerfile からビルドしたカスタムイメージに置き換えることができます。これにより、基盤となるコンテナーをカスタマイズしながら、厳密に型指定されたリソース型とその固有の拡張メソッドを引き続き使用できます。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// デフォルトの PostgreSQL コンテナーイメージをカスタムイメージに置き換えます +// Dockerfile からビルドしたものを使用し、PostgreSQL 固有の機能は維持されます +var pgsql = builder.AddPostgres("pgsql") + .WithDockerfile("path/to/context") + .WithPgAdmin(); // PostgreSQL リソースであることに変わりないため、引き続き動作します +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const pgsql = await builder.addPostgres("pgsql"); + +// デフォルトの PostgreSQL コンテナーイメージをカスタムイメージに置き換えます +// Dockerfile からビルドしたものを使用し、PostgreSQL 固有の機能は維持されます。 +await pgsql.withDockerfile("path/to/context"); +await pgsql.withPgAdmin(); // PostgreSQL リソースであることに変わりないため、引き続き動作します。 +``` + + + +## Dockerfile をプログラムで生成する + +`AddDockerfileBuilder` または `WithDockerfileBuilder` は、AppHost コードから Dockerfile を生成する必要がある場合に使用します。これらの API は、Dockerfile が AppHost の設定に依存する場合、Dockerfile フラグメントを組み合わせたい場合、またはマルチステージイメージのビルドロジックをリソース定義の近くに保ちたい場合に便利です。 + + + +`AddDockerfileBuilder` は、新しいコンテナーリソースを作成し、生成された Dockerfile を 1 ステップで設定します: + + + +```csharp title="AppHost.cs" +using Aspire.Hosting.ApplicationModel.Docker; + +var builder = DistributedApplication.CreateBuilder(args); + +#pragma warning disable ASPIREDOCKERFILEBUILDER001 +builder.AddDockerfileBuilder("frontend", "../frontend", context => +{ + var build = context.Builder.From("node:22-alpine", "build"); + build.WorkDir("/app") + .Copy("package*.json", "./") + .Run("npm ci") + .Copy(".", ".") + .Run("npm run build"); + + var runtime = context.Builder.From("nginx:alpine", "runtime"); + runtime.CopyFrom("build", "/app/dist", "/usr/share/nginx/html") + .Expose(80); + + return Task.CompletedTask; +}, stage: "runtime"); +#pragma warning restore ASPIREDOCKERFILEBUILDER001 + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" +import { createBuilder } from './.modules/aspire.js'; +import type { DockerfileBuilderCallbackContext } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const configureDockerfile = async (context: DockerfileBuilderCallbackContext) => { + const dockerfile = await context.builder(); + + await dockerfile + .from("node:22-alpine", { stageName: "build" }) + .workDir("/app") + .copy("package*.json", "./") + .run("npm ci") + .copy(".", ".") + .run("npm run build"); + + await dockerfile + .from("nginx:alpine", { stageName: "runtime" }) + .copyFrom("build", "/app/dist", "/usr/share/nginx/html") + .expose(80); +}; + +await builder.addDockerfileBuilder("frontend", "../frontend", configureDockerfile, { + stage: "runtime", +}); + +await builder.build().run(); +``` + + + +`WithDockerfileBuilder` は、既存のコンテナーリソースに生成された Dockerfile を適用します。リソースの作成時に指定されたイメージ名は、パブリッシュ時に生成された Dockerfile のビルドに置き換えられます: + + + +```csharp title="AppHost.cs" +using Aspire.Hosting.ApplicationModel.Docker; + +var builder = DistributedApplication.CreateBuilder(args); + +#pragma warning disable ASPIREDOCKERFILEBUILDER001 +builder.AddContainer("frontend", "nginx:alpine") + .WithDockerfileBuilder("../frontend", context => + { + var stage = context.Builder.From("nginx:alpine", "runtime"); + stage.Copy(".", "/usr/share/nginx/html") + .Expose(80); + + return Task.CompletedTask; + }, stage: "runtime"); +#pragma warning restore ASPIREDOCKERFILEBUILDER001 + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" +import { createBuilder } from './.modules/aspire.js'; +import type { DockerfileBuilderCallbackContext } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const configureDockerfile = async (context: DockerfileBuilderCallbackContext) => { + const dockerfile = await context.builder(); + await dockerfile + .from("nginx:alpine", { stageName: "runtime" }) + .copy(".", "/usr/share/nginx/html") + .expose(80); +}; + +await builder + .addContainer("frontend", "nginx:alpine") + .withDockerfileBuilder("../frontend", configureDockerfile, { + stage: "runtime", + }); + +await builder.build().run(); +``` + + + +## ビルド引数を渡す + +`WithBuildArg` メソッドを使用して、コンテナーイメージのビルドに引数を渡すことができます。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var container = builder.AddDockerfile("mygoapp", "relative/context/path") + .WithBuildArg("GO_VERSION", "1.22"); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const container = await builder.addDockerfile("mygoapp", "relative/context/path"); +await container.withBuildArg("GO_VERSION", "1.22"); +``` + + + +`WithBuildArg` メソッドの値パラメーターには、リテラル値 (`boolean`、`string`、`int`) またはパラメーターリソースのリソースビルダーを指定できます ([パラメーターリソース](/ja/fundamentals/external-parameters/) を参照)。次のコードでは、`GO_VERSION` をデプロイ時に指定できるパラメーター値に置き換えます。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var goVersion = builder.AddParameter("goversion"); + +var container = builder.AddDockerfile("mygoapp", "relative/context/path") + .WithBuildArg("GO_VERSION", goVersion); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const goVersion = await builder.addParameter("goversion"); + +const container = await builder.addDockerfile("mygoapp", "relative/context/path"); +await container.withBuildArg("GO_VERSION", goVersion); +``` + + + +ビルド引数は _Dockerfiles_ の [`ARG` コマンド](https://docs.docker.com/build/guide/build-args/) に対応します。前述の例を拡張したマルチステージ _Dockerfile_ では、使用するコンテナーイメージのバージョンをパラメーターとして指定しています。 + +```dockerfile title="Dockerfile" +# Stage 1: Go プログラムをビルドする +ARG GO_VERSION=1.22 +FROM golang:${GO_VERSION} AS builder +WORKDIR /build +COPY . . +RUN go build mygoapp.go + +# Stage 2: Go プログラムを実行する +FROM mcr.microsoft.com/cbl-mariner/base/core:2.0 +WORKDIR /app +COPY --from=builder /build/mygoapp . +CMD ["./mygoapp"] +``` + + + +## ビルドシークレットを渡す + +ビルド引数に加え、`WithBuildSecret` を使用してビルドシークレットを指定できます。シークレットは、`RUN` コマンドの `--mount=type=secret` 構文を使用して _Dockerfile_ 内の個別のコマンドに選択的に公開されます。 + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var accessToken = builder.AddParameter("accesstoken", secret: true); + +var container = builder.AddDockerfile("myapp", "relative/context/path") + .WithBuildSecret("ACCESS_TOKEN", accessToken); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const accessToken = await builder.addParameter("accesstoken", { secret: true }); + +const container = await builder.addDockerfile("myapp", "relative/context/path"); +await container.withBuildSecret("ACCESS_TOKEN", accessToken); +``` + + + +たとえば、_Dockerfile_ の `RUN` コマンドで指定したシークレットを特定のコマンドに公開する場合を考えてみましょう: + +```dockerfile title="Dockerfile" +# helloworld コマンドは /run/secrets/ACCESS_TOKEN からシークレットを読み取ることができます +RUN --mount=type=secret,id=ACCESS_TOKEN helloworld +``` + + diff --git a/src/frontend/src/content/docs/ja/extensibility/custom-resources.mdx b/src/frontend/src/content/docs/ja/extensibility/custom-resources.mdx new file mode 100644 index 000000000..16ad8dd59 --- /dev/null +++ b/src/frontend/src/content/docs/ja/extensibility/custom-resources.mdx @@ -0,0 +1,292 @@ +--- +title: Aspire カスタム リソース +description: アプリケーション固有のインフラストラクチャ コンポーネントをモデル化するために、Aspire AppHost 向けのカスタム リソース型を作成する方法を学びます。 +--- + +import { Aside } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + +カスタム リソースを作成すると、組み込み統合でカバーされていないコンポーネントをモデル化できるように Aspire を拡張できます。このガイドでは、独自のリソース型を構築するためのパターンと API について説明します。 + +## リソースの基本 + +すべての Aspire リソースは `IResource` インターフェイスを実装し、`Name` プロパティが必要です。基本の `Resource` クラスには、継承できるシンプルな実装が用意されています。 + +### 基本的なリソース定義 + +最もシンプルなカスタム リソースは、`Resource` を継承するクラスです: + +```csharp title="MailDevResource.cs" +public sealed class MailDevResource(string name) : Resource(name); +``` + +これでアプリ モデルに追加できるリソースは作成できますが、特別な動作はまだありません。通常は、機能を追加するために追加のインターフェイスを実装します。 + +## よく使うリソース インターフェイス + +Aspire には、リソースに特定の機能を付与するいくつかのインターフェイスがあります: + +| インターフェイス | 目的 | +|-----------|---------| +| `IResourceWithConnectionString` | リソースがコンシューマー向けに接続文字列を公開する | +| `IResourceWithEndpoints` | リソースがネットワーク エンドポイントを持つ | +| `IResourceWithEnvironment` | リソースが環境変数を構成できる | +| `IResourceWithArgs` | リソースがコマンド ライン引数を受け取る | +| `IResourceWithWaitSupport` | リソースが `WaitFor` オーケストレーションをサポートする | +| `IResourceWithParent` | リソースが親リソースを持つ(ライフサイクル バインド) | + +### IResourceWithConnectionString の実装 + +クライアント アプリケーション向けに接続文字列を公開するリソースは、`IResourceWithConnectionString` を実装する必要があります: + +```csharp title="MailDevResource.cs" +public sealed class MailDevResource(string name, EndpointReference smtpEndpoint) + : Resource(name), IResourceWithConnectionString +{ + public ReferenceExpression ConnectionStringExpression => + ReferenceExpression.Create( + $"smtp://{smtpEndpoint.Property(EndpointProperty.Host)}:{smtpEndpoint.Property(EndpointProperty.Port)}"); +} +``` + +認証があるリソースでは、接続文字列に資格情報を含めます: + +```csharp title="InfluxDbResource.cs" +public sealed class InfluxDbResource : Resource, IResourceWithConnectionString +{ + private readonly EndpointReference _endpoint; + private readonly ParameterResource _token; + + public InfluxDbResource( + string name, + EndpointReference endpoint, + ParameterResource token) : base(name) + { + _endpoint = endpoint; + _token = token; + } + + public ReferenceExpression ConnectionStringExpression => + ReferenceExpression.Create( + $"Endpoint={_endpoint.Property(EndpointProperty.UriString)};" + + $"Token={_token}"); +} +``` + +## 拡張メソッドの作成 + +慣例として、リソースは `IDistributedApplicationBuilder` の拡張メソッドを通じてアプリ モデルに追加します: + +```csharp title="MailDevExtensions.cs" +public static class MailDevExtensions +{ + public static IResourceBuilder AddMailDev( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + int? smtpPort = null) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentNullException.ThrowIfNull(name); + + var resource = new MailDevResource(name); + + return builder.AddResource(resource) + .WithImage("maildev/maildev", "2.1.0") + .WithHttpEndpoint(targetPort: 1080, name: "http") + .WithEndpoint(targetPort: 1025, port: smtpPort, name: "smtp"); + } +} +``` + +`[ResourceName]` 属性により、リソース名に対する IDE ツール機能と検証が有効になります。 + +## リソースの動作追加 + +既定では、リソースはデータ コンテナーです。ランタイム動作を追加するには、次のいずれかの方法を使用します: + +### イベント サブスクライバーを使う + +ライフサイクル動作を追加する推奨方法は、`IDistributedApplicationEventingSubscriber` を実装することです: + +```csharp title="MailDevEventingSubscriber.cs" +public sealed class MailDevEventingSubscriber( + ResourceNotificationService notification, + ResourceLoggerService loggerService) + : IDistributedApplicationEventingSubscriber +{ + public Task SubscribeAsync( + IDistributedApplicationEventing eventing, + DistributedApplicationExecutionContext context, + CancellationToken cancellationToken) + { + eventing.Subscribe(async (@event, ct) => + { + foreach (var resource in context.Model.Resources.OfType()) + { + var logger = loggerService.GetLogger(resource); + logger.LogInformation("MailDev server ready at {Name}", resource.Name); + + await notification.PublishUpdateAsync(resource, s => s with + { + State = KnownResourceStates.Running, + StartTimeStamp = DateTime.UtcNow + }); + } + }); + + return Task.CompletedTask; + } +} +``` + + +利用可能なイベントの完全な一覧と高度なパターンについては、[AppHost eventing](/ja/app-host/eventing/) を参照してください。 + + +拡張メソッドでサブスクライバーを登録します: + +```csharp title="MailDevExtensions.cs" +public static IResourceBuilder AddMailDev( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + int? smtpPort = null) +{ + builder.Services.TryAddEventingSubscriber(); + + var resource = new MailDevResource(name); + return builder.AddResource(resource); +} +``` + +### インライン イベント購読を使う + +よりシンプルなケースでは、リソース ビルダーで直接イベントを購読できます: + +```csharp title="AppHost.cs" +public static IResourceBuilder AddMailDev( + this IDistributedApplicationBuilder builder, + [ResourceName] string name) +{ + var resource = new MailDevResource(name); + + builder.Eventing.Subscribe(resource, async (@event, ct) => + { + // メール サーバーを初期化し、テスト用メールボックスを作成するなど。 + }); + + return builder.AddResource(resource); +} +``` + +## リソース状態管理 + +ダッシュボードに表示される状態更新を公開するには、`ResourceNotificationService` を使用します: + +```csharp title="Publishing state updates" +await notification.PublishUpdateAsync(resource, state => state with +{ + State = KnownResourceStates.Running, + StartTimeStamp = DateTime.UtcNow +}); +``` + +### 既知の状態 + +Aspire は `KnownResourceStates` にいくつかの既知の状態を提供します: + +- `NotStarted` - リソースはまだ開始されていない +- `Starting` - リソースを初期化中 +- `Running` - リソースは稼働中 +- `Stopping` - リソースを停止中 +- `Exited` - リソースは停止済み +- `FailedToStart` - 起動時にリソースが失敗した +- `Waiting` - リソースは依存関係を待機中 +- `Hidden` - リソースはダッシュボードから非表示 + +### カスタム状態 + +`ResourceStateSnapshot` を使用してカスタム状態を作成できます: + +```csharp title="Custom state example" +await notification.PublishUpdateAsync(resource, state => state with +{ + State = new ResourceStateSnapshot("Indexing", KnownResourceStateStyles.Info) +}); +``` + +## 初期状態の構成 + +`WithInitialState` を使ってダッシュボードでの初期表示を設定します: + +```csharp title="Setting initial state" +return builder.AddResource(resource) + .WithInitialState(new CustomResourceSnapshot + { + ResourceType = "MailDev", + CreationTimeStamp = DateTime.UtcNow, + State = KnownResourceStates.NotStarted, + Properties = [ + new(CustomResourceKnownProperties.Source, "MailDev SMTP Server") + ] + }); +``` + +## マニフェストから除外 + +リソースがローカル開発専用である場合は、デプロイ マニフェストから除外します: + +```csharp title="Excluding from deployment" +return builder.AddResource(resource) + .ExcludeFromManifest(); +``` + +## リソース関係 + +関係を使って、ダッシュボードでのリソース表示を整理します: + +### WithRelationship + +視覚的な整理のために、リソース間でカスタム関係を作成します: + +```csharp title="AppHost.cs" +var api = builder.AddProject("api"); +var worker = builder.AddProject("worker") + .WithRelationship(api.Resource, "publishes-to"); +``` + +### WithChildRelationship + +ダッシュボードで、関連するリソースを親の下にグループ化します: + +```csharp title="AppHost.cs" +var postgres = builder.AddPostgres("postgres"); +var catalogDb = postgres.AddDatabase("catalog"); + +// カスタム リソースでも親子関係を確立できます: +var mailDev = builder.AddMailDev("mail") + .WithChildRelationship(catalogDb); +``` + + +Aspire Dashboard でのリソース表示の詳細は、[Dashboard overview](/ja/dashboard/overview/) を参照してください。 + + +## カスタム アイコン + +`WithIconName` を使うと、ダッシュボードでリソースにカスタム アイコンを表示できます。任意の [Fluent UI system icon](https://github.com/microsoft/fluentui-system-icons/blob/main/icons_filled.md) を使用できます: + +```csharp title="Setting custom dashboard icons" +return builder.AddResource(resource) + .WithIconName("mail"); // "mail" の Fluent UI アイコンを使用 + +// またはバリアントを指定(既定は Filled、Regular はアウトラインのみ) +return builder.AddResource(resource) + .WithIconName("mail", IconVariant.Regular); +``` + +## 関連情報 + +- [AppHost eventing](/ja/app-host/eventing/) - ライフサイクル イベントとサブスクライバー +- [Resource annotations](/ja/fundamentals/annotations-overview/) - 注釈の作成と利用 +- [Resource examples](/ja/architecture/resource-examples/) - 実運用のカスタム リソース例 +- [Custom resource commands](/ja/fundamentals/custom-resource-commands/) - ダッシュボード コマンドの追加 diff --git a/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx b/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx new file mode 100644 index 000000000..75fa17d7d --- /dev/null +++ b/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx @@ -0,0 +1,586 @@ +--- +title: Interaction service(プレビュー) +description: Interaction service API を使用して、公開とデプロイ中に Aspire ダッシュボードまたは CLI でユーザー入力の要求、確認依頼、メッセージ表示を行います。 +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; +import { Image } from 'astro:assets'; +import messageDialog from '@assets/extensibility/interaction-service-message-dialog.png'; +import messageBar from '@assets/extensibility/interaction-service-message-bar.png'; +import confirmation from '@assets/extensibility/interaction-service-confirmation.png'; +import multipleInput from '@assets/extensibility/interaction-service-multiple-input.png'; +import multipleInputFilled from '@assets/extensibility/interaction-service-multiple-input-filled.png'; +import multipleInputLogs from '@assets/extensibility/interaction-service-multiple-input-logs.png'; + +Interaction service(`Aspire.Hosting.IInteractionService`)を使うと、ユーザー入力の要求、確認依頼、メッセージ表示を行えます。Interaction service は 2 つの異なるコンテキストで動作します: + +- **Aspire dashboard**: `aspire run` を実行するか AppHost を直接起動すると、ダッシュボード UI にダイアログと通知として表示されます。 +- **Aspire CLI**: `aspire publish` または `aspire deploy` を実行すると、コマンド ライン インターフェイス経由で対話が促されます。 + +これは、アプリケーションの起動方法やデプロイ方法に関係なく、ユーザーから情報を収集したり、操作の状態に関するフィードバックを提供したりする必要があるシナリオで役立ちます。 + +## `IInteractionService` API + +`IInteractionService` インターフェイスは、`DistributedApplication` の依存関係注入コンテナーから取得します。`IInteractionService` は DI で作成される型に注入でき、また通常はイベントに渡されるコンテキスト引数で利用できる `IServiceProvider` から解決することもできます。 + +`IInteractionService` を要求したら、必ず利用可能かどうかを確認してください。利用できないとき(`IInteractionService.IsAvailable` が `false` を返すとき)に Interaction service を使おうとすると、例外がスローされます。 + +```csharp +var interactionService = serviceProvider.GetRequiredService(); +if (interactionService.IsAvailable) +{ + var result = await interactionService.PromptConfirmationAsync( + title: "Delete confirmation", + message: "Are you sure you want to delete the data?"); + + if (result.Data) + { + // リソース/コマンド ロジックを実行します。 + } +} +``` + +Interaction service には、ユーザーと対話したりメッセージを表示したりするための複数のメソッドがあります。これらのメソッドの動作は実行コンテキストによって異なります: + +- **Dashboard context**(`aspire run` または AppHost の直接起動): 対話は、[Aspire dashboard web interface](/ja/dashboard/overview/) のモーダル ダイアログ、通知、フォーム入力として表示されます。 +- **CLI context**(`aspire publish` または `aspire deploy`): 対話は、テキスト ベースのプロンプトと応答を通じてコマンド ライン インターフェイスで促されます。 + +次のセクションでは、これらの API を両方のコンテキストで効果的に使う方法を説明します: + +| メソッド | 説明 | サポートされるコンテキスト | +|--------|-------------|-------------------| +| `PromptMessageBoxAsync` | ユーザー操作用のメッセージとボタンを持つモーダル ダイアログ ボックスを表示します。 | Dashboard のみ | +| `PromptNotificationAsync` | ダッシュボードでメッセージ バーとして非モーダル通知を表示します。 | Dashboard のみ | +| `PromptConfirmationAsync` | ユーザーが操作を確認またはキャンセルするための確認ダイアログを表示します。 | Dashboard のみ | +| `PromptInputAsync` | テキストやシークレットなど、単一の入力値をユーザーに求めます。 | Dashboard、CLI | +| `PromptInputsAsync` | 複数の入力値を 1 つのダイアログ(dashboard)または順次(CLI)でユーザーに求めます。 | Dashboard、CLI | + + + +## Interaction service の使用場所 + +`IResourceBuilder` の利用可能なコールバック ベース拡張メソッドは、どれも Interaction service を使ってユーザー入力や確認を求められます。Interaction service は次のシナリオで使用します: + +- **カスタム リソース型**: カスタム リソース型を作成するときに、ユーザーから入力を取得したり、アクションを確認したりします。リソース型では、ユーザー入力の要求やメッセージ表示など、ダッシュボード対話を自由に定義できます。 + +- **カスタム リソース コマンド**: Aspire ダッシュボードまたは CLI でリソースにコマンドを追加します。これらのコマンド実行時に、Interaction service を使ってユーザー入力や確認を求めます。対象の `IResourceBuilder` に `WithCommand` 呼び出しをチェーンすると、コールバック内で Interaction service を使って入力収集や確認ができます。詳細は、[Custom resource commands](/ja/fundamentals/custom-resource-commands/) を参照してください。 + +- **公開とデプロイのワークフロー**: `aspire publish` または `aspire deploy` の実行中に、Interaction service を使ってデプロイ固有の構成を収集し、CLI から破壊的操作の確認を行います。 + +これらのアプローチにより、ローカル開発、ダッシュボード操作、デプロイ ワークフローにおいて、対話的で使いやすい体験を作成できます。 + + + +## メッセージを表示する + +ユーザーにメッセージを表示する方法はいくつかあります: + +- **ダイアログ メッセージ**: 注意を必要とする重要な情報をダイアログ ボックスで表示します。 +- **通知メッセージ**: 重要度が低い情報を通知で表示します。 + + + +### ダイアログ メッセージ ボックスを表示する + +ダイアログ メッセージは、ユーザーの注意を必要とする重要な情報を提供します。 + +`IInteractionService.PromptMessageBoxAsync` メソッドは、応答オプションをカスタマイズ可能なメッセージを表示します。 + +```csharp title="AppHost.cs" +var interactionService = context.ServiceProvider.GetRequiredService(); +var result = await interactionService.PromptMessageBoxAsync( + "Simple Message Box: Example", + """ + ##### 🤓 Nice! + + It's worth noting that **Markdown** is _supported_ + (and demonstrated here) in the message body. + + Cool, [📖 learn more](/extensibility/interaction-service/)... + """, + new MessageBoxInteractionOptions + { + EnableMessageMarkdown = true, + PrimaryButtonText = "Awesome" + } +); + +if (result.Canceled) +{ + return CommandResults.Failure("User cancelled."); +} + +return result.Data + ? CommandResults.Success() + : CommandResults.Failure("The user doesn't like the example"); +``` + +**Dashboard view:** + +タイトル、メッセージ、ボタンを含むメッセージ ダイアログを表示している Aspire ダッシュボード インターフェイス。 + +**CLI view:** + +`PromptMessageBoxAsync` メソッドは dashboard コンテキストでのみ動作します。`aspire publish` または `aspire deploy` の実行中に呼び出すと、このメソッドは例外をスローし、CLI にはメッセージを表示しません。 + +### 通知メッセージを表示する + +通知メッセージは、非モーダルの通知を提供します。 + + + +`PromptNotificationAsync` メソッドは、dashboard コンテキストで任意のアクション リンク付き情報メッセージを表示します。通知メッセージの結果が不要なら await する必要はありません。これは通知に特に有用で、ユーザーが閉じるのを待たずに通知を表示して処理を続行したい場合に役立ちます。 + +```csharp title="AppHost.cs" +var interactionService = context.ServiceProvider.GetRequiredService(); +// 異なる intent を持つ各種通知タイプを示す +var tasks = new List +{ + interactionService.PromptNotificationAsync( + title: "Confirmation", + message: "Are you sure you want to proceed?", + options: new NotificationInteractionOptions + { + Intent = MessageIntent.Confirmation + }), + interactionService.PromptNotificationAsync( + title: "Success", + message: "Your operation completed successfully.", + options: new NotificationInteractionOptions + { + Intent = MessageIntent.Success, + LinkText = "View Details", + LinkUrl = "/" + }), + interactionService.PromptNotificationAsync( + title: "Warning", + message: "Your SSL certificate will expire soon.", + options: new NotificationInteractionOptions + { + Intent = MessageIntent.Warning, + LinkText = "Renew Certificate", + LinkUrl = "https://portal.azure.com/certificates" + }), + interactionService.PromptNotificationAsync( + title: "Information", + message: "There is an update available for your application.", + options: new NotificationInteractionOptions + { + Intent = MessageIntent.Information, + LinkText = "Update Now", + LinkUrl = "/" + }), + interactionService.PromptNotificationAsync( + title: "Error", + message: "An error occurred while processing your request.", + options: new NotificationInteractionOptions + { + Intent = MessageIntent.Error, + LinkText = "Troubleshoot", + LinkUrl = "/get-started/troubleshooting/" + }) +}; + +await Task.WhenAll(tasks); + +return CommandResults.Success(); +``` + +前の例では、通知 API のいくつかの使い方を示しています。各アプローチは異なる種類の通知を表示し、すべて並列で呼び出されるため、ほぼ同時に dashboard へ表示されます。 + +**Dashboard view:** + +ページ上部付近に複数の通知メッセージが積み重なっている Aspire ダッシュボード インターフェイス。5 つの通知が表示され、それぞれ通知タイプが異なります。 + +**CLI view:** + +`PromptNotificationAsync` メソッドは CLI コンテキストでは利用できません。`aspire publish` または `aspire deploy` の実行中に呼び出すと、例外をスローします。 + +## ユーザー確認を求める + +続行前にユーザーの確認が必要な場合は、Interaction service を使用します。`PromptConfirmationAsync` メソッドは dashboard コンテキストで確認プロンプトを表示します。確認プロンプトは、破壊的操作や重大な影響を持つアクションに不可欠です。意図しない操作を防ぎ、ユーザーが判断を見直す機会を提供します。 + +### 破壊的操作の前に確認を求める + +リソース削除のように取り消せない操作では、必ず確認を求めます: + +```csharp title="AppHost.cs" +var interactionService = context.ServiceProvider.GetRequiredService(); +// データベースのリセット前に確認を求める +var resetConfirmation = await interactionService.PromptConfirmationAsync( + title: "Confirm Reset", + message: "Are you sure you want to reset the `development-database`? This action **cannot** be undone.", + options: new MessageBoxInteractionOptions + { + Intent = MessageIntent.Confirmation, + PrimaryButtonText = "Reset", + SecondaryButtonText = "Cancel", + ShowSecondaryButton = true, + EnableMessageMarkdown = true + }); + +if (resetConfirmation.Data is true) +{ + // リセット操作を実行する... + + return CommandResults.Success(); +} +else +{ + return CommandResults.Failure("Database reset canceled by user."); +} +``` + +**Dashboard view:** + +操作を確認またはキャンセルするためのタイトル、メッセージ、ボタンを備えた確認ダイアログを表示している Aspire ダッシュボード インターフェイス。 + +**CLI view:** + +`PromptConfirmationAsync` メソッドは CLI コンテキストでは利用できません。`aspire publish` または `aspire deploy` の実行中に呼び出すと、このメソッドは例外をスローします。 + +## ユーザー入力を求める + +Interaction service API では、さまざまな方法でユーザー入力を求められます。単一値または複数値を収集でき、テキスト、シークレット、選択肢、真偽値、数値などの入力タイプをサポートしています。表示は実行コンテキストに応じて自動的に切り替わります。 + +| 種類 | Dashboard | CLI プロンプト | +|--------------|---------------------------|-----------------------| +| `Text` | テキスト ボックス | テキスト プロンプト | +| `SecretText` | マスク入力付きテキスト ボックス | マスク テキスト プロンプト | +| `Choice` | オプションのドロップダウン | 選択プロンプト | +| `Boolean` | チェック ボックス | 真偽値選択プロンプト | +| `Number` | 数値テキスト ボックス | テキスト プロンプト | + +### ユーザーに入力値を求める + +`PromptInputAsync` メソッドで単一値を求めることも、`PromptInputsAsync` で複数の情報を収集することもできます。dashboard では複数入力が 1 つのダイアログにまとめて表示されます。CLI では各入力が順番に要求されます。 + + + +次の例では、ユーザーに複数の入力値を求めます: + +```csharp title="AppHost.cs" +var interactionService = context.ServiceProvider.GetRequiredService(); +var loggerService = context.ServiceProvider.GetRequiredService(); +var logger = loggerService.GetLogger(fakeResource); + +var inputs = new List +{ + new() + { + Name = "Application Name", + InputType = InputType.Text, + Required = true, + Placeholder = "my-app" + }, + new() + { + Name = "Environment", + InputType = InputType.Choice, + Required = true, + Options = + [ + new("dev", "Development"), + new("staging", "Staging"), + new("test", "Testing") + ] + }, + new() + { + Name = "Instance Count", + InputType = InputType.Number, + Required = true, + Placeholder = "1" + }, + new() + { + Name = "Enable Monitoring", + InputType = InputType.Boolean, + Required = false + } +}; + +var appConfigurationInput = await interactionService.PromptInputsAsync( + title: "Application Configuration", + message: "Configure your application deployment settings:", + inputs: inputs); + +if (!appConfigurationInput.Canceled) +{ + // 収集した入力値を処理する + var appName = appConfigurationInput.Data[0].Value; + var environment = appConfigurationInput.Data[1].Value; + var instanceCount = int.Parse(appConfigurationInput.Data[2].Value ?? "1"); + var enableMonitoring = bool.Parse(appConfigurationInput.Data[3].Value ?? "false"); + + logger.LogInformation(""" + Application Name: {AppName} + Environment: {Environment} + Instance Count: {InstanceCount} + Monitoring Enabled: {EnableMonitoring} + """, + appName, environment, instanceCount, enableMonitoring); + + // 必要に応じて収集値を使用する + return CommandResults.Success(); +} +else +{ + return CommandResults.Failure("User canceled application configuration input."); +} +``` + +**Dashboard view:** + +これは、次の画像のように dashboard で描画されます: + +ラベル、入力フィールド、入力の確定またはキャンセル用ボタンを含む複数入力ダイアログを表示している Aspire ダッシュボード インターフェイス。 + +次の値でダイアログを入力したと想像してください: + +入力フィールドに値が入力され、入力の確定またはキャンセル用ボタンを備えた複数入力ダイアログを表示している Aspire ダッシュボード インターフェイス。 + +**Ok** ボタンを選択すると、リソース ログには次の出力が表示されます: + +複数入力ダイアログで入力した値をログに表示している Aspire ダッシュボード インターフェイス。 + +**CLI view:** + +CLI コンテキストでは、同じ入力が順番に要求されます: + +```plaintext data-disable-copy +aspire deploy + +Step 1: Analyzing model. + + ✓ DONE: Analyzing the distributed application model for publishing and deployment capabilities. 00:00:00 + Found 1 resources that support deployment. (FakeResource) + +✅ COMPLETED: Analyzing model. completed successfully + +══════════════════════════════════════════════════════════════════════════════════════════════════════════════ +Configure your application deployment settings: +Application Name: example-app +Environment: Staging +Instance Count: 3 +Enable Monitoring: [y/n] (n): y +✓ DEPLOY COMPLETED: Deploying completed successfully +``` + +入力タイプによっては、CLI が追加のプロンプトを表示する場合があります。例えば `Enable Monitoring` 入力は真偽値選択なので、CLI は yes/no の応答を求めます。`y` を入力すると監視が有効になり、`n` を入力すると無効になります。environment 入力では、CLI が選択可能な環境一覧を表示します: + +```plaintext data-disable-copy +Configure your application deployment settings: +Application Name: example-app +Environment: + +> Development + Staging + Testing + +(Type to search) +``` + +#### 入力オプションを動的に読み込む + +Interaction service は動的入力をサポートしており、先行する回答に基づいてオプションを設定できます。これにより、dashboard と CLI の両方で連動ドロップダウンなどの依存プロンプトを実現できます。 + +動的入力を構成するには、`InteractionInput.DynamicLoading` プロパティに `InputLoadOptions` のインスタンスを設定します。`InputLoadOptions` には次のプロパティがあります: + +- **LoadCallback**: 入力オプションを設定または更新するコールバック関数です。入力の読み込みや更新が必要なときに呼び出されます。`context.AllInputs` ディクショナリを通じて、他の入力の現在値にアクセスできます。 +- **DependsOnInputs**: 動的入力が依存する入力名の一覧です。これらの入力が変化すると `LoadCallback` がトリガーされ、動的入力のオプションが更新されます。依存関係が指定されていない場合、コールバックは対話開始時にトリガーされます。 +- **AlwaysLoadOnStart**: `true` に設定すると、動的入力に依存関係がある場合でも、対話開始時に常に `LoadCallback` が呼び出されます。 + +```csharp +var inputs = new List +{ + new() + { + Name = "DatabaseType", + InputType = InputType.Choice, + Label = "Database Type", + Required = true, + Options = + [ + KeyValuePair.Create("postgres", "PostgreSQL"), + KeyValuePair.Create("mysql", "MySQL"), + KeyValuePair.Create("sqlserver", "SQL Server") + ] + }, + + new() + { + Name = "DatabaseVersion", + InputType = InputType.Choice, + Label = "Database Version", + Required = true, + DynamicLoading = new InputLoadOptions + { + LoadCallback = async context => + { + var dbType = context.AllInputs["DatabaseType"].Value; + context.Input.Options = await GetAvailableVersionsAsync(dbType); + }, + DependsOnInputs = ["DatabaseType"] + } + } +}; + +var result = await interactionService.PromptInputsAsync( + title: "Database configuration", + message: "Select a database type and version", + inputs: inputs); + +if (!result.Canceled) +{ + var version = result.Data["DatabaseVersion"].Value; + // バージョン固有の構成を使用する... +} +``` + +前述の例では、`DatabaseVersion` 入力は選択された `DatabaseType` に基づいて動的に設定されます。 + +#### 入力検証 + +基本的な入力検証は `InteractionInput` を設定することで利用できます。値の必須化や、`Text` または `SecretText` フィールドの最大文字数を指定できます。 + +複雑なシナリオでは、`InputsDialogInteractionOptions.ValidationCallback` プロパティを使ってカスタム検証ロジックを提供できます: + +```csharp +// カスタム検証を持つ複数入力 +var databaseInputs = new List +{ + new() + { + Name = "Database Name", + InputType = InputType.Text, + Required = true, + Placeholder = "myapp-db" + }, + new() + { + Name = "Username", + InputType = InputType.Text, + Required = true, + Placeholder = "admin" + }, + new() + { + Name = "Password", + InputType = InputType.SecretText, + Required = true, + Placeholder = "Enter a strong password" + }, + new() + { + Name = "Confirm password", + InputType = InputType.SecretText, + Required = true, + Placeholder = "Confirm your password" + } +}; + +var validationOptions = new InputsDialogInteractionOptions +{ + ValidationCallback = async context => + { + var passwordInput = context.Inputs.FirstOrDefault(i => i.Label == "Password"); + var confirmPasswordInput = context.Inputs.FirstOrDefault(i => i.Label == "Confirm password"); + + // パスワード強度を検証する + if (passwordInput?.Value is { Length: < 8 }) + { + context.AddValidationError(passwordInput, "Password must be at least 8 characters long"); + } + + // パスワード確認を検証する + if (passwordInput?.Value != confirmPasswordInput?.Value) + { + context.AddValidationError(confirmPasswordInput!, "Passwords do not match"); + } + + await Task.CompletedTask; + } +}; + +var dbResult = await interactionService.PromptInputsAsync( + title: "Database configuration", + message: "Configure your PostgreSQL database connection:", + inputs: databaseInputs, + options: validationOptions); + +if (!dbResult.Canceled && dbResult.Data != null) +{ + // 検証済み構成を使用する +} +``` + +ユーザーにパスワード入力を求め、同じ値か確認することは「二重独立検証」入力と呼ばれます。このアプローチは、タイプミスや不一致を避けるために同じパスワードを 2 回入力してもらいたい場面で一般的です。 + +### ユーザー入力のベスト プラクティス + +ユーザー入力を求めるときは、次のベスト プラクティスを考慮してください: + + + +1. **関連入力をグループ化する**: 関連する構成値を収集するには複数入力プロンプトを使います。dashboard では 1 つのダイアログに表示され、CLI では順次要求されますが、概念的には同じグループです。 +1. **明確なラベルとプレースホルダーを提供する**: コンテキストに関係なく、どの情報が期待されているかをユーザーが理解できるようにします。 +1. **適切な入力タイプを使う**: 収集するデータに合った入力タイプ(パスワードには secret、定義済み選択肢には choice など)を選択します。両コンテキストで適切にサポートされます。 +1. **検証を実装する**: ユーザー入力を検証し、検証失敗時には明確なエラー メッセージを提供します。両コンテキストで検証フィードバックをサポートします。 +1. **必須フィールドを明確にする**: 必須フィールドを明示し、任意フィールドには適切な既定値を提供します。 +1. **キャンセルを処理する**: ユーザーが入力プロンプトをキャンセルしたかを常に確認し、適切に処理します。dashboard と CLI の両方でキャンセルできます。 + + + +## 対話コンテキスト + +Interaction service の動作は、Aspire ソリューションの起動方法によって異なります: + +### Dashboard context + +`aspire run` を使用するか AppHost プロジェクトを直接起動すると、対話は Aspire ダッシュボード Web インターフェイスに表示されます: + +- **モーダル ダイアログ**: メッセージ ボックスや入力プロンプトが、ユーザー操作を必要とするオーバーレイ ダイアログとして表示されます。 +- **通知メッセージ**: 情報メッセージが、ダッシュボード上部の閉じられるバナーとして表示されます。 +- **リッチ UI**: 対話的なフォーム要素、検証、視覚的フィードバックを完全にサポートします。 +- **全メソッド利用可能**: dashboard コンテキストでは、すべての Interaction service メソッドがサポートされます。 + +### CLI context + +`aspire publish` または `aspire deploy` を実行すると、対話はコマンド ライン インターフェイス経由で促されます: + +- **テキスト プロンプト**: 入力プロンプト(`PromptInputAsync` と `PromptInputsAsync`)のみ利用でき、ターミナルにテキスト ベースのプロンプトとして表示されます。 +- **順次入力**: 複数入力は 1 つのダイアログではなく、1 つずつ要求されます。 +- **機能制限**: メッセージ ボックス、通知、確認ダイアログは利用できず、呼び出すと例外がスローされます。 + + diff --git a/src/frontend/src/content/docs/ja/extensibility/multi-language-integration-authoring.mdx b/src/frontend/src/content/docs/ja/extensibility/multi-language-integration-authoring.mdx new file mode 100644 index 000000000..0c5e73fec --- /dev/null +++ b/src/frontend/src/content/docs/ja/extensibility/multi-language-integration-authoring.mdx @@ -0,0 +1,614 @@ +--- +title: 多言語統合 +description: TypeScript、Python、Java、その他の言語の AppHost で動作するように Aspire hosting integration に注釈を付ける方法を学びます。 +--- + +import { + Aside, + Badge, + Code, + Steps, + Tabs, + TabItem, +} from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + + + +Aspire hosting integration は、新しいリソース型で AppHost を拡張する C# ライブラリです。既定では、これらの統合は C# AppHost でのみ利用できます。TypeScript AppHost で利用可能にするには、ATS(Aspire Type System)属性で API に注釈を付けます。 + +このガイドでは、統合を多言語で利用できるようにエクスポートする手順を説明します。 + +## 仕組み + +TypeScript AppHost が統合を追加すると、Aspire CLI は次を実行します: + + + +1. 統合アセンブリを読み込みます +2. メソッド、型、プロパティ上の ATS 属性(`[AspireExport]` など)をスキャンします。 +3. 対応するメソッドを持つ型付き TypeScript SDK を生成します +4. 生成された SDK は、実行時に JSON-RPC 経由で C# コードと通信します + + + +C# コードはそのまま実行され、TypeScript SDK はそれを呼び出す薄いクライアントです。TypeScript に書き直す必要はありません。 + +## Analyzer をインストールする + +[`📦 Aspire.Hosting.Integration.Analyzers`](https://www.nuget.org/packages/Aspire.Hosting.Integration.Analyzers) パッケージは、よくあるエクスポート ミスをビルド時に検出する検証を提供します。統合プロジェクトに追加してください: + +```xml title="XML — MyIntegration.csproj" + + all + runtime; build; native; contentfiles; analyzers + +``` + +Analyzer は、ユーザーがランタイム エラーに遭遇する前にエクスポートを正しく整えるのに役立つ診断を報告します。代表的なシナリオには、互換性のないパラメーター型の検出、公開メソッド上のエクスポート注釈不足、重複する export または capability ID、多言語 AppHost でデッドロックを引き起こす可能性がある同期コールバックの検出が含まれます。 + +## 拡張メソッドをエクスポートする + +プロジェクト ファイルで実験的診断を抑制します: + +```xml title="XML — MyIntegration.csproj" + + $(NoWarn);ASPIREATS001 + +``` + +次に、拡張メソッドに `[AspireExport]` を付けます: + +```csharp title="C# — MyDatabaseBuilderExtensions.cs" +[AspireExport("addMyDatabase", Description = "Adds a MyDatabase container resource")] +public static IResourceBuilder AddMyDatabase( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + int? port = null) +{ + // 既存の実装... +} + +[AspireExport("addDatabase", Description = "Adds a database to the MyDatabase server")] +public static IResourceBuilder AddDatabase( + this IResourceBuilder builder, + [ResourceName] string name, + string? databaseName = null) +{ + // 既存の実装... +} + +[AspireExport("withDataVolume", Description = "Adds a data volume to the MyDatabase server")] +public static IResourceBuilder WithDataVolume( + this IResourceBuilder builder, + string? name = null) +{ + // 既存の実装... +} +``` + +これにより、次の TypeScript API が生成されます: + +```typescript title="TypeScript — Generated SDK" {5-8} +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const db = await builder + .addMyDatabase("db", { port: 5432 }) + .addDatabase("mydata") + .withDataVolume(); + +const app = await builder.build(); +await app.run(); +``` + + + +### capability ID を一意に保つ + +ランタイムは **capability ID** によって多言語呼び出しをディスパッチします。capability ID は C# のメソッド シグネチャより制約が厳しく、C# のレシーバー型、パラメーター一覧、オーバーロード シグネチャを含みません。Aspire 13.3 以降では、同じアセンブリ内の 2 つのエクスポートが同じ capability ID を生成すると、Analyzer が `ASPIREEXPORT013` を報告します。 + +静的エクスポートでは、生成される capability ID はアセンブリ名と有効な export ID を使用します。次のメソッドは、異なる C# 型を対象にしていても衝突します: + +```csharp title="C# — Duplicate capability ID" +[AspireExport("configure")] +public static void ConfigureBuilder( + this IDistributedApplicationBuilder builder, + string name) +{ + // ... +} + +[AspireExport("configure")] +public static IResourceBuilder ConfigureDatabase( + this IResourceBuilder builder, + string value) +{ + return builder; +} +``` + +ランタイム capability には異なる export ID を使い、異なる対象型上でも生成される SDK メソッド名を簡潔に保ちたい場合は `MethodName` を使います: + +```csharp title="C# — Unique capability IDs with SDK method names" +[AspireExport("configureBuilder", MethodName = "configure")] +public static void ConfigureBuilder( + this IDistributedApplicationBuilder builder, + string name) +{ + // ... +} + +[AspireExport("configureDatabase", MethodName = "configure")] +public static IResourceBuilder ConfigureDatabase( + this IResourceBuilder builder, + string value) +{ + return builder; +} +``` + +コンテキスト型に対して `ExposeMethods = true` または `ExposeProperties = true` を設定すると、Analyzer は公開インスタンス メンバーから生成される capability も確認します。同名のオーバーロードされたインスタンス メソッドは既定で同じ capability ID を生成するため、ATS 対応オーバーロードを 1 つだけ公開するか、未対応オーバーロードに `[AspireExportIgnore]` を付けるか、各エクスポート メンバーに一意の `[AspireExport]` ID と生成用 `MethodName` を与えてください。 + +## リソース型をエクスポートする + +TypeScript SDK が型付きハンドルとして参照できるように、リソース型に `[AspireExport]` を付けます。すべての公開プロパティを capability として公開するには `ExposeProperties = true` を設定し、より細かく制御したい場合は各プロパティに `[AspireExport]` を付けます: + +```csharp title="C# — MyDatabaseResource.cs" +[AspireExport(ExposeProperties = true)] +public sealed class MyDatabaseResource(string name) + : ContainerResource(name), IResourceWithConnectionString +{ + /// + /// データベースのプライマリ エンドポイントを取得します。 + /// + public EndpointReference PrimaryEndpoint => new(this, "tcp"); + + /// + /// 内部実装の詳細。エクスポートされません。 + /// + [AspireExportIgnore] + public string InternalConnectionPool { get; set; } = ""; +} + +[AspireExport] +public sealed class MyDatabaseDatabaseResource(string name, MyDatabaseResource parent) + : Resource(name) +{ + // 既存の実装... +} +``` + +`ExposeProperties = true` の場合、各公開プロパティは生成される SDK で capability になります。公開したくないプロパティには `[AspireExportIgnore]` を使用してください。 + +`ExposeMethods = true` を設定して、プロパティに加えて公開インスタンス メソッドも capability としてエクスポートできます。 + +### getter のみのプロパティが TypeScript でどう見えるか + +コード ジェネレーターは、読み取り専用(getter のみ)プロパティと、読み書き可能または可変コレクション プロパティを区別します: + +- **getter のみのプロパティ**(setter がなく、可変コレクション型でもないもの)は、TypeScript で async メソッドとして生成されます: `property(): Promise`。 +- **読み書き可能プロパティ** と **可変コレクション プロパティ**(`AspireList` や `AspireDict` など)は、`readonly` getter プロパティとして生成されます。 + +例えば、両方の種類のプロパティを持つ C# クラス: + +```csharp title="C# — Mixed property kinds" +[AspireExport(ExposeProperties = true)] +public class MyCallbackContext +{ + /// getter のみ。TypeScript では async メソッドになります。 + public IResource Resource => _resource; + + /// 可変コレクション。TypeScript では readonly getter のままです。 + public AspireList Tags { get; } = new(); +} +``` + +これにより、次の TypeScript インターフェイスが生成されます: + +```typescript title="TypeScript — Generated interface" +export interface MyCallbackContext { + toJSON(): MarshalledHandle; + resource(): Promise; // getter のみ → async メソッド + readonly tags: AspireList; // 可変コレクション → readonly getter +} +``` + +TypeScript AppHost の作成者は、getter のみのプロパティを関数として呼び出します: + +```typescript title="TypeScript — Consuming the generated API" +const resource = await context.resource(); +const tags = context.tags; // 可変コレクションでは await は不要 +``` + +:::tip +TypeScript 側で値を一度読み取る async 操作として扱いたい場合は、getter のみのプロパティ(`=> value;` または setter のない `{ get; }`)を優先してください。TypeScript コードから直接追加、削除、反復処理を行う必要がある場合は `AspireList` と `AspireDict` を使用します。 +::: + +## コールバック コンテキスト型と ATS-first の editor パターン + +`withEnvironmentCallback`、`withArgsCallback`、`withUrls` など、コールバックを受け取るメソッドをエクスポートする場合、コールバックは *context* オブジェクトを受け取ります。TypeScript 互換性のため、コンテキスト型は ATS-first 設計に従う必要があります: + +1. コンテキスト クラスには `[AspireExport]` を使用します(`ExposeProperties = true` ではありません)。 +2. TypeScript 呼び出し元に必要なプロパティだけを個別の `[AspireExport]` 属性で注釈します。 +3. 可変状態(環境変数、コマンド ライン引数、URL リスト)には、生のコレクションではなく小さな *editor* クラスを公開します。 + +### editor クラスを定義する + +editor は可変コレクションをラップし、生のコレクションを TypeScript に渡す代わりに、通常は `add`、`set`、`remove` などの特定操作を公開します: + +```csharp title="C# — EnvironmentEditor.cs" +/// +/// polyglot コールバック内の環境変数に対する ATS-first editor を提供します。 +/// +[AspireExport] +internal sealed class EnvironmentEditor(Dictionary environmentVariables) +{ + /// 環境変数を設定します。 + [AspireExport(Description = "Sets an environment variable")] + public void Set( + string name, + [AspireUnion( + typeof(string), + typeof(ReferenceExpression), + typeof(EndpointReference), + typeof(IResourceBuilder), + typeof(IResourceBuilder))] + object value) + { + environmentVariables[name] = value; + } +} +``` + +### コールバック コンテキストを定義する + +TypeScript 呼び出し元に必要な各プロパティへ個別に `[AspireExport]` を付けます。editor は getter のみのプロパティとして渡し、TypeScript 呼び出し元が async メソッドとして受け取れるようにします: + +```csharp title="C# — MyCallbackContext.cs" +[AspireExport] +public sealed class MyCallbackContext( + DistributedApplicationExecutionContext executionContext, + IResource resource, + Dictionary environmentVariables) +{ + /// このコールバックに関連付けられたリソースを取得します。 + [AspireExport(Description = "Gets the resource associated with this callback")] + public IResource Resource => resource; + + /// 実行コンテキストを取得します。 + [AspireExport(Description = "Gets the execution context")] + public DistributedApplicationExecutionContext ExecutionContext => executionContext; + + /// 環境変数 editor を取得します。 + [AspireExport(Description = "Gets the environment variable editor")] + internal EnvironmentEditor Environment => new(environmentVariables); +} +``` + +### コールバック メソッドをエクスポートする + +`Action` をパラメーター型として使用し、コールバックを受け取る拡張メソッドをエクスポートします: + +```csharp title="C# — MyResourceBuilderExtensions.cs" +[AspireExport("withMyCallback", Description = "Configures the resource using a callback")] +public static IResourceBuilder WithMyCallback( + this IResourceBuilder builder, + Action configure) +{ + return builder.WithAnnotation(new MyCallbackAnnotation(configure)); +} +``` + +生成される TypeScript API は async アロー関数を受け取ります: + +```typescript title="TypeScript — Consuming the callback API" +await myResource.withMyCallback(async (context) => { + const resource = await context.resource(); + const env = await context.environment(); + await env.set("MY_KEY", "my-value"); +}); +``` + +:::note +`Action` デリゲート型は ATS 互換です。TypeScript 側は async 関数を受け取り、Aspire ランタイムは async な TypeScript 呼び出しをバックグラウンド スレッド上の同期 C# デリゲートへ橋渡しします。 +::: + +## 構成 DTO をエクスポートする + +統合が構造化された構成を受け入れる場合は、オプション クラスに `[AspireDto]` を付けます。DTO は TypeScript AppHost と .NET ランタイムの間で JSON としてシリアル化されます: + +```csharp title="C# — MyDatabaseOptions.cs" +[AspireDto] +public sealed class AddMyDatabaseOptions +{ + public required string Name { get; init; } + public int? Port { get; init; } + public string? ImageTag { get; init; } +} +``` + + + +## 値カタログをエクスポートする + +`[AspireValue]` を使うと、統合に含まれる不変の事前定義値を、型付きカタログ オブジェクトとしてゲスト SDK にエクスポートできます。これは、対応モデル名一覧やリージョン識別子など、polyglot AppHost 作成者が自分で組み立て直さずに参照できる既知の定数や構成プリセットを統合に含める場合に便利です。 + +`[AspireValue]` は `ASPIREATS001` 診断によって保護される実験的 API です。ほかの ATS 属性と同様に、プロジェクト ファイルで抑制してください: + +```xml title="XML — MyIntegration.csproj" + + $(NoWarn);ASPIREATS001 + +``` + +### 値カタログを定義する + +型上の `static readonly` フィールドまたは `static` プロパティに `[AspireValue]` を適用します。必須の `catalogName` 引数で、ゲスト SDK で生成されるカタログのルート名を設定します: + +```csharp title="C# — MyModels.cs" +using Aspire.Hosting; + +[AspireDto] +public sealed class MyModel +{ + public required string Name { get; init; } + public required string Version { get; init; } +} + +public static class MyModels +{ + public static class FastModels + { + /// 単純なタスク向けの高速で軽量なモデル。 + [AspireValue("MyModels")] + public static readonly MyModel Lite = new() { Name = "my-model-lite", Version = "1" }; + + /// 拡張コンテキスト サポートを備えた高速モデル。 + [AspireValue("MyModels")] + public static readonly MyModel LiteLong = new() { Name = "my-model-lite-long", Version = "1" }; + } + + public static class PowerModels + { + /// 複雑なタスク向けの高機能モデル。 + [AspireValue("MyModels")] + public static readonly MyModel Pro = new() { Name = "my-model-pro", Version = "2" }; + } +} +``` + +スキャナーは、各フィールドまたはプロパティを JSON にシリアル化することで、スキャン時点の値を固定します。さらに XML ドキュメント コメントを読み取り、生成されるカタログに説明を含めます。 + +### ゲスト SDK でカタログ値を使用する + +SDK を生成した後(例えば `aspire run` で)、カタログは各サポート言語で入れ子になったオブジェクトとして利用できます。入れ子構造は C# ソースの static クラス階層を反映します: + +```typescript title="TypeScript — apphost.ts" +import { createBuilder } from './.modules/aspire.js'; +import { MyModels } from './.modules/my-integration.js'; + +const builder = await createBuilder(); + +// 事前定義されたカタログ値を直接使用する +await builder + .addMyService('svc', { model: MyModels.FastModels.Lite }) + .build() + .run(); +``` + +```python title="Python — apphost.py" +from modules.my_integration import MyModels + +builder = await create_builder() + +await ( + builder + .add_my_service("svc", model=MyModels.FastModels.Lite) + .build() + .run() +) +``` + +### エクスポート名を上書きする + +既定では、エクスポート名はフィールド名またはプロパティ名と一致します。上書きするには `Name` プロパティを使用します: + +```csharp title="C# — Override exported name" +[AspireValue("MyModels", Name = "lite")] +public static readonly MyModel Lite = new() { Name = "my-model-lite", Version = "1" }; +``` + +### 値カタログの制約 + +- エクスポートされるフィールドとプロパティは **static** でなければなりません。 +- 値は JSON にシリアル化可能である必要があります。ランタイム ハンドル、デリゲート、その他の非シリアル化状態を保持する型は避けてください。 +- ハンドル(`IResourceBuilder`、リソース インスタンス)は、エクスポート値として **無効** です。 +- 値はスキャン時に **1 回だけ** 固定されます。生成される SDK ではコンパイル時定数として出力され、実行時に更新されることはありません。 + +:::note +`[AspireValue]` は事前定義された定数を生成 SDK にエクスポートするものです。ライブな実行時状態を共有する仕組みではありません。実行時の対話には、代わりに `[AspireExport]` メソッドを使用してください。 +::: + +## 互換性のないオーバーロードを扱う + +一部の C# オーバーロードでは、TypeScript で表現できない型(例: 非シリアル化コンテキストを持つ `Action` デリゲート、補間文字列ハンドラー、C# 固有の型)を使用します。こうしたものには `[AspireExportIgnore]` を付けます: + +```csharp title="C# — Exclude incompatible overloads" +// このオーバーロードは TypeScript で動作する。単純なパラメーター +[AspireExport("withConnectionStringLimit", Description = "Sets connection limit")] +public static IResourceBuilder WithConnectionStringLimit( + this IResourceBuilder builder, + int maxConnections) +{ + // ... +} + +// このオーバーロードは C# 固有型を使うので除外する +[AspireExportIgnore(Reason = "ForwarderConfig is not ATS-compatible. Use the DTO-based overload.")] +public static IResourceBuilder WithConnectionStringLimit( + this IResourceBuilder builder, + ForwarderConfig config) +{ + // ... +} +``` + + + +## Union 型 + +パラメーターが複数型を受け入れる場合は、`[AspireUnion]` を使って有効な選択肢を宣言します: + +```csharp title="C# — Union type parameter" +[AspireExport("withEnvironment", Description = "Sets an environment variable")] +public static IResourceBuilder WithEnvironment( + this IResourceBuilder builder, + string name, + [AspireUnion( + typeof(string), + typeof(ReferenceExpression), + typeof(EndpointReference), + typeof(IResourceBuilder), + typeof(IResourceBuilder), + typeof(IExpressionValue))] + object value) + where T : IResourceWithEnvironment +{ + // ... +} +``` + +Union に含まれるすべての型は ATS 互換である必要があります。Analyzer(ASPIREEXPORT005、ASPIREEXPORT006)は、ビルド時に Union 宣言を検証します。 + +## Analyzer 診断 + +`Aspire.Hosting.Integration.Analyzers` パッケージは次の診断を報告します: + +| ID | 重大度 | 説明 | +| --------------- | -------- | ------------------------------------------------------------------------------------------- | +| ASPIREEXPORT001 | Error | `[AspireExport]` メソッドは static でなければなりません | +| ASPIREEXPORT002 | Error | 無効な export ID 形式(`[a-zA-Z][a-zA-Z0-9.]*` に一致する必要があります) | +| ASPIREEXPORT003 | Error | 戻り値型が ATS 互換ではありません | +| ASPIREEXPORT004 | Error | パラメーター型が ATS 互換ではありません | +| ASPIREEXPORT005 | Warning | `[AspireUnion]` には少なくとも 2 つの型が必要です | +| ASPIREEXPORT006 | Warning | Union 型が ATS 互換ではありません | +| ASPIREEXPORT007 | Warning | 同じ対象型に対して export ID が重複しています | +| ASPIREEXPORT008 | Warning | エクスポート型上の公開拡張メソッドに `[AspireExport]` または `[AspireExportIgnore]` がありません | +| ASPIREEXPORT009 | Warning | export 名がほかの統合と衝突する可能性があります | +| ASPIREEXPORT010 | Warning | 同期コールバックがインラインで呼び出されています。多言語 AppHost でデッドロックする可能性があります | +| ASPIREEXPORT011 | Warning | 明示的な export ID が規約由来の名前と一致しています | +| ASPIREEXPORT012 | Warning | コールバック コンテキスト型に `[AspireExport]` がありません | +| ASPIREEXPORT013 | Warning | 同じアセンブリ内のエクスポート間で polyglot capability ID が重複しています | + +Analyzer 警告が 1 つもないクリーン ビルドであれば、統合は多言語利用の準備ができています。 + +## プロジェクト参照によるローカル開発 + +NuGet フィードに公開しなくても、統合をローカルでテストできます。TypeScript AppHost の `aspire.config.json` で、package 値にバージョン番号の代わりに `.csproj` パスを設定します: + +```json title="JSON — aspire.config.json" +{ + "appHost": { + "path": "apphost.ts", + "language": "typescript/nodejs" + }, + "packages": { + "Aspire.Hosting.Redis": "13.3.0", + "MyCompany.Hosting.MyDatabase": "../src/MyCompany.Hosting.MyDatabase/MyCompany.Hosting.MyDatabase.csproj" + } +} +``` + +CLI が `.csproj` パスを検出すると、プロジェクトをローカルでビルドし、生成されたアセンブリから TypeScript SDK を生成します。これにより、フィードへ公開せずにエクスポートを反復できます。 + + + +## エクスポートをテストする + + + +1. テスト用の TypeScript AppHost を作成します: + + ```bash title="Create test AppHost" + mkdir test-apphost && cd test-apphost + aspire init --language typescript + ``` + +2. `aspire.config.json` にプロジェクト参照として統合を追加します: + + ```json title="JSON — aspire.config.json (packages section)" + { + "packages": { + "MyCompany.Hosting.MyDatabase": "../src/MyCompany.Hosting.MyDatabase/MyCompany.Hosting.MyDatabase.csproj" + } + } + ``` + +3. `aspire run` を実行して TypeScript SDK を生成します: + + ```bash title="Generate SDK and start" + aspire run + ``` + +4. 生成された `.modules/` ディレクトリで、統合の TypeScript 型を確認します。エクスポートしたメソッドが正しいシグネチャで現れることを検証してください。 + +5. `apphost.ts` で生成された API を使用します: + + ```typescript title="TypeScript — apphost.ts" + import { createBuilder } from './.modules/aspire.js'; + + const builder = await createBuilder(); + + const db = await builder + .addMyDatabase('db', { port: 5432 }) + .addDatabase('mydata') + .withDataVolume(); + + await builder.build().run(); + ``` + + + +## サポートされる型 + +次の型は ATS 互換であり、エクスポート メソッド シグネチャで使用できます: + +| カテゴリ | 型 | +| --------------- | ---------------------------------------------------------------------------------------------------- | +| **Primitives** | `string`、`bool`、`int`、`long`、`float`、`double`、`decimal` | +| **Value types** | `DateTime`、`TimeSpan`、`Guid`、`Uri` | +| **Enums** | 任意の enum 型 | +| **Handles** | `IResourceBuilder`、`IDistributedApplicationBuilder`、`[AspireExport]` が付いたリソース型 | +| **DTOs** | `[AspireDto]` が付いたクラス/構造体 | +| **Exported values** | `[AspireValue]` が付いた static フィールド/プロパティ(ゲスト SDK ではカタログ定数として出力) | +| **Collections** | `List`、`Dictionary`、配列。`T` は ATS 互換である必要があります | +| **Delegates** | `Action`、`Func`、その他のデリゲート型(インラインで呼ばれる同期デリゲートには `RunSyncOnBackgroundThread = true` を使用) | +| **Services** | `ILogger`、`IServiceProvider`、`IConfiguration`(コア フレームワークですでにエクスポート済み) | +| **Special** | `ParameterResource`、`ReferenceExpression`、`EndpointReference`、`IExpressionValue`、`CancellationToken` | +| **Nullable** | 上記の nullable 版(`T?`) | + +ATS 互換 **ではない** 型には、補間文字列ハンドラーや、`[AspireExport]` または `[AspireDto]` を持たないカスタム複合型が含まれます。 + +## 関連情報 + +- [Build your first app](/ja/get-started/first-app/?lang=typescript) — TypeScript AppHost を使い始める +- [Custom resources](/ja/extensibility/custom-resources/) — カスタム リソース型の作成 +- [Integrations overview](/ja/integrations/overview/) — 利用可能な統合 diff --git a/src/frontend/src/content/docs/ja/fundamentals/custom-resource-commands.mdx b/src/frontend/src/content/docs/ja/fundamentals/custom-resource-commands.mdx new file mode 100644 index 000000000..3039900ab --- /dev/null +++ b/src/frontend/src/content/docs/ja/fundamentals/custom-resource-commands.mdx @@ -0,0 +1,848 @@ +--- +title: カスタム リソース コマンド +description: Aspire でカスタム リソース コマンドを作成する方法を学びます。 +--- + +import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; +import { Image } from 'astro:assets'; +import customClearCacheCommand from '@assets/fundamentals/custom-clear-cache-command.png'; +import customClearCacheCommandSucceeded from '@assets/fundamentals/custom-clear-cache-command-succeeded.png'; + +Aspire アプリ モデル内の各リソースは `IResource` として表現され、分散アプリケーション ビルダーに追加されると、`IResourceBuilder` インターフェイスのジェネリック型パラメーターになります。_resource builder_ API を使って呼び出しを連鎖し、基になるリソースを構成できます。状況によっては、そのリソースにカスタム コマンドを追加したいことがあります。カスタム コマンドを作成する一般的なシナリオには、データベース移行の実行やデータベースのシード/リセットなどがあります。この記事では、キャッシュをクリアする Redis リソースにカスタム コマンドを追加する方法を学びます。 + + + +## リソースにカスタム コマンドを追加する + +Aspire AppHost プロジェクトから開始します。以下のウォークスルーでは、Redis リソースに `clear-cache` コマンドを登録します。C# 版は登録をラップする拡張メソッドを使用し、TypeScript 版は管理エンドポイントを公開する Node サービスに対してコマンドをインライン登録します。どちらのフローでも、同じダッシュボード/CLI 体験を得られます。 + + + + +AppHost プロジェクトに _RedisResourceBuilderExtensions.cs_ という新しいクラスを追加し、内容を次のコードに置き換えます。 + +```csharp title="RedisResourceBuilderExtensions.cs" +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using StackExchange.Redis; + +namespace Aspire.Hosting; + +internal static class RedisResourceBuilderExtensions +{ + public static IResourceBuilder WithClearCommand( + this IResourceBuilder builder) + { + var commandOptions = new CommandOptions + { + UpdateState = OnUpdateResourceState, + IconName = "AnimalRabbitOff", + IconVariant = IconVariant.Filled + }; + + builder.WithCommand( + name: "clear-cache", + displayName: "Clear Cache", + executeCommand: context => OnRunClearCacheCommandAsync(builder, context), + commandOptions: commandOptions); + + return builder; + } + + private static async Task OnRunClearCacheCommandAsync( + IResourceBuilder builder, + ExecuteCommandContext context) + { + var connectionString = await builder.Resource.GetConnectionStringAsync() ?? + throw new InvalidOperationException( + $"Unable to get the '{context.ResourceName}' connection string."); + + await using var connection = ConnectionMultiplexer.Connect(connectionString); + var database = connection.GetDatabase(); + await database.ExecuteAsync("FLUSHALL"); + + return CommandResults.Success(); + } + + private static ResourceCommandState OnUpdateResourceState( + UpdateCommandStateContext context) + { + var logger = context.ServiceProvider.GetRequiredService>(); + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation( + "Updating resource state: {ResourceSnapshot}", + context.ResourceSnapshot); + } + + return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy + ? ResourceCommandState.Enabled + : ResourceCommandState.Disabled; + } +} +``` + +前述のコード: + +- AppHost から拡張が見えるように、`Aspire.Hosting` 名前空間を共有します。 +- `IResourceBuilder` に対する拡張メソッドを含む `static class` です。 +- `WithClearCommand` という単一の拡張メソッドを定義し、Redis リソースに `clear-cache` コマンドを登録します。さらに、ダッシュボードがコマンド実行と有効化判定に使う `executeCommand` と `updateState` コールバックを定義します。 +- 呼び出し側でチェーン可能にするため、`IResourceBuilder` を返します。 + + + + +TypeScript AppHost では、リソース ビルダー上でコマンドをインライン登録します。TypeScript には拡張メソッドがないため、クロージャーでコマンドに必要な状態をキャプチャします。 + +```typescript title="apphost.ts" +import { + createBuilder, + type ExecuteCommandContext, + type ExecuteCommandResult, +} from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const cache = await builder + .addNodeApp("cache", "./cache-service", "src/server.ts") + .withHttpEndpoint(); + +await cache.withCommand( + "clear-cache", + "Clear Cache", + async (_context: ExecuteCommandContext): Promise => { + const endpoint = await cache.getEndpoint("http"); + const url = await endpoint.url.get(); + const res = await fetch(`${url}/admin/cache/clear`, { method: "POST" }); + + if (!res.ok) { + return { + success: false, + message: `Cache service returned ${res.status} ${res.statusText}.`, + }; + } + + return { success: true, message: "Cache cleared." }; + }, + { + commandOptions: { + description: "Drops all entries in the cache service.", + confirmationMessage: "Clear all cached entries?", + iconName: "AnimalRabbitOff", + }, + }); + +await builder.build().run(); +``` + +前述のコード: + +- `cache` という名前の Node アプリを追加し、その上に `clear-cache` コマンドを登録します。 +- `executeCommand` コールバックを async アロー関数として実装し、リソースの HTTP エンドポイントを呼び出して実際のキャッシュ無効化を実行します。このパターンは、HTTP 経由で管理操作を公開する任意のリソースで機能します。代わりにクライアントを直接使いたいリソース(データベース、メッセージ ブローカー、…)では、同じコールバック内からそのクライアントを呼び出してください。 +- 4 番目の引数として `{ commandOptions: { ... } }` を渡し、ダッシュボードの説明、確認プロンプト、アイコンを設定します。 + + + + +`WithCommand` API は、リソースに適切な注釈を追加し、それらは [Aspire ダッシュボード](/ja/dashboard/overview/) で利用されます。ダッシュボードはこれらの注釈を使って UI にコマンドを描画します。詳細へ進む前に、まず `WithCommand` メソッドのパラメーターを理解しておきましょう。 + +- `name`: 呼び出すコマンド名。 +- `displayName`: ダッシュボードに表示するコマンド名。 +- `executeCommand`: コマンド呼び出し時に実行されるコールバック。C# では型が `Func>`、TypeScript では `(context: ExecuteCommandContext) => Promise` です。 +- `updateState`: ダッシュボード上でコマンドを有効化する状態を判定するコールバック。C# では `Func` で、`CommandOptions.UpdateState` 経由で指定します。TypeScript では `CommandOptions` 上の `updateState` フィールドです(現在は `any` 型)。 +- `iconName`: ダッシュボードに表示するアイコン名。アイコンは省略可能ですが、指定する場合は有効な [Fluent UI Blazor アイコン名](https://www.fluentui-blazor.net/Icon#explorer) である必要があります。 +- `iconVariant`: ダッシュボードに表示するアイコンのバリアント。有効な値は `Regular`(既定)または `Filled` です。 + +## コマンド実行ロジック + +`executeCommand` コールバックは、コマンド ロジックを実装する場所です。受け取る `ExecuteCommandContext` から、サービス プロバイダー、操作対象リソース、キャンセル トークンにアクセスできます。 + + + + +C# ではパラメーター型は `Func>` です。`ExecuteCommandContext` が公開する内容: + +- `ServiceProvider` _(`IServiceProvider`)_ — ロガーや `ResourceCommandService` などのサービス解決に使用します。 +- `ResourceName` _(`string`)_ — コマンド実行対象となるリソース インスタンス名です。 +- `CancellationToken` _(`CancellationToken`)_ — コマンド実行のキャンセルに使用します。 +- `Logger` _(`ILogger`)_ — ログをリソースのログへ直接書き込むために使用します。これらのログは [Aspire ダッシュボード](/ja/dashboard/explore/#console-logs-page) または `aspire logs ` コマンドで確認できます。 + +前述の例は、`OnRunClearCacheCommandAsync` という名前の private static メソッドに処理を委譲してキャッシュをクリアします。 + +```csharp title="RedisResourceBuilderExtensions.cs" +private static async Task OnRunClearCacheCommandAsync( + IResourceBuilder builder, + ExecuteCommandContext context) +{ + var connectionString = await builder.Resource.GetConnectionStringAsync() ?? + throw new InvalidOperationException( + $"Unable to get the '{context.ResourceName}' connection string."); + + await using var connection = ConnectionMultiplexer.Connect(connectionString); + + var database = connection.GetDatabase(); + + await database.ExecuteAsync("FLUSHALL"); + + return CommandResults.Success(); +} +``` + +前述のコード: + +- Redis リソースから接続文字列を取得します。 +- Redis インスタンスへ接続します。 +- データベース インスタンスを取得します。 +- `FLUSHALL` コマンドを実行してキャッシュをクリアします。 +- コマンド成功を示す `CommandResults.Success()` インスタンスを返します。 + + + + +TypeScript でのコールバック シグネチャは `(context: ExecuteCommandContext) => Promise` です。`ExecuteCommandContext` は camelCase の同等サーフェスを公開し、加えてショートカットとして `logger` アクセサーを提供します。 + +- `serviceProvider` — 依存性注入コンテナーの async アクセサー。 +- `resourceName` — リソース インスタンス名の async アクセサー。 +- `cancellationToken` — `CancellationToken` を返す async アクセサー。`await` して `AbortSignal` を受け取る API に転送できます。 +- `logger` — リソース ロガーの async アクセサー。`serviceProvider` からロガーを解決するのと同等です。 + +TypeScript コールバックは通常、async アロー関数としてインライン定義します。次の例は、リソースの HTTP エンドポイントを取得し、キャンセル トークンを `fetch` に転送します。 + +```typescript title="apphost.ts" +async (context: ExecuteCommandContext): Promise => { + const endpoint = await cache.getEndpoint("http"); + const url = await endpoint.url.get(); + const cancellation = await context.cancellationToken.get(); + + const res = await fetch(`${url}/admin/cache/clear`, { + method: "POST", + signal: cancellation as unknown as AbortSignal, + }); + + if (!res.ok) { + return { + success: false, + message: `Cache service returned ${res.status} ${res.statusText}.`, + }; + } + + return { success: true, message: "Cache cleared." }; +} +``` + +前述のコード: + +- リソースの HTTP エンドポイント URL を読み取ります。 +- リソースの管理エンドポイントを呼び出し、キャンセル トークンを abort signal として転送することで、ダッシュボードまたは CLI がコマンドをキャンセルしたときに要求を停止します。 +- HTTP 呼び出しが失敗した場合は `{ success: false, message: ... }` を返し、成功した場合は `{ success: true, message: "Cache cleared." }` を返します。 + + + + +## コマンド状態更新ロジック + +`updateState` コールバックは、ダッシュボード上でコマンドを有効化するかどうかを判定します。ダッシュボードはリソース状態が変化するたびにこれを呼び出します。典型的なユース ケースは、破壊的なコマンドを正常なリソースに対してのみ有効化すること、または起動プローブ成功後にのみコマンドを有効化することです。 + + + + +C# ではパラメーター型は `Func` です。`UpdateCommandStateContext` が公開する内容: + +- `ServiceProvider` _(`IServiceProvider`)_ — サービス解決に使用します。 +- `ResourceSnapshot` _(`CustomResourceSnapshot`)_ — 正常性ステータス、ライフサイクル状態、プロパティ、URL を含む、リソース インスタンスの不変スナップショットです。 + +前述の例では、Redis リソースが正常なときだけ `clear-cache` コマンドを有効化します。 + +```csharp title="RedisResourceBuilderExtensions.cs" +private static ResourceCommandState OnUpdateResourceState( + UpdateCommandStateContext context) +{ + var logger = context.ServiceProvider.GetRequiredService>(); + + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation( + "Updating resource state: {ResourceSnapshot}", + context.ResourceSnapshot); + } + + return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy + ? ResourceCommandState.Enabled + : ResourceCommandState.Disabled; +} +``` + +前述のコード: + +- サービス プロバイダーからロガー インスタンスを取得します。 +- リソース スナップショットの詳細をログ出力します。 +- リソースが正常なら `ResourceCommandState.Enabled`、それ以外は `ResourceCommandState.Disabled` を返します。 + + + + + + +TypeScript では `CommandOptions` の `updateState` フィールドが緩い型(`any`)であり、SDK はまだ `ResourceCommandState` 列挙体をエクスポートしていません。現時点の TypeScript AppHost で最も単純な方法は、`updateState` を完全に省略することです。コマンドは既定で有効になり、リソース到達後にのみコマンド登録します。 + +```typescript title="apphost.ts" +await cache.withCommand( + "clear-cache", + "Clear Cache", + executeClearCache, + { + commandOptions: { + iconName: "AnimalRabbitOff", + }, + }); +``` + +TypeScript AppHost でライフサイクル対応のゲーティングが必要な場合は、コールバック内ではなく外側で制御します。たとえば、接続文字列またはエンドポイント イベントを購読した後に、コマンドが依存するデータがリソースから公開されてからコマンドを登録してください。 + + + + +## カスタム コマンドをテストする + +カスタム コマンドをテストするには、AppHost を更新してリソースとコマンドを配線します。 + + + + +```csharp title="AppHost.cs" {4} +var builder = DistributedApplication.CreateBuilder(args); + +var cache = builder.AddRedis("cache") + .WithClearCommand(); + +var apiService = builder.AddProject("apiservice"); + +builder.AddProject("webfrontend") + .WithExternalHttpEndpoints() + .WithReference(cache) + .WaitFor(cache) + .WithReference(apiService) + .WaitFor(apiService); + +builder.Build().Run(); +``` + +前述のコードは `WithClearCommand` 拡張メソッドを呼び出し、Redis リソースにカスタム コマンドを追加します。 + + + + +```typescript title="apphost.ts" {5-15} +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const cache = await builder.addNodeApp("cache", "../cache/server.js"); +await cache.withHttpEndpoint(); +await cache.withCommand( + "clear-cache", + "Clear Cache", + async (context) => { + const endpoint = await cache.getEndpoint("http"); + const url = await endpoint.url.get(); + const cancellation = await context.cancellationToken.get(); + + const res = await fetch(`${url}/admin/cache/clear`, { + method: "POST", + signal: cancellation as unknown as AbortSignal, + }); + + if (!res.ok) { + return { + success: false, + message: `Cache service returned ${res.status} ${res.statusText}.`, + }; + } + + return { success: true, message: "Cache cleared." }; + }, + { + commandOptions: { + iconName: "AnimalRabbitOff", + description: "Clears the application cache.", + confirmationMessage: "Are you sure you want to clear the cache?", + }, + }); + +const apiService = await builder.addProject("apiservice", "../ApiService/ApiService.csproj"); + +const web = await builder.addProject("webfrontend", "../Web/Web.csproj"); +await web.withExternalHttpEndpoints(); +await web.withReference(cache); +await web.waitFor(cache); +await web.withReference(apiService); +await web.waitFor(apiService); + +await builder.build().run(); +``` + +前述のコードは、キャッシュ サービスを HTTP エンドポイント付き Node アプリとして登録し、`clear-cache` コマンドを直接アタッチします。 + + + + +アプリを実行して Aspire ダッシュボードへ移動します。キャッシュ リソース配下にカスタム コマンドが表示されるはずです。ダッシュボードの **Resources** ページで、**Actions** 列の下にある省略記号ボタンを選択します。 + +Aspire ダッシュボード: カスタム コマンドが表示された Redis キャッシュ リソース。 + +前述の画像には、Redis リソースへ追加した **Clear cache** コマンドが表示されています。アイコンは、依存リソースの速度がクリアされることを示すため、取り消し線付きのウサギとして表示されます。 + +**Clear cache** コマンドを選択して、Redis リソースのキャッシュをクリアします。コマンドは正常に実行され、キャッシュはクリアされるはずです。コマンドの結果は [通知センター](/ja/dashboard/explore/#notification-center) で確認できます。 + +Aspire ダッシュボード: カスタム コマンドが実行された Redis キャッシュ リソース。 + +## コマンドをプログラムで実行する + + + +[Aspire ダッシュボード](/ja/dashboard/overview/) を介してコマンドを実行するだけでなく、`ResourceCommandService` を使ってプログラムからコマンドを実行することもできます。このサービスは、次のような場合に有用です。 + +- アプリケーション コード内からコマンドを実行する +- ワークフローの一部としてコマンド実行を自動化する +- リソース制御が必要なカスタム ツールを構築する + +最も一般的なシナリオは、他のカスタム コマンド実装からコマンドを呼び出すことです。`ExecuteCommandContext` は `IServiceProvider` へのアクセスを提供し、これを使って `ResourceCommandService` を取得できます。 + +### カスタム コマンドからコマンドを実行する + +次の例は、他のコマンドを実行するカスタム コマンドの作成方法を示しています。このケースでは、"reset-all" コマンドがキャッシュをクリアし、データベースを再起動します。 + +```csharp title="AppHost.cs" +using Aspire.Hosting.ApplicationModel; +using Microsoft.Extensions.DependencyInjection; + +var builder = DistributedApplication.CreateBuilder(args); + +var cache = builder.AddRedis("cache") + .WithClearCommand(); // 前述のとおり "clear-cache" コマンドを定義 + +var database = builder.AddPostgres("postgres") + .WithCommand("restart", "Restart Database", async (context, ct) => + { + // データベース再起動の実装 + return CommandResults.Success(); + }); + +var api = builder.AddProject("api") + .WithReference(cache) + .WithReference(database) + .WithCommand("reset-all", "Reset Everything", async (context, ct) => + { + var commandService = context.ServiceProvider.GetRequiredService(); + + context.Logger.LogInformation("Starting full system reset..."); + + var clearResult = await commandService.ExecuteCommandAsync( + resource: cache.Resource, + commandName: "clear-cache", + cancellationToken: ct); + + var restartResult = await commandService.ExecuteCommandAsync( + resource: database.Resource, + commandName: "restart", + cancellationToken: ct); + + if (!clearResult.Success || !restartResult.Success) + { + return CommandResults.Failure("System reset failed"); + } + + context.Logger.LogInformation("System reset completed successfully"); + return CommandResults.Success(); + }); + +builder.Build().Run(); +``` + +この例では: + +- `context` パラメーターで `ServiceProvider` と `Logger` にアクセスします。 +- `context.Logger` は Aspire ダッシュボード内のリソース ログ ストリームへ直接ログを書き込みます。サービス プロバイダーからロガーを解決する必要はありません。 +- `ResourceCommandService` はサービス プロバイダーから取得します。 +- コマンドは `cache.Resource` と `database.Resource` を使ってリソース インスタンスに対して実行します。 +- 各コマンド結果の成功を確認してから次へ進みます。 + +### リソース ID でコマンドを実行する + +リソース ID またはリソース名を使ってコマンドを実行することもできます。リソース ID はリソース インスタンスの一意識別子で、リソース名は表示名です(この方法を使うには一意である必要があります)。 + +```csharp +var result = await commandService.ExecuteCommandAsync( + resourceId: "cache", + commandName: "clear-cache", + cancellationToken: cancellationToken); + +if (result.Success) +{ + logger.LogInformation("Command executed successfully"); +} +else if (result.Canceled) +{ + logger.LogWarning("Command was canceled"); +} +else +{ + logger.LogError("Command failed: {Message}", result.Message); +} +``` + +`resourceId` パラメーターには、次のいずれかを指定できます: +- リソースの一意 ID(例: レプリカを持つリソースの `cache-abcdwxyz`) +- 重複名がない場合の表示名(例: `cache`) + +### レプリカを持つリソースでコマンドを実行する + +複数レプリカを持つリソースに対して `IResource` オーバーロードでコマンドを実行すると、すべてのインスタンスで並列実行されます。 + +```csharp +// レプリカを持つリソースでは、すべてのインスタンスでコマンドが実行される +var result = await commandService.ExecuteCommandAsync( + resource: cache.Resource, + commandName: "clear-cache", + cancellationToken: cancellationToken); +``` + +複数レプリカ上で実行した場合の動作: +- コマンドはすべてのインスタンスで並列実行されます。 +- すべてのコマンドが成功した場合、結果は成功を示します。 +- いずれかのコマンドが失敗した場合、結果には失敗の詳細が含まれます。 +- 非成功のすべてがキャンセルだった場合、結果はキャンセルを示します。 + +### コマンド実行結果を処理する + +`ExecuteCommandResult` 型はコマンドの結果を保持します。両言語で同じ概念フィールドを公開します。 + +- **`Success` / `success`** _(boolean)_ — コマンドが正常完了したかどうか。 +- **`Canceled` / `canceled`** _(boolean)_ — ユーザー操作でコマンドがキャンセルされたかどうか。 +- **`Message` / `message`** _(string?)_ — [通知センター](/ja/dashboard/explore/#notification-center) と CLI 出力に表示される人間向けメッセージ。成功メッセージとエラー メッセージの両方に使われます。 +- **`Data` / `data`** _(`CommandResultData?`)_ — 省略可能な構造化出力(プレーン テキスト、JSON、Markdown)。[コマンドから構造化出力を返す](#コマンドから構造化出力を返す) を参照してください。 + + + + + + +`CommandResults` ヘルパー クラスは、一般的な形状のファクトリー メソッドを提供します。 + +```csharp +// ペイロードなしで成功 +return CommandResults.Success(); + +// ステータス メッセージ付きで失敗 +return CommandResults.Failure("Error occurred during execution"); + +// キャンセル(通常は確認プロンプトでユーザーが戻った場合) +return CommandResults.Canceled(); + +// 例外由来の失敗(Exception.Message を使用) +return CommandResults.Failure(ex); +``` + + + + +TypeScript にはヘルパー クラスがないため、`ExecuteCommandResult` に準拠するプレーン オブジェクトを返します。 + +```typescript +// ペイロードなしで成功 +return { success: true }; + +// ステータス メッセージ付きで失敗 +return { success: false, message: "Error occurred during execution" }; + +// キャンセル(通常は確認プロンプトでユーザーが戻った場合) +return { canceled: true }; + +// 捕捉した例外由来の失敗 +return { success: false, message: err instanceof Error ? err.message : String(err) }; +``` + + + + +## コマンドから構造化出力を返す + +リソース コマンドは、成功/失敗シグナルに加えて、プレーン テキスト、JSON、Markdown の構造化ペイロードを返せます。このペイロードは Aspire パイプライン全体を自動で流れます。 + +- **Dashboard**: 成功通知に **View response** アクションが追加され、ペイロードを表示するテキスト ビジュアライザー ダイアログが開きます。`Json` 結果は JSON シンタックス ハイライトに固定され、`Markdown` 結果は Markdown レンダリングに固定されます。`DisplayImmediately` を設定すると、コマンド完了直後にダイアログが開きます(クリック不要)。 +- **CLI**: ステータス メッセージは `stderr` に、ペイロードは `stdout` に出力されるため、`jq` のようなツールへ安全にパイプできます。 + + ```bash title="Terminal" + aspire resource cache issue-access-token | jq -r .token + ``` + +- **MCP tools**: ステータス メッセージの後に続く 2 番目の `TextContentBlock` として、ペイロードがツール応答に追加されます。 + +### テキストまたは JSON を返す + +一般的なシナリオは、カスタム コマンドから **アクセス トークン** を発行することです。開発者はそれをダッシュボードから直接コピーしたり、CLI から `Bearer` ヘッダーにパイプしたりできます。`Text` モードでは結果はトークン文字列のみ、`Json` モードでは有効期限とスコープを含む結果になります。 + +成功結果へペイロードを添付するには、`CommandResults.Success(message, result, resultFormat)` オーバーロードを使います。`message` は通知センター/CLI のステータス、`result` はペイロード文字列、`resultFormat` はダッシュボード ビジュアライザーの解釈方法を制御します。 + + + + +```csharp title="C# — AppHost.cs" +using System.Security.Cryptography; +using Aspire.Hosting.ApplicationModel; + +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddProject("myservice") + .WithCommand( + name: "issue-access-token", + displayName: "Issue Access Token", + executeCommand: context => + { + var token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)); + + return Task.FromResult(CommandResults.Success( + message: "Access token issued.", + result: token, + resultFormat: CommandResultFormat.Text)); + }); + +builder.Build().Run(); +``` + +有効期限とスコープ付き JSON を返すには、形式を `CommandResultFormat.Json` に切り替えます。 + +```csharp title="C# — AppHost.cs" +using System.Security.Cryptography; +using System.Text.Json; +using Aspire.Hosting.ApplicationModel; + +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddProject("myservice") + .WithCommand( + name: "issue-access-token", + displayName: "Issue Access Token", + executeCommand: context => + { + var token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)); + var json = JsonSerializer.Serialize(new + { + token, + expiresAt = DateTimeOffset.UtcNow.AddHours(1), + scopes = new[] { "read", "write" }, + }); + + return Task.FromResult(CommandResults.Success( + message: "Access token issued.", + result: json, + resultFormat: CommandResultFormat.Json)); + }); + +builder.Build().Run(); +``` + + + + +TypeScript では、`CommandResultData` 型の `data` プロパティを持つ `ExecuteCommandResult` オブジェクト リテラルを返します。 + +```typescript title="TypeScript — apphost.ts" +import { + createBuilder, + CommandResultFormat, + type ExecuteCommandContext, + type ExecuteCommandResult, +} from './.modules/aspire.js'; + +const builder = await createBuilder(); + +await builder + .addNodeApp("myservice", "./myservice", "src/server.ts") + .withCommand("issue-access-token", "Issue Access Token", + async (_context: ExecuteCommandContext): Promise => { + const token = crypto.randomUUID().replace(/-/g, ""); + + return { + success: true, + message: "Access token issued.", + data: { + value: token, + format: CommandResultFormat.Text, + }, + }; + }); + +await builder.build().run(); +``` + +有効期限とスコープ付き JSON を返すには、形式を `CommandResultFormat.Json` に切り替えます。 + +```typescript title="TypeScript — apphost.ts" +import { + createBuilder, + CommandResultFormat, + type ExecuteCommandContext, + type ExecuteCommandResult, +} from './.modules/aspire.js'; + +const builder = await createBuilder(); + +await builder + .addNodeApp("myservice", "./myservice", "src/server.ts") + .withCommand("issue-access-token", "Issue Access Token", + async (_context: ExecuteCommandContext): Promise => { + const token = crypto.randomUUID().replace(/-/g, ""); + const json = JSON.stringify({ + token, + expiresAt: new Date(Date.now() + 3_600_000).toISOString(), + scopes: ["read", "write"], + }); + + return { + success: true, + message: "Access token issued.", + data: { + value: json, + format: CommandResultFormat.Json, + }, + }; + }); + +await builder.build().run(); +``` + + + + +### 結果形式を選択する + +`CommandResultFormat` には 3 つの値があります。 + +| 値 | ダッシュボードでの動作 | +|------------|--------------------| +| `Text` | プレーン テキスト。固定形式なしでテキスト ビジュアライザー ダイアログに開き、ユーザーは別の構文へ切り替えて確認できます。 | +| `Json` | JSON。ビジュアライザーは JSON モードに固定され、シンタックス ハイライトと整形表示を行います。 | +| `Markdown` | Markdown。ビジュアライザーは Markdown レンダリングに固定されます。 | + +コマンドに表示すべきペイロードがない場合は、`Data` を省略してください(`CommandResults.Success()` または `{ success: true }` を返します)。 + +### 失敗時にデータを返す + +対応する `CommandResults.Failure(errorMessage, result, resultFormat)` オーバーロードを使うと、失敗結果にも同じペイロード形状を添付できます。これは、ユーザー(または下流ツール)が確認できる診断詳細を表面化するのに便利です。 + + + + +```csharp title="C# — AppHost.cs" +return CommandResults.Failure( + errorMessage: "Migration failed.", + result: errorJson, + resultFormat: CommandResultFormat.Json); +``` + + + + +```typescript title="TypeScript — apphost.ts" +return { + success: false, + message: "Migration failed.", + data: { + value: errorJson, + format: CommandResultFormat.Json, + }, +}; +``` + + + + +### ダッシュボードで結果ダイアログを自動表示する + +既定では、ダッシュボードは [通知センター](/ja/dashboard/explore/#notification-center) の通知に **View response** アクションとしてペイロードを表示します。`CommandResultData` の `DisplayImmediately` を設定すると、コマンド完了時にビジュアライザーを即座に開けます。短いコマンドで応答自体が目的の場合に便利です。 + + + + +```csharp title="C# — AppHost.cs" +return CommandResults.Success( + message: "Access token issued.", + value: new CommandResultData + { + Value = json, + Format = CommandResultFormat.Json, + DisplayImmediately = true, + }); +``` + + + + +```typescript title="TypeScript — apphost.ts" +return { + success: true, + message: "Access token issued.", + data: { + value: json, + format: CommandResultFormat.Json, + displayImmediately: true, + }, +}; +``` + + + + +### レプリカ集約 + +リソースが複数レプリカを持つ場合、コマンドはすべてのインスタンスで並列実行されます。複数レプリカからペイロードが返された場合、最初に成功したペイロードのみが呼び出し側へ伝搬し、他は破棄されます。 + +### CLI からコマンドを呼び出す + +`WithCommand` で登録した任意のコマンドは、組み込みの `start`、`stop`、`restart` コマンドを含め、`aspire resource` コマンドを使ってターミナルから呼び出せます。 + +```bash title="Terminal" +aspire resource [--apphost ] +``` + +CLI はステータス出力とペイロード出力を分離するため、結果はスクリプト処理しやすい形式になります。 + +- `Message` と進捗テキストは **stderr** に書き込まれます。 +- `Data.Value`(存在する場合)は **stdout** にそのまま書き込まれます。`Json` と `Text` ペイロードはそのまま出力され、`Markdown` は見出し、リスト、コード ブロックを端末向けに装飾してレンダリングされます。 +- 終了コードは、成功時が `0`、失敗またはキャンセル時が非 0 です。 + +これにより、構造化ペイロードを `jq` に直接パイプしたり、ファイルへリダイレクトしたり、終了コードで分岐したりできます。 + +```bash title="Terminal — Pipe a JSON payload through jq" +$ aspire resource cache issue-access-token | jq -r .token +ey7WqGxk2vL... +``` + +ステータス メッセージ `Access token issued.` は stderr に書き込まれるため、stdout はパイプ用にクリーンなまま保たれます。 + +```bash title="Terminal — Use the exit code in a script" +if aspire resource db migrate > migrations.json; then + echo "Applied $(jq length migrations.json) migrations." +else + echo "Migration failed — see error above." + exit 1 +fi +``` diff --git a/src/frontend/src/content/docs/ja/fundamentals/custom-resource-urls.mdx b/src/frontend/src/content/docs/ja/fundamentals/custom-resource-urls.mdx new file mode 100644 index 000000000..d1153b25d --- /dev/null +++ b/src/frontend/src/content/docs/ja/fundamentals/custom-resource-urls.mdx @@ -0,0 +1,108 @@ +--- +title: カスタム リソース URL を定義する +description: Aspire リソース用のカスタム URL を作成する方法を学びます。 +--- + +import { Aside } from '@astrojs/starlight/components'; + +Aspire では、エンドポイントを公開するリソースはホストとポートのみを構成しますが、これらは実行時まで確定しません。これらのエンドポイントの特定パスにアクセスする必要がある場合、特に [ダッシュボード](/ja/dashboard/overview/) からアクセスしたい場合は、カスタム リソース URL を定義できます。任意のエンドポイントに紐付かないカスタム URL を追加することも可能です。カスタム URL はダッシュボードで使うことを目的としているため、すべて "run" モードでのみ利用できます。この記事では、カスタム URL の定義方法を説明します。 + +## 既定のエンドポイント動作 + +既定では、Aspire プロジェクト リソースは Kestrel や起動プロファイルなどの既存構成に基づいて、構成済みエンドポイント向けリソースのホストとポートを決定します。エンドポイントは常にダッシュボードに表示されます。 + +同様に、`WithEndpoint` API を使ってエンドポイントを明示的に公開することもできます。この API ではリソースのホストとポートを指定でき、これを使ってそのリソースの既定 URL が作成されます。既定 URL は通常、`://:` 形式です。ホスト ポートを省略するには、次のいずれかのメソッドを使います。 + +- `WithHttpEndpoint` +- `WithHttpsEndpoint` + +詳細は、[エンドポイント拡張メソッド](/ja/fundamentals/networking-overview/#エンドポイント拡張メソッド) を参照してください。 + +## サポートされるリソースの種類 + +カスタム リソース URL は、次のリソースの種類でサポートされます。 + +- `ContainerResource` +- `ExecutableResource` +- `ProjectResource` + +## リソース URL をカスタマイズする + +サポートされる任意のリソース ビルダーで、適切な `WithUrl` オーバーロード、`WithUrls`、または `WithUrlForEndpoint` API を使うと、リソースのカスタム URL を定義できます。次の例は、プロジェクト リソースにカスタム URL を設定する方法を示しています。 + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var api = builder.AddProject("api"); + +api.WithUrl("/admin", "Admin Portal"); + +builder.Build().Run(); +``` + + + +前述のコードでは、プロジェクト参照を `api` 変数に代入し、その変数を使って `Admin Portal` ルートのカスタム URL を作成しています。`WithUrl` メソッドは、`ReferenceExpression` と表示名をパラメーターとして受け取ります。生成された URL はダッシュボードで利用できます。 + +### エンドポイント URL をカスタマイズする + +[Scalar](https://scalar.com/) と [Swagger](https://swagger.io/tools/swagger-ui/) はどちらも、エンドポイントの使いやすさを高める一般的な API サービスです。これらのサービスには、宣言済みエンドポイントに紐付く URL でアクセスします。 + +最初に関連付けられたリソース エンドポイントの URL をカスタマイズするには、`WithUrlForEndpoint` メソッドを使います。別の URL(同じエンドポイント向けであっても)を追加したい場合は、`ReferenceExpression` または補間文字列を受け取る `WithUrl` オーバーロードを呼び出すか、`WithUrls` を呼び出してコンテキスト上の `Urls` リストに URL を追加する必要があります。 + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddProject("api") + .WithUrlForEndpoint("https", url => + { + url.DisplayText = "Scalar (HTTPS)"; + url.Url = "/scalar"; + }); + +builder.Build().Run(); +``` + +前述の例は、`api` プロジェクト リソースに `https` エンドポイントが構成されていることを前提にしています。`WithUrlForEndpoint` メソッドは、エンドポイントに関連付けられた `ResourceUrlAnnotation` を更新します。この場合、表示テキストに `Scalar (HTTPS)` を設定し、URL に相対パス `/scalar` を設定します。 + +リソースが開始されると、URL はダッシュボードで利用できます。 + +または、コールバックとして `Func` を受け取るオーバーロードを使うこともできます。これにより、対象 `EndpointReference` インスタンスのディープ リンクを指定できます。 + +### 複数のリソース URL をカスタマイズする + +リソースの複数 URL をカスタマイズするには、`WithUrls` メソッドを使います。このメソッドでは、各 URL に独自の表示テキストを設定しながら、リソースに対して複数 URL を指定できます。次の例は、プロジェクト リソースに複数 URL を設定する方法を示しています。 + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddProject("api") + .WithUrls(context => + { + foreach (var url in context.Urls) + { + if (string.IsNullOrEmpty(url.DisplayText)) + { + url.DisplayText = $"API ({url.Endpoint?.Scheme?.ToUpper()})"; + } + } + }); + +builder.Build().Run(); +``` + +前述のコードは、`api` プロジェクト リソースに定義された URL を走査し、スキーム付きの表示テキストを割り当てます。 + + + +## URL カスタマイズのライフサイクル + +URL カスタマイズ コールバックは、アプリケーション モデルのライフサイクル内、具体的には `BeforeResourceStartedEvent` イベント処理中に実行されます。エンドポイントに関連付けられた URL は、エンドポイント自体がアクティブになった時点で有効化され、ダッシュボードに表示されます。エンドポイントに関連付けられていない URL は、リソースが "Running" 状態に入ったときにのみ有効になります。これにより、アプリケーション リソースが完全に稼働した時点で、すべてのカスタム URL が正しく表現され利用可能になることが保証されます。 diff --git a/src/frontend/src/content/docs/ja/fundamentals/http-commands.mdx b/src/frontend/src/content/docs/ja/fundamentals/http-commands.mdx new file mode 100644 index 000000000..45e3c1f1b --- /dev/null +++ b/src/frontend/src/content/docs/ja/fundamentals/http-commands.mdx @@ -0,0 +1,255 @@ +--- +title: カスタム HTTP コマンド +description: Aspire でカスタム HTTP コマンドを作成する方法を学びます。 +--- + +import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; +import { Image } from 'astro:assets'; +import LearnMore from '@components/LearnMore.astro'; +import customHttpCommandHighlighted from '@assets/fundamentals/custom-http-command-highlighted.png'; +import customHttpCommand from '@assets/fundamentals/custom-http-command.png'; +import customHttpCommandStarting from '@assets/fundamentals/custom-http-command-starting.png'; +import customHttpCommandSucceeded from '@assets/fundamentals/custom-http-command-succeeded.png'; + +Aspire では、`WithHttpCommand` API を使ってリソースにカスタム HTTP コマンドを追加できます。この API は、[リソースのカスタム コマンド](/ja/fundamentals/custom-resource-commands/) を提供する既存機能を拡張するものです。この機能により、指定したエンドポイントとパスへ HTTP 要求を送るコマンドをリソース上に定義できます。これは、データベース移行のトリガー、キャッシュのクリア、HTTP 要求を介したリソースへのカスタム操作などのシナリオで役立ちます。 + +カスタム HTTP コマンドを実装するには、リソース上のコマンドと、その要求を処理する対応 HTTP エンドポイントを定義します。この記事では、Aspire でカスタム HTTP コマンドを作成して構成する方法の概要を説明します。 + +## HTTP コマンド API + +利用できる API には、HTTP コマンドをカスタマイズするための多くのパラメーターがあり、幅広い機能を提供します。リソースに HTTP コマンドを追加するには、リソース ビルダー上の `WithHttpCommand` 拡張メソッドを使います。利用可能なオーバーロードは 2 つあります。 + +`WithHttpCommand` API は、Aspire のリソースにカスタム HTTP コマンドを追加するために 2 つのオーバーロードを提供します。これらの API は柔軟性を重視して設計されており、HTTP コマンドを定義する際の異なるユース ケースに対応します。 + +1. **`endpointName` 付きオーバーロード:** + + このバージョンは、HTTP コマンドの対象にするエンドポイント名があらかじめ決まっている場合に適しています。特定のエンドポイントへコマンドを直接関連付けることで、構成を簡素化できます。これは、開発時点でエンドポイントが固定されていて既知であるシナリオで有用です。 + +1. **`endpointSelector` 付きオーバーロード:** + + このバージョンは、実行時にエンドポイントを決定するコールバック(`endpointSelector`)を指定できるため、より動的な動作を提供します。エンドポイントがリソースの状態やその他のコンテキスト要因に応じて変わる可能性がある場合に有効です。エンドポイントをハードコードできない高度なシナリオに対して、より高い柔軟性を提供します。 + +どちらのオーバーロードでも HTTP コマンドを幅広くカスタマイズでき、`CommandOptions` 型のサブクラスである `HttpCommandOptions` を通じて、HTTP メソッドの指定、要求の構成、応答の処理、表示名・説明・アイコンといった UI 関連プロパティの定義が行えます。どちらを選ぶかは、ユース ケースにおいてエンドポイントが静的か動的かで決まります。 + +これらの API は Aspire エコシステムへシームレスに統合されるよう設計されており、動作と表示を制御しながら最小限の労力でリソース機能を拡張できます。 + +## HTTP コマンドを登録する際の考慮事項 + +HTTP コマンドは HTTP エンドポイント経由で公開されるため、潜在的なセキュリティ リスクを考慮してください。可能であれば、これらのエンドポイントは開発環境またはステージング環境に限定します。受信要求が信頼できる送信元から来ていることを必ず検証してください。詳細は、[ASP.NET Core セキュリティ](https://learn.microsoft.com/ja-jp/aspnet/core/security) を参照してください。 + +`HttpCommandOptions.PrepareRequest` コールバックを使うと、認証ヘッダーの追加などによってセキュリティを強化できます。一般的なアプローチは、AppHost とリソースだけが知っている共有シークレット、[外部パラメーター](/ja/fundamentals/external-parameters/)、またはトークンを使うことです。この共有値を使えば、要求を検証して未承認アクセスを防止できます。 + +## カスタム HTTP コマンドを追加する + +_AppHost.cs_ ファイルでは、`T` が `IResourceWithEndpoints` である `IResourceBuilder` に対して `WithHttpCommand` API を使い、カスタム HTTP コマンドを追加します。方法の例を次に示します。 + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var cache = builder.AddRedis("cache"); + +var apiCacheInvalidationKey = builder.AddParameter("ApiCacheInvalidationKey", secret: true); + +var api = builder.AddProject("api") + .WithReference(cache) + .WaitFor(cache) + .WithEnvironment("ApiCacheInvalidationKey", apiCacheInvalidationKey) + .WithHttpCommand( + path: "/cache/invalidate", + displayName: "Invalidate cache", + commandOptions: new HttpCommandOptions() + { + Description = """ + Invalidates the API cache. All cached values are cleared! + """, + PrepareRequest = (context) => + { + var key = apiCacheInvalidationKey.Resource.GetValueAsync(context.CancellationToken); + context.Request.Headers.Add("X-CacheInvalidation-Key", $"Key: {key}"); + return Task.CompletedTask; + }, + IconName = "DocumentLightning", + IsHighlighted = true + }); + +builder.Build().Run(); +``` + +前述のコード: + +- 新しい分散アプリケーション ビルダーを作成します。 +- `cache` という名前の Redis キャッシュをアプリケーションに追加します。 +- `ApiCacheInvalidationKey` という名前のパラメーターをアプリケーションに追加します。このパラメーターはシークレットとしてマークされるため、その値は安全に扱われます。 +- `AspireApp_Api` という名前のプロジェクトをアプリケーションに追加します。 +- Redis キャッシュへの参照を追加し、準備完了まで待機してから処理を進めます。 +- 次の内容で、プロジェクト向け HTTP コマンドを構成します: + - `path`: HTTP コマンドの URL パス(`/cache/invalidate`)を指定します。 + - `displayName`: UI に表示されるコマンド名(`Invalidate cache`)を設定します。 + - `commandOptions`: UI 上でのコマンド動作と外観を構成する `HttpCommandOptions` の省略可能インスタンスです: + - `Description`: UI に表示されるコマンド説明を提供します。 + - `PrepareRequest`: 送信前に HTTP 要求を構成するコールバック関数です。この場合は、`ApiCacheInvalidationKey` パラメーターの値を使ってカスタム ヘッダー(`X-CacheInvalidation-Key`)を追加します。 + - `ResultMode`: 応答本文をコマンド結果データとして返すかどうかを指定します。詳細は、[HTTP 応答本文を返す](#http-応答本文を返す) を参照してください。 + - `IconName`: UI のコマンドに使用するアイコン(`DocumentLightning`)を指定します。 + - `IsHighlighted`: UI でコマンドを強調表示するかどうかを示します。 +- 最後に、アプリケーションをビルドして実行します。 + + + 独自アイコンを探すには、[Fluent UI: Icons + catalog](https://storybooks.fluentui.dev/react/?path=/docs/icons-catalog--docs) を参照してください。 + + +HTTP エンドポイントは、キャッシュの無効化を担当します。コマンドが実行されると、構成済みパラメーターと共に指定パス(`/cache/invalidate`)へ HTTP 要求が送信されます。追加のセキュリティ対策があるため、要求には `ApiCacheInvalidationKey` パラメーターの値を持つ `X-CacheInvalidation-Key` ヘッダーが含まれます。これにより、承認された要求のみがキャッシュ無効化処理をトリガーできます。 + +### HTTP エンドポイントの例 + +前述の AppHost コード スニペットでは、`/cache/invalidate` エンドポイントに要求を送信するカスタム HTTP コマンドを定義しました。ASP.NET Core 最小 API プロジェクトは、キャッシュ無効化要求を処理する HTTP エンドポイントを定義します。プロジェクトの _Program.cs_ ファイルから次のコード スニペットを確認してください。 + +```csharp title="Program.cs" +app.MapPost("/cache/invalidate", static async ( + [FromHeader(Name = "X-CacheInvalidation-Key")] string? header, + ICacheService registry, + IConfiguration config) => +{ + var hasValidHeader = config.GetValue("ApiCacheInvalidationKey") is { } key + && header == $"Key: {key}"; + + if (hasValidHeader is false) + { + return Results.Unauthorized(); + } + + await registry.ClearAllAsync(); + + return Results.Ok(); +}); +``` + +前述のコード: + +- `app` 変数が `IApplicationBuilder` のインスタンスであり、HTTP 要求を処理するよう構成済みであることを前提にしています。 +- パス `/cache/invalidate` に HTTP POST エンドポイントをマップします。 +- このエンドポイントは、要求に `X-CacheInvalidation-Key` という名前のヘッダーが含まれることを想定します。 +- 構成から `ApiCacheInvalidationKey` パラメーターの値を取得します。 +- ヘッダー値が期待されるキーと一致しない場合は、未承認応答を返します。 +- ヘッダーが有効な場合は、`ICacheService` の `ClearAllAsync` メソッドを呼び出して、すべてのキャッシュ項目をクリアします。 +- 最後に、HTTP OK 応答を返します。 + +## HTTP 応答本文を返す + +既定では、HTTP コマンドは HTTP ステータス コードを使って成功可否を判定し、応答本文をコマンド結果データとして返しません。`HttpCommandOptions.ResultMode` を設定すると、エンドポイントから空でない応答本文を返す動作にオプトインできます。本文は、[カスタム リソース コマンドからの構造化出力](/ja/fundamentals/custom-resource-commands/#コマンドから構造化出力を返す) と同様に、コマンドの構造化出力として表示されます。 + +次の例では、JSON 応答本文を返す HTTP コマンドを構成します。 + + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddProject("api") + .WithHttpCommand( + path: "/admin/sync", + displayName: "Sync now", + commandOptions: new HttpCommandOptions + { + Method = HttpMethod.Post, + ResultMode = HttpCommandResultMode.Auto + }); + +builder.Build().Run(); +``` + + + + +```typescript title="apphost.ts" +import { createBuilder, HttpCommandResultMode } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +await builder + .addNodeApp('api', './api', 'src/index.ts') + .withHttpCommand('/admin/sync', 'Sync now', { + methodName: 'POST', + resultMode: HttpCommandResultMode.Auto, + }); + +await builder.build().run(); +``` + + + + +エンドポイントは、コマンド呼び出し元に表示すべきペイロードを返せます。たとえば、C# 最小 API エンドポイントでは `MapPost` を使えます。 + +```csharp title="Program.cs" +app.MapPost("/admin/sync", () => +{ + return Results.Json(new + { + status = "Completed", + itemsProcessed = 42 + }); +}); +``` + +TypeScript AppHost サンプルで登録した Node.js アプリも、Express エンドポイントから同じペイロードを返せます。 + +```typescript title="src/index.ts" +import express from 'express'; + +const app = express(); +const port = process.env.PORT || 3000; + +app.post('/admin/sync', (_req, res) => { + res.json({ + status: 'Completed', + itemsProcessed: 42, + }); +}); + +app.listen(port, () => { + console.log(`API listening on port ${port}`); +}); +``` + +`HttpCommandResultMode` は、既定の HTTP コマンド結果ハンドラーが応答本文をどのように解釈するかを制御します。 + +| 結果モード | 動作 | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `None` | 既定値です。応答本文はコマンド結果データとして取り込まれません。 | +| `Auto` | 応答の `Content-Type` から結果形式を推論します。`application/json` や `application/*+json` などの JSON コンテンツ タイプは JSON として返されます。`text/*`、XML、`application/x-www-form-urlencoded` などのテキスト系コンテンツ タイプはテキストとして返されます。その他のコンテンツ タイプは取り込まれません。 | +| `Json` | 応答の `Content-Type` に関係なく、応答本文を JSON コマンド結果データとして返します。 | +| `Text` | 応答の `Content-Type` に関係なく、応答本文をプレーン テキストのコマンド結果データとして返します。 | + +エンドポイントが非成功ステータス コードを返した場合、コマンドは失敗します。`ResultMode` が応答本文を取り込む設定の場合、その本文は失敗結果に添付されるため、呼び出し側はエラー詳細を確認できます。`ResultMode` は `HttpCommandOptions.GetCommandResult` が設定されていない場合にのみ使われます。`GetCommandResult` を指定すると、そのコールバックがコマンドの成功可否、メッセージ、結果データを制御します。 + +### ダッシュボードでの表示例 + +サンプル AppHost と対応する ASP.NET Core 最小 API プロジェクトは、HTTP コマンド実装の両側面を示しています。AppHost を実行すると、ダッシュボードの **Resources** ページにカスタム HTTP コマンドがボタンとして表示されます。コマンドを強調表示(`isHighlighted: true`)するよう指定した場合、このボタンは **Resources** ページの **Actions** 列に表示されます。これにより、次のスクリーンショットのように、ユーザーはダッシュボードから簡単にコマンドを実行できます。 + +Aspire ダッシュボード: 強調表示されたカスタム HTTP コマンドが表示された Resources ページ。 + +`isHighlighted` パラメーターを省略するか `false` に設定すると、コマンドは **Resources** ページの **Actions** 列にある横並び省略記号メニュー(三点メニュー)の下にネストされて表示されます。これにより、UI にボタンが多くなり過ぎることなくコマンドへアクセスできます。次のスクリーンショットは、同じコマンドが省略記号メニューに表示される様子を示しています。 + +Aspire ダッシュボード: 省略記号メニュー内にカスタム HTTP コマンドが表示された Resources ページ。 + +ユーザーがボタンを選択すると、コマンドが実行され、HTTP 要求が指定エンドポイントへ送信されます。ダッシュボードはコマンド実行状態のフィードバックを提供し、ユーザーが結果を監視できるようにします。開始時には、トースト通知が表示されます。 + +Aspire ダッシュボード: カスタム HTTP コマンドの開始を示すトースト通知。 + +コマンドが完了すると、ダッシュボードは状態を更新し、成功したか失敗したかのフィードバックを提供します。次のスクリーンショットは、コマンドの成功実行を示しています。 + +Aspire ダッシュボード: カスタム HTTP コマンドが成功したことを示すトースト通知。 diff --git a/src/frontend/src/content/docs/ja/get-started/aspire-mcp-server.mdx b/src/frontend/src/content/docs/ja/get-started/aspire-mcp-server.mdx new file mode 100644 index 000000000..d712e8662 --- /dev/null +++ b/src/frontend/src/content/docs/ja/get-started/aspire-mcp-server.mdx @@ -0,0 +1,317 @@ +--- +title: Aspire MCP サーバー +description: AI コーディングエージェント向けの Aspire MCP サーバーのツール、セキュリティモデル、トラブルシューティングについて説明します。 +--- + +import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + +:::note +Aspire ダッシュボードに組み込まれていた MCP サーバーは削除されました。[`aspire agent mcp`](/ja/reference/cli/commands/aspire-agent-mcp/) CLI コマンドが Aspire MCP サーバーを起動する方法になりました。 +::: + +Aspire MCP サーバーは、AI コーディングエージェントに実行中の Aspire アプリケーションへの直接ランタイムアクセスを提供します。Model Context Protocol (MCP) を通じて、エージェントはリソースの状態を照会し、ログを読み取り、分散トレースを検査し、コマンドを実行できます — ターミナル出力をコピー&ペーストする必要はありません。 + +`aspire agent init` を実行して **Install Aspire MCP server** を選択すると、MCP サーバーは自動的に設定されます。 + + + AI コーディングエージェント向けにプロジェクトをセットアップするには、[AI コーディングエージェントを活用する](/ja/get-started/ai-coding-agents/)を参照してください。 + + +## 設定 + +`aspire agent init` コマンドは、検出された AI 環境向けの MCP サーバー設定ファイルを作成します: + + + + `.vscode/mcp.json` を作成または更新します: + + ```json title=".vscode/mcp.json" + { + "servers": { + "aspire": { + "type": "stdio", + "command": "aspire", + "args": [ + "agent", + "mcp" + ] + } + } + } + ``` + + + `.mcp.json` を作成または更新します: + + ```json title=".mcp.json" + { + "mcpServers": { + "aspire": { + "command": "aspire", + "args": [ + "agent", + "mcp" + ] + } + } + } + ``` + + + `~/.copilot/mcp-config.json` を作成または更新します: + + ```json title="~/.copilot/mcp-config.json" + { + "mcpServers": { + "aspire": { + "type": "local", + "command": "aspire", + "args": [ + "agent", + "mcp" + ] + } + } + } + ``` + + + `opencode.jsonc` を作成または更新します: + + ```jsonc title="opencode.jsonc" + { + "mcp": { + "aspire": { + "type": "local", + "command": [ + "aspire", + "agent", + "mcp" + ], + "enabled": true + } + } + } + ``` + + + +## ツール + +Aspire MCP サーバーは、AI エージェントに次のツールを提供します: + +| ツール | 説明 | +|------|-------------| +| `list_resources` | 状態、ヘルス状態、ソース、エンドポイント、コマンドを含むすべてのリソースを一覧表示します | +| `list_console_logs` | リソースのコンソールログを一覧表示します | +| `list_structured_logs` | 構造化ログを一覧表示します。リソース名でフィルタリングできます | +| `list_traces` | 分散トレースを一覧表示します。リソース名でフィルタリングできます | +| `list_trace_structured_logs` | 特定のトレースの構造化ログを一覧表示します | +| `execute_resource_command` | リソースコマンド (start、stop、restart) を実行します | +| `list_apphosts` | 検出された AppHost の接続とそのスコープを一覧表示します | +| `select_apphost` | 複数の AppHost が実行中の場合に使用する AppHost を選択します | +| `list_integrations` | 利用可能な Aspire ホスティング統合パッケージを一覧表示します | +| `get_integration_docs` | 特定の統合パッケージのドキュメントを取得します | +| `list_docs` | aspire.dev で利用可能なすべてのドキュメントページを一覧表示します | +| `search_docs` | キーワード検索を使用して aspire.dev のドキュメントを検索します | +| `get_doc` | スラッグでドキュメントページの全内容を取得します | +| `doctor` | Aspire 環境の問題を診断し、セットアップを確認します | +| `refresh_tools` | サーバーにツールリストを再送信するよう要求し、クライアントが再取得できるようにします | + +### MCP からリソースを除外する + +デフォルトでは、すべてのリソース、コンソールログ、テレメトリが MCP サーバーを通じてアクセス可能です。`ExcludeFromMcp()` でアノテーションを付けることで、特定のリソースとそれに関連するテレメトリを除外できます: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var apiservice = builder.AddProject("apiservice") + .ExcludeFromMcp(); + +builder.AddProject("webfrontend") + .WithExternalHttpEndpoints() + .WithReference(apiservice); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const apiservice = await builder + .addProject("apiservice", "./api/ApiService.csproj") + .excludeFromMcp(); + +await builder + .addProject("webfrontend", "./web/Web.csproj") + .withExternalHttpEndpoints() + .withReference(apiservice); + +await builder.build().run(); +``` + + + +## セキュリティ + +Aspire MCP サーバーは、ローカル使用向けに設計された開発時ツールです。 + +### 仕組み + +MCP サーバーは `aspire agent mcp` で起動すると **STDIO トランスポートプロトコル** を使用します: + +- MCP サーバーは AI アシスタントによって起動された **ローカル子プロセス** として実行されます。 +- 通信は **標準入出力 (STDIO) パイプ** を介して行われます。 +- **オープンなネットワークポートはありません** — サーバーはネットワークインターフェースをリッスンしません。 +- **親プロセス (AI アシスタント) のみ** が MCP サーバーと通信できます。 + + + +### アクセス可能なデータ + +MCP サーバーは次のデータへのアクセスを提供します: + +- **リソースメタデータ** — 名前、種類、状態、ヘルス状態、エンドポイント、コマンド +- **コンソールログ** — 標準出力とエラーストリーム +- **構造化ログ** — OpenTelemetry 経由のログエントリ +- **分散トレース** — リソース間のリクエストフロー +- **統合カタログ** — 利用可能なホスティング統合パッケージ +- **製品ドキュメント** — LLMS.txt ベースの公式 `aspire.dev` コンテンツ + +MCP サーバーが公開**しない**情報: + +- ソースコードまたはファイルシステムのコンテンツ +- 環境変数の値やシークレット +- ネットワークトラフィックや生のリクエスト/レスポンスペイロード +- Aspire AppHost プロセスを超えたホストマシンへのアクセス + +### 認証 + +STDIO トランスポート (デフォルト) では、追加の認証は不要です — 通信はローカルプロセスパイプに制限されます。 + +### エンタープライズ向けの考慮事項 + +Aspire MCP サーバーを評価するチーム向けの情報: + +- **開発時のみ** — 公開またはデプロイされたアプリケーションには含まれません +- **外部ネットワークアクセスなし** — STDIO トランスポート使用時はネットワークリスナーなし +- **データのローカル保持** — テレメトリは開発者のマシン上に残ります。AI アシスタントと共有されるデータはアシスタント独自のデータポリシーに準拠します +- **きめ細かいアクセス制御** — `ExcludeFromMcp()` を使用してセンシティブなリソースを制限 +- **永続ストレージなし** — すべてのデータはセッション期間中メモリ内に存在します +- **オープン仕様** — [Model Context Protocol specification](https://modelcontextprotocol.io/) を実装 + +## デプロイに関する考慮事項 + +MCP サーバーは Aspire CLI ツールの一部であり、AppHost とは別に実行されます — デプロイからの明示的な除外は不要です。 + +AppHost に開発専用のリソースが含まれる場合は、`ExecutionContext.IsRunMode` を使用して本番環境から除外してください: + + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var api = builder.AddProject("api"); + +if (builder.ExecutionContext.IsRunMode) +{ + // ローカル開発時のみ使用可能 + builder.AddContainer("dev-tool", "some-dev-image"); +} + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const api = await builder + .addProject("api", "./api/Api.csproj"); + +if (await builder.executionContext.isRunMode()) { + // ローカル開発時のみ使用可能 + await builder.addContainer("dev-tool", "some-dev-image"); +} + +await builder.build().run(); +``` + + + +## 制限事項 + +AI モデルは処理できるデータ量に制限があります。Aspire MCP サーバーはツールから返されるデータを制限する場合があります: + +- 大きなデータフィールド (例: 長いスタックトレース) は切り捨てられる場合があります +- 大量のテレメトリコレクションは古いアイテムを省略して短縮される場合があります + +## トラブルシューティング + +問題が発生した場合は、[GitHub のオープンな MCP Issues](https://github.com/microsoft/aspire/issues?q=is%3Aissue+is%3Aopen+label%3Aarea-mcp) を確認してください。 + +### AppHost の検出 + +MCP サーバーは作業ディレクトリのスコープ内で実行中の AppHost を自動的に検出します: + +- AppHost の変更を継続的に監視します — 再起動は不要です +- `list_apphosts` を使用して検出された AppHost を確認できます +- `select_apphost` を使用して複数の実行中 AppHost を切り替えられます + + + +### エージェントが接続できない場合 + + + +1. Aspire CLI がインストールされていることを確認します: + + ```bash title="Aspire CLI" + aspire --version + ``` + +1. AppHost が実行中であることを確認します: + + ```bash title="Aspire CLI" + aspire start + ``` + +1. MCP サーバーを直接テストします: + + ```bash title="Aspire CLI" + aspire agent mcp + ``` + + エラーなしで起動した場合、問題は AI アシスタントの設定にあります。 + +1. 設定を再生成します: + + ```bash title="Aspire CLI" + aspire agent init + ``` + + + +### Claude Code の問題 + +- プロジェクトルートに `.mcp.json` が存在することを確認してください — `aspire agent init` を実行して再生成できます +- Windows では、`npx` などのコマンドには `cmd.exe /c` プレフィックスが必要です +- 古くなった MCP 接続を再確立するには Claude Code を再起動してください + +## 関連情報 + +- [AI コーディングエージェントを活用する](/ja/get-started/ai-coding-agents/) — プロジェクトを AI エージェント向けにセットアップします +- [aspire agent mcp コマンド](/ja/reference/cli/commands/aspire-agent-mcp/) +- [ダッシュボードのセキュリティに関する考慮事項](/ja/dashboard/security-considerations/) diff --git a/src/frontend/src/content/docs/ja/get-started/faq.mdx b/src/frontend/src/content/docs/ja/get-started/faq.mdx new file mode 100644 index 000000000..ba3541dd8 --- /dev/null +++ b/src/frontend/src/content/docs/ja/get-started/faq.mdx @@ -0,0 +1,191 @@ +--- +title: よくある質問 (FAQ) +description: AppHost、ダッシュボード、統合、TypeScript サポート、デプロイ、そして Aspire と他ツールの比較を含む、Aspire に関するよくある質問への回答です。 +--- + +このページでは、Aspire とは何か、ワークフローにどう適合するのか、何ができるのか、そして他のテクノロジとどう違うのかについて、よくある質問に答えます。 + +## Aspire とは何ですか? + +Aspire は、任意の分散アプリを構成、デバッグ、デプロイするための、エージェント対応かつコードファーストのツールです。言語、スタック、クラウドを問わず、サービスの構築、実行、デバッグ、デプロイをより簡単にします。これは [github.com/microsoft/aspire](https://github.com/microsoft/aspire) で公開されている無償のオープンソースです。 + +その中心的な考え方は **AppHost** です: これは、多数の設定ファイルに情報を分散させる代わりに、サービス、リソース、依存関係、エンドポイント、パラメーター、関係性をコードで宣言する場所です。AppHost は **C# または TypeScript** で記述できるため、Aspire は複数言語を扱うチームに特に適しています。 + +詳しくはこちら: [最初の Aspire アプリを構築する](/ja/get-started/first-app/) + +## Aspire はどのような課題を解決しますか? + +Aspire は、複数サービス開発を理解しやすく、運用しやすくします。接続されたサービスを扱う際の摩擦を減らします。アプリをモデル化し、関連サービスをまとめて起動し、依存関係を接続し、テレメトリを確認し、開発からデプロイまでのワークフローで設定の乖離を減らすための共通の場所をチームに提供します。 + +## AppHost とは何で、なぜそれほど重要なのですか? + +AppHost は Aspire のコントロールセンターです。分散アプリを構成するすべての要素の地図であり、プロジェクト、コンテナー、データベース、エンドポイント、ボリューム、パラメーター、そしてそれらの関係性を含む、アプリ アーキテクチャの **単一の信頼できる情報源** です。同じ AppHost モデルが、インナーループ開発、デプロイ、CI/CD ワークフロー全体で利用されます。 + +詳しくはこちら: [AppHost とは?](/ja/get-started/app-host/) + +## Aspire は最初から具体的に何を提供してくれますか? + +Aspire は、特に有用な 3 つの機能をまとめて提供します: + +1. アプリのリソースと関係性に対する **コードファースト オーケストレーション**。 +2. ログ、メトリクス、トレース、リソース健全性のための **ダッシュボード**。 +3. 作成、実行、公開、デプロイ、調査、トラブルシューティングに対応する **ライフサイクル志向かつエージェント志向の CLI**。 + +ライフサイクルのすべての段階は、人間でもエージェントでも確認および自動化できます。 + +詳しくはこちら: [Aspire ダッシュボード概要](/ja/dashboard/overview/)、[CLI 概要](/ja/reference/cli/overview/)、[統合ギャラリー](/ja/integrations/gallery/) + +## Aspire はどのような統合を提供していますか? + +Aspire は、実システムで頻出する多くの構成要素に対する統合を提供します: データベース、キャッシュ、メッセージング システム、ストレージ サービス、可観測性バックエンド、クラウド リソースなどです。これらの統合により、AppHost でリソースをモデル化し、参照でサービスを接続し、接続文字列、URL、環境変数などの適切な設定を自動注入できます。 + +詳しくはこちら: [統合ギャラリー](/ja/integrations/gallery/)、[`aspire add`](/ja/reference/cli/commands/aspire-add/) + +## Aspire の統合は既存アプリにどう適合しますか? + +統合は加算的です。アプリが新規であっても、すでに本番稼働していても、システムの必要に応じて 1 つずつ導入できます。一般的なパターンは、PostgreSQL、Redis、メッセージ ブローカーなどの共有リソースを AppHost でモデル化し、それを必要なサービスから参照することです。 + +詳しくはこちら: [統合ギャラリー](/ja/integrations/gallery/)、[`aspire init`](/ja/reference/cli/commands/aspire-init/) + +## Aspire ダッシュボードとは何ですか? + +ダッシュボードは開発者体験の中で最も目に見える要素ですが、それが全体ではありません。Aspire アプリを実行すると、ダッシュボードはリソース、ログ、メトリクス、トレース、設定、健全性をリアルタイムで可視化し、システムの挙動を理解できるようにします。 + +詳しくはこちら: [Aspire ダッシュボード概要](/ja/dashboard/overview/) + +## Aspire を使うにはアプリを書き直す必要がありますか? + +**いいえ。** Aspire は、1 つのフレームワークや 1 つのクラウドへの書き換えを求めるのではなく、すでに利用している技術を補完するよう設計されています。C#、Python、JavaScript、Node.js、Go、Java など多言語のアプリをオーケストレーションでき、TypeScript または C# の AppHost をサポートします。デプロイでは、1 つの独自ホスティング モデルを強制するのではなく、構成済みターゲットと統合を通じて動作します。 + +詳しくはこちら: [AppHost とは?](/ja/get-started/app-host/)、[デプロイ概要](/ja/deployment/overview/#compute-environments) + +## Aspire は .NET アプリ専用ですか? + +**いいえ。** .NET は Aspire で特に強力な体験を提供しますが、アプリ モデルは 1 つのフレームワークやランタイムに限定されません。Aspire は複数スタックにまたがるサービス調整を目的に設計されており、TypeScript の AppHost によって既存の JavaScript / TypeScript アプリにも自然に適合します。 + +詳しくはこちら: [TypeScript AppHost サポート](/ja/whats-new/aspire-13-2/#-typescript-apphost-のサポート-プレビュー) + +## AppHost を TypeScript で書けますか? + +**はい。** TypeScript の AppHost (`apphost.ts`) は、既存の JavaScript / TypeScript アプリケーション向けの第一級オプションです。この体験では、`aspire init --language typescript` のようなコマンドや、`addNodeApp`、`addViteApp`、`addJavaScriptApp` のような AppHost API を利用します。 + +詳しくはこちら: [`aspire init`](/ja/reference/cli/commands/aspire-init/)、[TypeScript AppHost サポート](/ja/whats-new/aspire-13-2/#-typescript-apphost-のサポート-プレビュー) + +## Aspire は新規プロジェクト専用ですか? + +**いいえ。** Aspire は段階的に導入できます。既存コードベースに AppHost を追加し、すでにあるリソースを登録し、すべてを一度に書き直すことなく、段階的にシステムを Aspire オーケストレーション下に置けます。 + +詳しくはこちら: [`aspire init`](/ja/reference/cli/commands/aspire-init/) + +## Aspire は Docker Compose とどう違いますか? + +最も端的で確かな答えは次のとおりです: **Docker Compose はコンテナー中心の YAML、Aspire はアプリ モデル中心のコードです。** Compose はコンテナーとその実行時設定の記述に焦点を当てます。Aspire は分散アプリ全体とその関係性の記述に焦点を当て、その上でオーケストレーション、サービス検出、統合、テレメトリ、ダッシュボードによる洞察を重ねます。 + +とはいえ、Docker は Aspire がサポートする多数の計算環境の 1 つであり、Docker Compose 成果物を公開することもできます。 + +詳しくはこちら: [Docker 統合](/ja/integrations/compute/docker/)、[Aspire アプリ ライフサイクル ガイド](/ja/deployment/app-lifecycle/) + +## 「agent-ready」とはどういう意味ですか? + +Aspire は、AI エージェントや Copilot と、人間の開発者と同じくらい自然に連携できるように設計されています。CLI は対話的でありつつ機械可読で、組み込みの MCP (Model Context Protocol) サーバーがアプリ リソース、ログ、トレース、ドキュメントを AI エージェントに公開します。AppHost はコードファーストで構造化されたモデルであり、散在した YAML や設定ファイルではないため、エージェントはアプリ トポロジを読み取り、トレースから問題を診断し、アーキテクチャをプログラム的に変更できます。`aspire agent` コマンドは AI エージェント環境の構成を管理します。 + +詳しくはこちら: [MCP ツール](/ja/reference/cli/commands/aspire-mcp/)、[`aspire agent`](/ja/reference/cli/commands/aspire-agent/) + +## Aspire はどの言語とスタックをサポートしますか? + +Aspire はマルチ言語プラットフォームです。AppHost は **C# または TypeScript** で記述できます。サービスは任意の言語で記述できます: + +- **C# / .NET** — 第一級のプロジェクト参照、サービス既定値、統合 +- **Python** — uv/pip/venv パッケージ管理と Dockerfile 自動生成を備えた `AddPythonApp`、`AddUvicornApp`、`AddPythonModule` +- **JavaScript / TypeScript** — npm/yarn/pnpm 自動検出を備えた `AddJavaScriptApp`、`AddViteApp`、`AddNodeApp` +- **Go, Java, Rust** — コミュニティ ツールキット統合とコード生成パッケージ経由 +- **任意のコンテナー化アプリ** — コンテナーで動作するものはすべて AppHost に追加可能 + +データベース リソースは接続文字列を複数形式 (URI、JDBC、個別プロパティ) で自動公開するため、どの言語でも独自配線なしで接続できます。 + +詳しくはこちら: [統合ギャラリー](/ja/integrations/gallery/) + +## Aspire は Pulumi、Terraform、Bicep と比べてどうですか? + +これらのツールは競合ではなく、**補完関係** と捉えるのが最適です: + +- **Pulumi / Terraform / Bicep** は、インフラ リソースとクラウド環境のプロビジョニングおよび管理に焦点を当てます。 +- **Aspire** は、アプリケーションそのもののモデリングに焦点を当てます: サービス、依存関係、オーケストレーション、検出、テレメトリ、開発者ワークフロー。 + +実践的には次の整理が有効です: Aspire で **アプリケーション トポロジ** を構築・実行・デバッグ・デプロイし、IaC ツールで **環境とプラットフォーム リソース** をプロビジョニングします。 + +詳しくはこちら: [Aspire アプリ ライフサイクル ガイド](/ja/deployment/app-lifecycle/) + +## Aspire は Kubernetes とどう違いますか? + +Kubernetes は本番向けオーケストレーション プラットフォームです。Aspire は、サービスを記述、接続、観測するのを支援するアプリケーション モデルと開発者ワークフローです。Aspire は Kubernetes の 1 対 1 の置き換えではなく、Kubernetes をデプロイ先として対象化し、実際のデプロイ ワークフローに接続できるアプリケーション構成体験です。 + +詳しくはこちら: [デプロイ概要](/ja/deployment/overview/#compute-environments) + +## Aspire は Dapr や他のサービス ランタイム フレームワークとどう違いますか? + +Dapr は pub/sub、バインディング、ステート、サービス呼び出しなどのランタイム ビルディング ブロックを提供します。Aspire はアプリケーション構成、オーケストレーション、統合配線、可観測性に焦点を当てます。両者は課題の異なる層を扱っており、組み合わせが有効な場合には併用できます。 + +詳しくはこちら: [Dapr 統合](/ja/integrations/frameworks/dapr/)、[コミュニティ ディスカッション: Aspire + Dapr](https://github.com/microsoft/aspire/discussions/2735)、[コミュニティ ディスカッション: Aspire + Kubernetes](https://github.com/microsoft/aspire/discussions/6597) + +## Aspire は Docker Compose、Kubernetes、または既存のデプロイ プラットフォームを置き換えますか? + +**いいえ。** Aspire は分散アプリのモデル化、実行、観測、公開、デプロイを支援しますが、実際の計算環境とデプロイ ターゲットは、プラットフォーム戦略に合うものを引き続き選択します。 + +詳しくはこちら: [デプロイ概要](/ja/deployment/overview/#compute-environments)、[`aspire deploy`](/ja/reference/cli/commands/aspire-deploy/) + +## Aspire は開発から本番までのライフサイクルにどう適合しますか? + +Aspire は一貫したライフサイクルをサポートします: + +1. インナーループ開発とデバッグのための **`aspire run/start`**。 +2. 構成済み計算環境へのデプロイのための **`aspire deploy`**。 +3. リリース成果物とデプロイ ワークフローのための **`aspire publish`** と関連 CI/CD ステップ。 + +重要な考え方は、同じ AppHost 設定がこれらの段階を通して流れることです。 + +詳しくはこちら: [Aspire アプリ ライフサイクル ガイド](/ja/deployment/app-lifecycle/)、[`aspire run`](/ja/reference/cli/commands/aspire-run/)、[`aspire deploy`](/ja/reference/cli/commands/aspire-deploy/)、[`aspire publish`](/ja/reference/cli/commands/aspire-publish/) + +## Aspire はホット リロードをサポートしていますか? + +Aspire は `defaultWatchEnabled` 機能フラグによるオプトインの watch モードをサポートします。AppHost の変更後に AppHost 管理アプリケーションを再起動することで、C# と TypeScript の両方の AppHost 言語をサポートします。現在は C# プロジェクト リソースもこの設定で制御されます。他のリソースでは、AppHost を実行したまま、対象リソースのフレームワーク、ランタイム、Aspire CLI アクション、またはダッシュボード アクションを使って、リソース固有のリロード、再起動、リビルドを行ってください。 + +詳しくはこちら: [ホット リロードと watch](/ja/app-host/hot-reload-and-watch/) + +## Aspire 導入時に重要なコマンドは何ですか? + +最短で有用な一覧だけを挙げるなら、まずは次のとおりです: + +- `aspire new` — 新しい Aspire アプリを作成 +- `aspire init` — 既存コードベースで Aspire を初期化 +- `aspire init --language typescript` — JS/TS アプリ向けに TypeScript AppHost を作成 +- `aspire add` — ホスティング統合を追加 +- `aspire run/start` — 開発向けに AppHost を実行 +- `aspire deploy` — 構成済みターゲットへデプロイ +- `aspire publish` — デプロイ成果物を生成 +- `aspire logs` と `aspire otel` — アプリのログと分散トレースを確認 +- `aspire docs` と `aspire doctor` — 確認、学習、トラブルシューティング + +詳しくはこちら: [CLI 概要](/ja/reference/cli/overview/)、[`aspire init`](/ja/reference/cli/commands/aspire-init/)、[`aspire run`](/ja/reference/cli/commands/aspire-run/) + +## デプロイ マニフェストはまだ推奨されていますか? + +**いいえ。** デプロイ マニフェストは非推奨です。現在は `aspire publish` と `aspire deploy` を、サポートされるデプロイ ターゲットおよびワークフローとともに使うのが推奨される経路です。 + +詳しくはこちら: [`aspire publish`](/ja/reference/cli/commands/aspire-publish/)、[`aspire deploy`](/ja/reference/cli/commands/aspire-deploy/) + +## 過剰な主張をせずに、どうすれば Aspire を自信を持って説明できますか? + +次のような表現を推奨します: + +- 「Aspire は、任意の分散アプリを構成、デバッグ、デプロイするための、エージェント対応かつコードファーストのツールです。」 +- 「開発からデプロイまで 1 つのアプリ モデルで管理することで、環境間の設定乖離を減らせます。」 +- 「組み込み可観測性を設定不要で利用可能: ログ、トレース、メトリクス、ヘルスチェックを最初から提供。」 +- 「任意の言語、任意のスタックに対応: AppHost で定義すれば Aspire が接続を構成します。」 +- 「Aspire は既存のツールやクラウドを置き換えるのではなく、それらと連携して動作します。」 + +次のような曖昧な誇張や誤った主張は避けてください: + +- 「Aspire はプラットフォームのすべてを置き換える。」 +- 「Aspire は単なるダッシュボードだ。」 +- 「Aspire は新規の .NET アプリでしか動かない。」 diff --git a/src/frontend/src/content/docs/ja/get-started/resource-mcp-servers.mdx b/src/frontend/src/content/docs/ja/get-started/resource-mcp-servers.mdx new file mode 100644 index 000000000..933528b17 --- /dev/null +++ b/src/frontend/src/content/docs/ja/get-started/resource-mcp-servers.mdx @@ -0,0 +1,135 @@ +--- +title: リソース MCP サーバー +description: Aspire リソースから MCP ツールを公開し、CLI を使用して操作する方法について学びます。 +--- + +import { Aside, Code, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; +import LearnMore from '@components/LearnMore.astro'; + +Aspire リソースは、独自の MCP (Model Context Protocol) サーバーを公開でき、AI コーディング エージェントがデータベース、API、その他のサービスと直接対話できるようにします。例えば、PostgreSQL リソースは SQL クエリ ツールを公開でき、エージェントが会話を終了することなくクエリを実行できます。 + +## 仕組み + +AppHost で `WithMcpServer()` で注釈が付けられたリソースの場合、Aspire は MCP エンドポイントを検出し、そのツールを 2 つの方法で利用可能にします。 + +- **Aspire MCP サーバーを通じて** — リソース ツールが、組み込みの [Aspire MCP サーバー](/ja/get-started/aspire-mcp-server/) ツールと共に自動的にプロキシされます。AI エージェントは追加の構成なしでツール リストにそれらを表示します。 +- **CLI を通じて** — `aspire mcp tools` と `aspire mcp call` を使用してリソース ツールをターミナルから直接検出して呼び出します。 + +## リソースに MCP サーバーを追加する + +`WithMcpServer()` 拡張メソッドを使用して、リソースが MCP サーバーをホストしていることを宣言します。 + + + +```csharp title="AppHost.cs" +#pragma warning disable ASPIREMCP001 + +var builder = DistributedApplication.CreateBuilder(args); + +var db = builder.AddPostgres("db") + .AddDatabase("appdata"); + +// PostgreSQL MCP ツール (SQL クエリ、スキーマ検査など) を公開します +db.WithPostgresMcp(); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const db = await builder + .addPostgres("db") + .addDatabase("appdata"); + +// PostgreSQL MCP ツール (SQL クエリ、スキーマ検査など) を公開します +await db.withPostgresMcp(); + +await builder.build().run(); +``` + + + + + +## 利用可能なツールを検出する + +`aspire mcp tools` を使用して、実行中のリソースによって公開されているすべての MCP ツールをリスト表示します。 + +```bash title="Aspire CLI" +aspire mcp tools +``` + +入力スキーマを含むマシン読み取り可能な出力の場合: + +```bash title="Aspire CLI — JSON 出力" +aspire mcp tools --format Json +``` + +## ツールを呼び出す + +`aspire mcp call` を使用して、リソース上の特定のツールを呼び出します。 + +```bash title="Aspire CLI" +aspire mcp call --input '{"key": "value"}' +``` + +例えば、PostgreSQL リソースで SQL クエリを実行するには: + +```bash title="Aspire CLI — クエリの例" +aspire mcp call appdata query --input '{"sql": "SELECT * FROM users LIMIT 5"}' +``` + +## カスタム MCP サーバー リソース + +MCP プロトコルを実装するコンテナーを MCP 対応リソースとして追加できます。`WithMcpServer()` を使用して、Aspire に MCP エンドポイントの場所を指示します。 + + + +```csharp title="AppHost.cs" +#pragma warning disable ASPIREMCP001 + +var builder = DistributedApplication.CreateBuilder(args); + +// カスタム MCP サーバー コンテナーを追加します +var myMcpServer = builder.AddContainer("my-mcp", "myregistry/my-mcp-server") + .WithHttpEndpoint(targetPort: 8080) + .WithMcpServer("/mcp"); + +builder.Build().Run(); +``` + + +```typescript title="apphost.ts" twoslash +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// カスタム MCP サーバー コンテナーを追加します +const myMcpServer = await builder + .addContainer("my-mcp", "myregistry/my-mcp-server") + .withHttpEndpoint({ targetPort: 8080 }) + .withMcpServer("/mcp"); + +await builder.build().run(); +``` + + + +`WithMcpServer()` メソッドはオプションのパスとエンドポイント名を受け入れます。 + +- `WithMcpServer()` — ルート パスでデフォルトの HTTP エンドポイントを使用します +- `WithMcpServer("/mcp")` — `/mcp` でデフォルトの HTTP エンドポイントを使用します +- `WithMcpServer("/sse", endpointName: "https")` — `/sse` で名前付きエンドポイントを使用します + +## 関連項目 + +- [AI コーディング エージェントを使用する](/ja/get-started/ai-coding-agents/) — プロジェクトを AI エージェント用に設定します +- [Aspire MCP サーバー](/ja/get-started/aspire-mcp-server/) — 組み込みの MCP サーバー ツール +- [ASPIREMCP001 診断](/ja/diagnostics/aspiremcp001/) — 実験的な MCP サーバー API 警告 +- [ASPIREPOSTGRES001 診断](/ja/diagnostics/aspirepostgres001/) — 実験的な PostgreSQL MCP 警告 diff --git a/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx b/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx new file mode 100644 index 000000000..69280dc8c --- /dev/null +++ b/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx @@ -0,0 +1,210 @@ +--- +title: Aspire トラブルシューティング ガイド +description: Docker の問題、ポート競合、サービス検出エラー、TypeScript AppHost の問題など、Aspire の導入時によくあるトラブルへの対処法をまとめています。 +--- + +import { Aside, Code, Steps } from '@astrojs/starlight/components'; +import { Kbd } from 'starlight-kbd/components'; +import LearnMore from '@components/LearnMore.astro'; +import OsAwareTabs from '@components/OsAwareTabs.astro'; + +Aspire の導入で問題が発生していますか? このページでは、開発者がよく遭遇する代表的な問題の解決策を紹介します。 + +## Docker Desktop が起動していない + +**症状**: `aspire run` が停止したままになる、または「container runtime を待機中」のメッセージが表示されます。 + +**解決策**: `aspire run` を実行する前に Docker Desktop (または Podman) を起動してください。システムトレイで Docker が緑色のステータス表示で動作していることを確認します。 + + + +## ポートが既に使用中 + +**症状**: 「Address already in use」や「Port 5000 is already bound.」のようなエラー メッセージが表示されます。 + +**解決策**: + +- 同じポートを使用しているほかのアプリケーションを停止する +- 別の Aspire アプリが動作中の場合は、まず で停止する + +### ポートを使用しているプロセスを特定する方法 + + +
+ + ```powershell + netstat -ano | findstr :5000 + # 最後の列で PID を確認してから: + taskkill /PID /F + ``` + +
+
+ + ```bash + lsof -i :5000 + # 次にプロセスを終了: + kill -9 + ``` +
+ +
+ +## ダッシュボードでサービスが "Unhealthy" と表示される + +**症状**: Aspire ダッシュボードでサービスが赤い状態、または「Unhealthy」と表示されます。 + +**解決策**: + + + +1. ダッシュボードでサービス名をクリックし、ログを確認する +2. 起動時エラーや例外を探す +3. 正常性 チェック エンドポイントが存在することを確認する (例: `/health` が 200 OK を返す) +4. すべての依存関係が正常に起動したことを確認する + + + +## "Connection refused" エラー + +**症状**: フロントエンドが API に接続できず、connection refused エラーが表示されます。 + +**解決策**: AppHost で `WaitFor()` を使用していることを確認してください: + +```csharp title="AppHost.cs" +builder.AddProject("frontend") + .WithReference(apiService) + .WaitFor(apiService); // この行を追加! +``` + +## 環境変数が利用できない + +**症状**: サービスで、注入されるはずの接続文字列や構成を見つけられません。 + +**解決策**: リソース接続に `WithReference()` を使用していることを確認してください。 + +### 例: サービスにデータベースを接続する + +AppHost 側: + +```csharp title="AppHost.cs" +var db = builder.AddPostgres("db"); +var api = builder.AddProject("api") + .WithReference(db); // これにより接続文字列が注入されます +``` + +サービス コード側では、構成から接続文字列を取得します: + +```csharp title="Program.cs" +var connectionString = builder.Configuration.GetConnectionString("db"); +``` + +接続文字列は `ConnectionStrings__db` という名前の環境変数として注入されます。 + +## コンテナー イメージの pull 失敗 + +**症状**: コンテナー イメージの pull 失敗、または「image not found」エラーが表示されます。 + +**解決策**: + +- インターネット接続を確認する +- Docker Hub または使用中のコンテナー レジストリにアクセスできることを確認する +- 企業ネットワークを使用している場合は、Docker Desktop のプロキシ設定を確認する + +### イメージを手動で pull して確認する方法 + +```bash +# まずイメージを手動で pull して確認 +docker pull redis:latest + +# プロキシ環境の場合は Docker Desktop を設定: +# Settings > Resources > Proxies > Manual proxy configuration +``` + +## ダッシュボードが読み込まれない + +**症状**: Aspire ダッシュボードの URL に応答がない、または空白ページが表示されます。 + +**解決策**: + + + +1. コンソール出力で正しいダッシュボード URL を確認する (別ポートが使われる場合があります) +2. ブラウザー拡張機能がページをブロックしていないことを確認する +3. 別のブラウザーまたはシークレット モードで試す +4. ウイルス対策ソフトやファイアウォールが接続をブロックしていないか確認する + + + +## サービス検出が機能しない + +**症状**: サービス同士が名前で見つけられません (例: `http://apiservice` が解決されない)。 + +**解決策**: AppHost で定義したサービス名を、完全に同じ文字列で使用していることを確認してください。 + +### 例: 正しいサービス検出の設定 + +```csharp title="AppHost.cs" +// AppHost 側 +var api = builder.AddProject("apiservice"); // 名前は "apiservice" +``` + +```csharp title="Program.cs" +// 利用側サービスではこの名前を正確に使用 +var client = new HttpClient { BaseAddress = new Uri("http://apiservice") }; +``` + +次の点も確認してください: + +- 両方のサービスで `AddServiceDefaults()` が呼び出されている +- 利用側サービスに AppHost で `.WithReference(api)` が設定されている + + + Aspire のサービス検出の仕組みをより深く理解するには、 + [サービス検出](/ja/fundamentals/service-discovery/)を参照してください。 + + +## TypeScript AppHost の問題 + +### "Command not found" エラー + +Node.js がインストールされ、`PATH` で利用可能であることを確認してください: + +```bash title="Node.js のインストールを確認" +node --version +npm --version +``` + +### SDK コンパイル エラー + +生成された `.modules/` SDK でコンパイル エラーが発生する場合: + +1. Aspire CLI の最新バージョンがインストールされていることを確認します。 +2. `.modules` ディレクトリを削除し、`aspire run` を再実行して SDK を再生成します。 +3. 既知の問題は [Aspire GitHub issues](https://github.com/microsoft/aspire/issues) を確認します。 + +### デバッグ モード + +問題を診断するには、デバッグ出力で実行します: + +```bash title="デバッグ出力で実行" +aspire run --log-level Debug +``` + +### CLI ログ + +Aspire CLI のログは次に保存されます: + + + + + + +## 関連情報 + +- [最初の Aspire アプリを作成する](/ja/get-started/first-app/) +- [正常性 チェック](/ja/fundamentals/health-checks/) +- [サービス検出](/ja/fundamentals/service-discovery/) diff --git a/src/frontend/src/content/docs/ja/languages-and-runtimes/index.mdx b/src/frontend/src/content/docs/ja/languages-and-runtimes/index.mdx new file mode 100644 index 000000000..28eab4e99 --- /dev/null +++ b/src/frontend/src/content/docs/ja/languages-and-runtimes/index.mdx @@ -0,0 +1,110 @@ +--- +title: 言語とランタイム +description: Aspire が AppHost の言語、アプリの言語、ランタイムエコシステムでどのように機能するか、そしてスタックに適した出発点を見つける方法を学びます。 +--- + +import { Aside, Card, CardGrid } from '@astrojs/starlight/components'; + +Aspire は、複数のサービス、ツール、またはランタイムにまたがる分散アプリケーションで良好に機能します。リポジトリに合った AppHost スタイルを選択し、アプリが既に使用している言語とフレームワークを持ち込むことができます。 + +## 実際にはどういう意味か + +- **AppHost** を **C#** または **TypeScript** で記述します。 +- **C#**、**JavaScript**、**Python**、**Go**、**Java**、**Rust**、**PowerShell** などで記述されたサービスとツールをオーケストレーションします。 +- 可観測性が最初のステップの場合は、**Aspire ダッシュボード** から開始します。 +- 既存のアプリを 1 つの言語の周りに書き直さずに Aspire を採用します。 + +## 知っておくべき 2 つの選択肢 + +Aspire が言語をサポートしているかどうかについてユーザーが尋ねるとき、通常は次の 2 つのいずれかを意味しています。 + +- **AppHost の言語**: 分散アプリをどのようにまとめるかを定義するために使用する言語。 +- **アプリケーションの言語またはランタイム**: アプリ内のサービス、フロントエンド、ワーカー、スクリプト、およびツールで使用される言語とランタイム。 + +たとえば、**TypeScript AppHost** を使用して、**Python ワーカー**、**Node.js フロントエンド**、および **C# API** を同じアプリケーションモデルで調整する場合があります。 + + + +## AppHost の言語 + +どちらの AppHost スタイルも同じ Aspire モデルを使用します。主な違いは、オーケストレーションの作成方法と、それが既存のワークフローにどのように適合するかです。 + +| AppHost の言語 | 適している場合 | ここから開始 | サポート | +| --- | --- | --- | --- | +| C# | .NET ツールを既に使用しているか、単一ファイルの AppHost を必要とするチーム | [AppHost とは](/ja/get-started/app-host/) | 公式 | +| TypeScript | Node.js または TypeScript ワークスペースで作業するチーム | [TypeScript AppHost プロジェクト構造](/ja/app-host/typescript-apphost/) | 公式 | + +## アプリケーション言語とランタイムのガイド + +Aspire は、複数の言語で記述されたアプリをオーケストレーションできます。一部のガイドは **言語**(たとえば C# または Python)で記述するのが最適ですが、他のガイドはより広い **ランタイムまたはエコシステム**(たとえば .NET または Node.js)をカバーしています。 + +以下のセクションでは、1 つの実用的な質問に答えるのに最も役立つラベルを使用しています。**「既に持っているスタックで Aspire を使用するにはどうすればよいですか?」** + +### 公式ガイド + + + + Aspire を C# プロジェクト、ファイルベースのアプリ、およびその他の .NET ワークロードで使用します。 + + [C# ファイルベースのアプリ](/ja/integrations/dotnet/csharp-file-based-apps/)または[プロジェクトリソース](/ja/integrations/dotnet/project-resources/)から開始してください。 + + + + Aspire を JavaScript アプリ、Node.js サービス、Vite などのフロントエンドワークフローで使用します。 + + [JavaScript インテグレーション](/ja/integrations/frameworks/javascript/)と[Node.js 用スタンドアロン Aspire ダッシュボード](/ja/dashboard/standalone-for-nodejs/)から開始してください。 + + + + Aspire を Python サービスおよび OpenTelemetry 対応の Python アプリで使用します。 + + [Python インテグレーション](/ja/integrations/frameworks/python/)と[Python 用スタンドアロン Aspire ダッシュボード](/ja/dashboard/standalone-for-python/)から開始してください。 + + + +### Community Toolkit ガイド + + + + Community Toolkit を通じて Go サービスを追加します。 + + [Go インテグレーション](/ja/integrations/frameworks/go-apps/)から開始してください。 + + + + Community Toolkit を通じて Java サービスを追加します。 + + [Java インテグレーション](/ja/integrations/frameworks/java/)から開始してください。 + + + + Community Toolkit を通じて Rust サービスを追加します。 + + [Rust インテグレーション](/ja/integrations/frameworks/rust/)から開始してください。 + + + + Community Toolkit を通じて PowerShell ベースのスクリプトと開発者向けツールを追加します。 + + [PowerShell インテグレーション](/ja/integrations/frameworks/powershell/)から開始してください。 + + + + + +## 既存アプリのダッシュボードガイド + +完全な AppHost を採用する前に可観測性から始めたい場合は、スタンドアロンダッシュボードガイドを使用してください。 + +- [Node.js 用スタンドアロン Aspire ダッシュボード](/ja/dashboard/standalone-for-nodejs/) +- [Python 用スタンドアロン Aspire ダッシュボード](/ja/dashboard/standalone-for-python/) + +## 関連ガイド + +- [マルチ言語アーキテクチャ](/ja/architecture/multi-language-architecture/) +- [既存のアプリに Aspire を追加](/ja/get-started/add-aspire-existing-app/) +- [インテグレーション概要](/ja/integrations/overview/) From 50304641c65ad9835cd12a19db5b22d4029aa901 Mon Sep 17 00:00:00 2001 From: takashiuesaka <61622933+takashiuesaka@users.noreply.github.com> Date: Sat, 16 May 2026 04:02:03 +0000 Subject: [PATCH 2/3] Fixed Copilot review comments and a build break caused by an invalid link. --- src/frontend/src/content/docs/ja/app-host/eventing.mdx | 2 +- .../docs/ja/app-host/migrate-from-docker-compose.mdx | 2 +- .../content/docs/ja/extensibility/interaction-service.mdx | 4 ++-- .../src/content/docs/ja/get-started/aspire-mcp-server.mdx | 2 +- src/frontend/src/content/docs/ja/get-started/faq.mdx | 6 +++--- .../content/docs/ja/get-started/resource-mcp-servers.mdx | 2 +- .../src/content/docs/ja/get-started/troubleshooting.mdx | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/frontend/src/content/docs/ja/app-host/eventing.mdx b/src/frontend/src/content/docs/ja/app-host/eventing.mdx index b6de529cf..77ef2a5eb 100644 --- a/src/frontend/src/content/docs/ja/app-host/eventing.mdx +++ b/src/frontend/src/content/docs/ja/app-host/eventing.mdx @@ -405,7 +405,7 @@ builder.OnAfterPublish((@event, ct) => ``` -発行中に何が起こるかの詳細については、[発行とデプロイの概要](/ja/deployment/overview/)を参照してください。 +発行中に何が起こるかの詳細については、[発行とデプロイの概要](/ja/deployment/deploy-with-aspire/)を参照してください。 ### リソース停止イベント diff --git a/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx b/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx index 626b8494b..a2627ef26 100644 --- a/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx +++ b/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx @@ -706,6 +706,6 @@ Aspire への移行後: - [Aspire インテグレーション](/ja/integrations/overview/) を探索してカスタムコンテナ構成を置き換えます - [正常性チェック](/ja/fundamentals/health-checks/) を設定してより良い監視を実現します -- 本番環境向けの [デプロイメントオプション](/ja/deployment/overview/) について学びます +- 本番環境向けの [デプロイメントオプション](/ja/deployment/deploy-with-aspire/) について学びます - 分散アプリケーション [テスト](/ja/testing/overview/) を検討します - [テレメトリー構成](/ja/fundamentals/telemetry/) をレビューして可観測性を実現します diff --git a/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx b/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx index 75fa17d7d..80eb9f8f2 100644 --- a/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx +++ b/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx @@ -120,7 +120,7 @@ var result = await interactionService.PromptMessageBoxAsync( It's worth noting that **Markdown** is _supported_ (and demonstrated here) in the message body. - Cool, [📖 learn more](/extensibility/interaction-service/)... + Cool, [📖 learn more](/ja/extensibility/interaction-service/)... """, new MessageBoxInteractionOptions { @@ -203,7 +203,7 @@ var tasks = new List { Intent = MessageIntent.Error, LinkText = "Troubleshoot", - LinkUrl = "/get-started/troubleshooting/" + LinkUrl = "/ja/get-started/troubleshooting/" }) }; diff --git a/src/frontend/src/content/docs/ja/get-started/aspire-mcp-server.mdx b/src/frontend/src/content/docs/ja/get-started/aspire-mcp-server.mdx index d712e8662..fce8566eb 100644 --- a/src/frontend/src/content/docs/ja/get-started/aspire-mcp-server.mdx +++ b/src/frontend/src/content/docs/ja/get-started/aspire-mcp-server.mdx @@ -241,7 +241,7 @@ const api = await builder if (await builder.executionContext.isRunMode()) { // ローカル開発時のみ使用可能 - await builder.addContainer("dev-tool", "some-dev-image"); + await builder.addContainer("dev-tool", { image: "some-dev-image", tag: "latest" }); } await builder.build().run(); diff --git a/src/frontend/src/content/docs/ja/get-started/faq.mdx b/src/frontend/src/content/docs/ja/get-started/faq.mdx index ba3541dd8..29ea492d2 100644 --- a/src/frontend/src/content/docs/ja/get-started/faq.mdx +++ b/src/frontend/src/content/docs/ja/get-started/faq.mdx @@ -57,7 +57,7 @@ Aspire は、実システムで頻出する多くの構成要素に対する統 **いいえ。** Aspire は、1 つのフレームワークや 1 つのクラウドへの書き換えを求めるのではなく、すでに利用している技術を補完するよう設計されています。C#、Python、JavaScript、Node.js、Go、Java など多言語のアプリをオーケストレーションでき、TypeScript または C# の AppHost をサポートします。デプロイでは、1 つの独自ホスティング モデルを強制するのではなく、構成済みターゲットと統合を通じて動作します。 -詳しくはこちら: [AppHost とは?](/ja/get-started/app-host/)、[デプロイ概要](/ja/deployment/overview/#compute-environments) +詳しくはこちら: [AppHost とは?](/ja/get-started/app-host/)、[デプロイ概要](/ja/deployment/deploy-with-aspire/#compute-environments) ## Aspire は .NET アプリ専用ですか? @@ -120,7 +120,7 @@ Aspire はマルチ言語プラットフォームです。AppHost は **C# ま Kubernetes は本番向けオーケストレーション プラットフォームです。Aspire は、サービスを記述、接続、観測するのを支援するアプリケーション モデルと開発者ワークフローです。Aspire は Kubernetes の 1 対 1 の置き換えではなく、Kubernetes をデプロイ先として対象化し、実際のデプロイ ワークフローに接続できるアプリケーション構成体験です。 -詳しくはこちら: [デプロイ概要](/ja/deployment/overview/#compute-environments) +詳しくはこちら: [デプロイ概要](/ja/deployment/deploy-with-aspire/#compute-environments) ## Aspire は Dapr や他のサービス ランタイム フレームワークとどう違いますか? @@ -132,7 +132,7 @@ Dapr は pub/sub、バインディング、ステート、サービス呼び出 **いいえ。** Aspire は分散アプリのモデル化、実行、観測、公開、デプロイを支援しますが、実際の計算環境とデプロイ ターゲットは、プラットフォーム戦略に合うものを引き続き選択します。 -詳しくはこちら: [デプロイ概要](/ja/deployment/overview/#compute-environments)、[`aspire deploy`](/ja/reference/cli/commands/aspire-deploy/) +詳しくはこちら: [デプロイ概要](/ja/deployment/deploy-with-aspire/#compute-environments)、[`aspire deploy`](/ja/reference/cli/commands/aspire-deploy/) ## Aspire は開発から本番までのライフサイクルにどう適合しますか? diff --git a/src/frontend/src/content/docs/ja/get-started/resource-mcp-servers.mdx b/src/frontend/src/content/docs/ja/get-started/resource-mcp-servers.mdx index 933528b17..7c06526e9 100644 --- a/src/frontend/src/content/docs/ja/get-started/resource-mcp-servers.mdx +++ b/src/frontend/src/content/docs/ja/get-started/resource-mcp-servers.mdx @@ -112,7 +112,7 @@ const builder = await createBuilder(); // カスタム MCP サーバー コンテナーを追加します const myMcpServer = await builder - .addContainer("my-mcp", "myregistry/my-mcp-server") + .addContainer("my-mcp", { image: "myregistry/my-mcp-server", tag: "latest" }) .withHttpEndpoint({ targetPort: 8080 }) .withMcpServer("/mcp"); diff --git a/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx b/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx index 69280dc8c..e0430f958 100644 --- a/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx +++ b/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx @@ -17,7 +17,7 @@ Aspire の導入で問題が発生していますか? このページでは、 **解決策**: `aspire run` を実行する前に Docker Desktop (または Podman) を起動してください。システムトレイで Docker が緑色のステータス表示で動作していることを確認します。 From db906127dfdc9f1d1b02a12f5cfe64d3eaebfb85 Mon Sep 17 00:00:00 2001 From: takashiuesaka <61622933+takashiuesaka@users.noreply.github.com> Date: Sat, 16 May 2026 12:32:41 +0000 Subject: [PATCH 3/3] Fixed build breaks and verified that the copied code in all committed files matches the original source code. --- .../ja/app-host/certificate-configuration.mdx | 2 +- .../docs/ja/app-host/container-files.mdx | 2 +- .../docs/ja/app-host/executable-resources.mdx | 6 ++--- .../app-host/migrate-from-docker-compose.mdx | 10 +++---- .../ja/app-host/persistent-containers.mdx | 2 +- .../ja/extensibility/custom-resources.mdx | 10 +++---- .../ja/extensibility/interaction-service.mdx | 4 +-- .../multi-language-integration-authoring.mdx | 26 +++++++++---------- .../fundamentals/custom-resource-commands.mdx | 6 ++--- .../docs/ja/get-started/troubleshooting.mdx | 2 +- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/frontend/src/content/docs/ja/app-host/certificate-configuration.mdx b/src/frontend/src/content/docs/ja/app-host/certificate-configuration.mdx index 122f21b98..23a05ad12 100644 --- a/src/frontend/src/content/docs/ja/app-host/certificate-configuration.mdx +++ b/src/frontend/src/content/docs/ja/app-host/certificate-configuration.mdx @@ -509,7 +509,7 @@ import { createBuilder, CertificateTrustScope } from './.modules/aspire.js'; const builder = await createBuilder(); -await builder.addContainer("service", "myimage") +await builder.addContainer("service", { image: "myimage", tag: "latest" }) .withCertificateTrustScope(CertificateTrustScope.None); await builder.build().run(); diff --git a/src/frontend/src/content/docs/ja/app-host/container-files.mdx b/src/frontend/src/content/docs/ja/app-host/container-files.mdx index d769f4da2..bfb66e385 100644 --- a/src/frontend/src/content/docs/ja/app-host/container-files.mdx +++ b/src/frontend/src/content/docs/ja/app-host/container-files.mdx @@ -353,7 +353,7 @@ const builder = await createBuilder(); const frontend = await builder.addViteApp("frontend", "../frontend"); -const api = await builder.addProject("api", "./Api/Api.csproj", "https") +const api = await builder.addProject("api", "./Api/Api.csproj") .publishWithContainerFiles(frontend, "./wwwroot"); await builder.build().run(); diff --git a/src/frontend/src/content/docs/ja/app-host/executable-resources.mdx b/src/frontend/src/content/docs/ja/app-host/executable-resources.mdx index e2f871d2b..d0e6f7cf8 100644 --- a/src/frontend/src/content/docs/ja/app-host/executable-resources.mdx +++ b/src/frontend/src/content/docs/ja/app-host/executable-resources.mdx @@ -193,7 +193,7 @@ import { createBuilder } from './.modules/aspire.js'; const builder = await createBuilder(); // バックエンド API -const api = await builder.addProject("api", "./Api/Api.csproj", "https") +const api = await builder.addProject("api", "./Api/Api.csproj") .withExternalHttpEndpoints(); // Vercel CLI を使用するフロントエンド @@ -295,7 +295,7 @@ import { createBuilder } from './.modules/aspire.js'; const builder = await createBuilder(); const app = await builder.addExecutable("frontend", "npm", ".", ["start", "--port", "3000"]) - .publishAsDockerFile(); + .publishAsDockerFile(async () => {}); ``` @@ -334,7 +334,7 @@ import { createBuilder } from './.modules/aspire.js'; const builder = await createBuilder(); const app = await builder.addExecutable("frontend", "npm", ".", ["start"]) - .publishAsDockerFile(); + .publishAsDockerFile(async () => {}); ``` diff --git a/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx b/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx index a2627ef26..b5af98dc6 100644 --- a/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx +++ b/src/frontend/src/content/docs/ja/app-host/migrate-from-docker-compose.mdx @@ -136,14 +136,14 @@ const database = (await builder.addPostgres("postgres") .addDatabase("myapp"); // 適切な依存関係を備えた API プロジェクトを追加 -const api = await builder.addProject("api", "./MyApp.Api/MyApp.Api.csproj", "https") +const api = await builder.addProject("api", "./MyApp.Api/MyApp.Api.csproj") .withHttpEndpoint({ port: 5000 }) .withHttpHealthCheck("/health") .withReference(database, "DefaultConnection") .waitFor(database); // 依存関係を備えたフロントエンドプロジェクトを追加 -const frontend = await builder.addProject("frontend", "./MyApp.Frontend/MyApp.Frontend.csproj", "https") +const frontend = await builder.addProject("frontend", "./MyApp.Frontend/MyApp.Frontend.csproj") .withHttpEndpoint({ port: 3000 }) .withReference(api) .withEnvironment("API_URL", api.getEndpoint("http")) @@ -342,7 +342,7 @@ const database = (await builder.addPostgres("db")) const cache = await builder.addRedis("cache"); -const app = await builder.addContainer("app", "myapp:latest") +const app = await builder.addContainer("app", { image: "myapp", tag: "latest" }) .withReference(database) .withReference(cache) .withEnvironment("API_KEY", apiKey) @@ -445,11 +445,11 @@ import { createBuilder } from './.modules/aspire.js'; const builder = await createBuilder(); -const app = await builder.addContainer("app", "myapp:latest") +const app = await builder.addContainer("app", { image: "myapp", tag: "latest" }) .withVolume("/data", { name: "app-data", isReadOnly: true }) .withBindMount("./config", "/app/config", { isReadOnly: true }); -const worker = await builder.addContainer("worker", "myworker:latest") +const worker = await builder.addContainer("worker", { image: "myworker", tag: "latest" }) .withVolume("/shared", { name: "app-data" }); await builder.build().run(); diff --git a/src/frontend/src/content/docs/ja/app-host/persistent-containers.mdx b/src/frontend/src/content/docs/ja/app-host/persistent-containers.mdx index 97b52ae27..7f87e5f06 100644 --- a/src/frontend/src/content/docs/ja/app-host/persistent-containers.mdx +++ b/src/frontend/src/content/docs/ja/app-host/persistent-containers.mdx @@ -49,7 +49,7 @@ const postgres = await builder.addPostgres("postgres") const db = postgres.addDatabase("inventorydb"); -await builder.addProject("inventory", "./InventoryService/InventoryService.csproj", "https") +await builder.addProject("inventory", "./InventoryService/InventoryService.csproj") .withReference(db); await builder.build().run(); diff --git a/src/frontend/src/content/docs/ja/extensibility/custom-resources.mdx b/src/frontend/src/content/docs/ja/extensibility/custom-resources.mdx index 16ad8dd59..2a70f8049 100644 --- a/src/frontend/src/content/docs/ja/extensibility/custom-resources.mdx +++ b/src/frontend/src/content/docs/ja/extensibility/custom-resources.mdx @@ -182,7 +182,7 @@ public static IResourceBuilder AddMailDev( ダッシュボードに表示される状態更新を公開するには、`ResourceNotificationService` を使用します: -```csharp title="Publishing state updates" +```csharp title="状態更新の公開" await notification.PublishUpdateAsync(resource, state => state with { State = KnownResourceStates.Running, @@ -207,7 +207,7 @@ Aspire は `KnownResourceStates` にいくつかの既知の状態を提供し `ResourceStateSnapshot` を使用してカスタム状態を作成できます: -```csharp title="Custom state example" +```csharp title="カスタム状態の例" await notification.PublishUpdateAsync(resource, state => state with { State = new ResourceStateSnapshot("Indexing", KnownResourceStateStyles.Info) @@ -218,7 +218,7 @@ await notification.PublishUpdateAsync(resource, state => state with `WithInitialState` を使ってダッシュボードでの初期表示を設定します: -```csharp title="Setting initial state" +```csharp title="初期状態の設定" return builder.AddResource(resource) .WithInitialState(new CustomResourceSnapshot { @@ -235,7 +235,7 @@ return builder.AddResource(resource) リソースがローカル開発専用である場合は、デプロイ マニフェストから除外します: -```csharp title="Excluding from deployment" +```csharp title="デプロイから除外" return builder.AddResource(resource) .ExcludeFromManifest(); ``` @@ -275,7 +275,7 @@ Aspire Dashboard でのリソース表示の詳細は、[Dashboard overview](/ja `WithIconName` を使うと、ダッシュボードでリソースにカスタム アイコンを表示できます。任意の [Fluent UI system icon](https://github.com/microsoft/fluentui-system-icons/blob/main/icons_filled.md) を使用できます: -```csharp title="Setting custom dashboard icons" +```csharp title="カスタム ダッシュボード アイコンの設定" return builder.AddResource(resource) .WithIconName("mail"); // "mail" の Fluent UI アイコンを使用 diff --git a/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx b/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx index 80eb9f8f2..75fa17d7d 100644 --- a/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx +++ b/src/frontend/src/content/docs/ja/extensibility/interaction-service.mdx @@ -120,7 +120,7 @@ var result = await interactionService.PromptMessageBoxAsync( It's worth noting that **Markdown** is _supported_ (and demonstrated here) in the message body. - Cool, [📖 learn more](/ja/extensibility/interaction-service/)... + Cool, [📖 learn more](/extensibility/interaction-service/)... """, new MessageBoxInteractionOptions { @@ -203,7 +203,7 @@ var tasks = new List { Intent = MessageIntent.Error, LinkText = "Troubleshoot", - LinkUrl = "/ja/get-started/troubleshooting/" + LinkUrl = "/get-started/troubleshooting/" }) }; diff --git a/src/frontend/src/content/docs/ja/extensibility/multi-language-integration-authoring.mdx b/src/frontend/src/content/docs/ja/extensibility/multi-language-integration-authoring.mdx index 0c5e73fec..8796d4dbc 100644 --- a/src/frontend/src/content/docs/ja/extensibility/multi-language-integration-authoring.mdx +++ b/src/frontend/src/content/docs/ja/extensibility/multi-language-integration-authoring.mdx @@ -94,7 +94,7 @@ public static IResourceBuilder WithDataVolume( これにより、次の TypeScript API が生成されます: -```typescript title="TypeScript — Generated SDK" {5-8} +```typescript title="TypeScript — 生成された SDK" {5-8} import { createBuilder } from './.modules/aspire.js'; const builder = await createBuilder(); @@ -118,7 +118,7 @@ await app.run(); 静的エクスポートでは、生成される capability ID はアセンブリ名と有効な export ID を使用します。次のメソッドは、異なる C# 型を対象にしていても衝突します: -```csharp title="C# — Duplicate capability ID" +```csharp title="C# — 重複する capability ID" [AspireExport("configure")] public static void ConfigureBuilder( this IDistributedApplicationBuilder builder, @@ -138,7 +138,7 @@ public static IResourceBuilder ConfigureDatabase( ランタイム capability には異なる export ID を使い、異なる対象型上でも生成される SDK メソッド名を簡潔に保ちたい場合は `MethodName` を使います: -```csharp title="C# — Unique capability IDs with SDK method names" +```csharp title="C# — SDK メソッド名付きの一意な capability ID" [AspireExport("configureBuilder", MethodName = "configure")] public static void ConfigureBuilder( this IDistributedApplicationBuilder builder, @@ -200,7 +200,7 @@ public sealed class MyDatabaseDatabaseResource(string name, MyDatabaseResource p 例えば、両方の種類のプロパティを持つ C# クラス: -```csharp title="C# — Mixed property kinds" +```csharp title="C# — 混在するプロパティ種別" [AspireExport(ExposeProperties = true)] public class MyCallbackContext { @@ -214,7 +214,7 @@ public class MyCallbackContext これにより、次の TypeScript インターフェイスが生成されます: -```typescript title="TypeScript — Generated interface" +```typescript title="TypeScript — 生成されたインターフェイス" export interface MyCallbackContext { toJSON(): MarshalledHandle; resource(): Promise; // getter のみ → async メソッド @@ -224,7 +224,7 @@ export interface MyCallbackContext { TypeScript AppHost の作成者は、getter のみのプロパティを関数として呼び出します: -```typescript title="TypeScript — Consuming the generated API" +```typescript title="TypeScript — 生成された API の利用" const resource = await context.resource(); const tags = context.tags; // 可変コレクションでは await は不要 ``` @@ -310,7 +310,7 @@ public static IResourceBuilder WithMyCallback( 生成される TypeScript API は async アロー関数を受け取ります: -```typescript title="TypeScript — Consuming the callback API" +```typescript title="TypeScript — コールバック API の利用" await myResource.withMyCallback(async (context) => { const resource = await context.resource(); const env = await context.environment(); @@ -424,7 +424,7 @@ await ( 既定では、エクスポート名はフィールド名またはプロパティ名と一致します。上書きするには `Name` プロパティを使用します: -```csharp title="C# — Override exported name" +```csharp title="C# — エクスポート名を上書き" [AspireValue("MyModels", Name = "lite")] public static readonly MyModel Lite = new() { Name = "my-model-lite", Version = "1" }; ``` @@ -444,7 +444,7 @@ public static readonly MyModel Lite = new() { Name = "my-model-lite", Version = 一部の C# オーバーロードでは、TypeScript で表現できない型(例: 非シリアル化コンテキストを持つ `Action` デリゲート、補間文字列ハンドラー、C# 固有の型)を使用します。こうしたものには `[AspireExportIgnore]` を付けます: -```csharp title="C# — Exclude incompatible overloads" +```csharp title="C# — 互換性のないオーバーロードを除外" // このオーバーロードは TypeScript で動作する。単純なパラメーター [AspireExport("withConnectionStringLimit", Description = "Sets connection limit")] public static IResourceBuilder WithConnectionStringLimit( @@ -474,7 +474,7 @@ public static IResourceBuilder WithConnectionStringLimit( パラメーターが複数型を受け入れる場合は、`[AspireUnion]` を使って有効な選択肢を宣言します: -```csharp title="C# — Union type parameter" +```csharp title="C# — Union 型パラメーター" [AspireExport("withEnvironment", Description = "Sets an environment variable")] public static IResourceBuilder WithEnvironment( this IResourceBuilder builder, @@ -547,14 +547,14 @@ CLI が `.csproj` パスを検出すると、プロジェクトをローカル 1. テスト用の TypeScript AppHost を作成します: - ```bash title="Create test AppHost" + ```bash title="テスト用 AppHost を作成" mkdir test-apphost && cd test-apphost aspire init --language typescript ``` 2. `aspire.config.json` にプロジェクト参照として統合を追加します: - ```json title="JSON — aspire.config.json (packages section)" + ```json title="JSON — aspire.config.json(packages セクション)" { "packages": { "MyCompany.Hosting.MyDatabase": "../src/MyCompany.Hosting.MyDatabase/MyCompany.Hosting.MyDatabase.csproj" @@ -564,7 +564,7 @@ CLI が `.csproj` パスを検出すると、プロジェクトをローカル 3. `aspire run` を実行して TypeScript SDK を生成します: - ```bash title="Generate SDK and start" + ```bash title="SDK を生成して開始" aspire run ``` diff --git a/src/frontend/src/content/docs/ja/fundamentals/custom-resource-commands.mdx b/src/frontend/src/content/docs/ja/fundamentals/custom-resource-commands.mdx index 3039900ab..b3049b99d 100644 --- a/src/frontend/src/content/docs/ja/fundamentals/custom-resource-commands.mdx +++ b/src/frontend/src/content/docs/ja/fundamentals/custom-resource-commands.mdx @@ -819,7 +819,7 @@ return { `WithCommand` で登録した任意のコマンドは、組み込みの `start`、`stop`、`restart` コマンドを含め、`aspire resource` コマンドを使ってターミナルから呼び出せます。 -```bash title="Terminal" +```bash title="ターミナル" aspire resource [--apphost ] ``` @@ -831,14 +831,14 @@ CLI はステータス出力とペイロード出力を分離するため、結 これにより、構造化ペイロードを `jq` に直接パイプしたり、ファイルへリダイレクトしたり、終了コードで分岐したりできます。 -```bash title="Terminal — Pipe a JSON payload through jq" +```bash title="ターミナル — JSON ペイロードを jq にパイプ" $ aspire resource cache issue-access-token | jq -r .token ey7WqGxk2vL... ``` ステータス メッセージ `Access token issued.` は stderr に書き込まれるため、stdout はパイプ用にクリーンなまま保たれます。 -```bash title="Terminal — Use the exit code in a script" +```bash title="ターミナル — スクリプトで終了コードを使用" if aspire resource db migrate > migrations.json; then echo "Applied $(jq length migrations.json) migrations." else diff --git a/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx b/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx index e0430f958..a7e7b1bb5 100644 --- a/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx +++ b/src/frontend/src/content/docs/ja/get-started/troubleshooting.mdx @@ -121,7 +121,7 @@ var connectionString = builder.Configuration.GetConnectionString("db"); docker pull redis:latest # プロキシ環境の場合は Docker Desktop を設定: -# Settings > Resources > Proxies > Manual proxy configuration +# 設定 > リソース > プロキシ > 手動プロキシ構成 ``` ## ダッシュボードが読み込まれない