Aspire で外部実行可能ファイルをホストする
Aspire では、AddExecutable メソッドを使用して、プロジェクトと一緒に外部の実行可能アプリケーションをホストできます。この機能は、Node.js アプリケーション、Python スクリプト、特殊な CLI ツールなどの実行可能アプリケーションやツールを分散アプリケーションに統合する必要がある場合に役立ちます。
実行可能リソースを使用する場合
Section titled “実行可能リソースを使用する場合”実行可能リソースは、次のような場合に使用します:
- コンテナーではなくホスト上でアプリケーションやツールを直接実行する。
- コマンドライン ツールやユーティリティをアプリケーションに統合する。
- 他のリソースが依存する外部プロセスを実行する。
- ローカル開発サーバーを提供するツールを使って開発する。
一般的な例は次のとおりです:
- フロントエンド開発サーバー: Vercel CLI や webpack dev server のようなツール。
- 言語固有のアプリケーション: Node.js アプリ、Python スクリプト、Go アプリケーション。
- データベース ツール: マイグレーション ユーティリティやデータベース シーダー。
- ビルド ツール: アセット プロセッサーやコード ジェネレーター。
基本的な使用方法
Section titled “基本的な使用方法”AddExecutable メソッドでは、リソース名、実行可能ファイルのパス、そして必要に応じてコマンドライン引数と作業ディレクトリが必要です:
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();import { createBuilder } from './.aspire/modules/aspire.mjs';
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 アプリケーションを起動します。
リソース依存関係と環境構成
Section titled “リソース依存関係と環境構成”コマンドライン引数は AddExecutable 呼び出しで直接指定でき、リソース依存関係の環境変数も構成できます。実行可能リソースは他のリソースを参照し、その接続情報にアクセスできます。
AddExecutable 呼び出しで引数を指定する
Section titled “AddExecutable 呼び出しで引数を指定する”var builder = DistributedApplication.CreateBuilder(args);
// 引数を AddExecutable で直接指定しますvar app = builder.AddExecutable( "vercel-dev", "vercel", ".", "dev", "--listen", "3000");import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
// 引数を addExecutable で直接指定しますconst const app: ExecutableResource
app = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("vercel-dev", "vercel", ".", ["dev", "--listen", "3000"]);環境変数を使ったリソース依存関係
Section titled “環境変数を使ったリソース依存関係”他のリソースに依存する引数には、環境変数を使用します:
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 を提供しますimport { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const redis: RedisResource
redis = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addRedis(name: string, options?: { port?: number; password?: string | ParameterResource;}): RedisResource (+1 overload)
Adds a Redis container to the application model.
addRedis("cache");const const postgres: PostgresDatabaseResource
postgres = (await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addPostgres(name: string, options?: { userName?: string | ParameterResource; password?: string | ParameterResource; port?: number;}): PostgresServerResource (+1 overload)
Adds a PostgreSQL resource to the application model. A container is used for local development.
addPostgres("postgres")).PostgresServerResource.addDatabase(name: string, options?: { databaseName?: string;} | undefined): PostgresDatabaseResource (+1 overload)
Adds a PostgreSQL database to the application model.
addDatabase("appdb");
const const app: ExecutableResource
app = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("worker", "python", ".", ["worker.py"]) .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ExecutableResource (+1 overload)
Adds a reference to another resource
withReference(const redis: RedisResource
redis) // ConnectionStrings__cache を提供します .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ExecutableResource (+1 overload)
Adds a reference to another resource
withReference(const postgres: PostgresDatabaseResource
postgres); // ConnectionStrings__appdb を提供します1 つのリソースが別のリソースに依存している場合、WithReference は依存先リソースの接続詳細を含む環境変数を渡します。たとえば、worker 実行可能ファイルが redis と postgres を参照すると、これらのリソースへの接続文字列を含む ConnectionStrings__cache および ConnectionStrings__appdb 環境変数が提供されます。
特定のエンドポイント情報にアクセスする
Section titled “特定のエンドポイント情報にアクセスする”実行可能ファイルに接続情報を渡す方法をさらに細かく制御するには、次のようにします:
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); });import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder, type EndpointProperty = "Url" | "Host" | "IPV4Host" | "Port" | "Scheme" | "TargetPort" | "HostAndPort" | "TlsEnabled"const EndpointProperty: { readonly Url: "Url"; readonly Host: "Host"; readonly IPV4Host: "IPV4Host"; readonly Port: "Port"; readonly Scheme: "Scheme"; readonly TargetPort: "TargetPort"; readonly HostAndPort: "HostAndPort"; readonly TlsEnabled: "TlsEnabled";}
Enum Aspire.Hosting.ApplicationModel.EndpointProperty
EndpointProperty } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const redis: RedisResource
redis = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addRedis(name: string, options?: { port?: number; password?: string | ParameterResource;}): RedisResource (+1 overload)
Adds a Redis container to the application model.
addRedis("cache");const const redisEndpoint: EndpointReference
redisEndpoint = await const redis: RedisResource
redis.ContainerResource.getEndpoint(name: string): EndpointReference
Gets an endpoint reference
getEndpoint("tcp");const const redisHost: EndpointReferenceExpression
redisHost = await const redisEndpoint: EndpointReference
redisEndpoint.EndpointReference.property(property: EndpointProperty): EndpointReferenceExpression
Gets the specified property expression of the endpoint.
property(const EndpointProperty: { readonly Url: "Url"; readonly Host: "Host"; readonly IPV4Host: "IPV4Host"; readonly Port: "Port"; readonly Scheme: "Scheme"; readonly TargetPort: "TargetPort"; readonly HostAndPort: "HostAndPort"; readonly TlsEnabled: "TlsEnabled";}
Enum Aspire.Hosting.ApplicationModel.EndpointProperty
EndpointProperty.type Host: "Host"
Host);const const redisPort: EndpointReferenceExpression
redisPort = await const redisEndpoint: EndpointReference
redisEndpoint.EndpointReference.property(property: EndpointProperty): EndpointReferenceExpression
Gets the specified property expression of the endpoint.
property(const EndpointProperty: { readonly Url: "Url"; readonly Host: "Host"; readonly IPV4Host: "IPV4Host"; readonly Port: "Port"; readonly Scheme: "Scheme"; readonly TargetPort: "TargetPort"; readonly HostAndPort: "HostAndPort"; readonly TlsEnabled: "TlsEnabled";}
Enum Aspire.Hosting.ApplicationModel.EndpointProperty
EndpointProperty.type Port: "Port"
Port);
const const app: ExecutableResource
app = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("app", "node", ".", ["app.js"]) .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ExecutableResource (+1 overload)
Adds a reference to another resource
withReference(const redis: RedisResource
redis) .ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): ExecutableResource
Sets an environment variable
withEnvironment("REDIS_HOST", const redisHost: EndpointReferenceExpression
redisHost) .ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): ExecutableResource
Sets an environment variable
withEnvironment("REDIS_PORT", const redisPort: EndpointReferenceExpression
redisPort);実践例: Vercel CLI
Section titled “実践例: Vercel CLI”次は、Vercel CLI を使用して、バックエンド API とともにフロントエンド アプリケーションをホストする完全な例です:
var builder = DistributedApplication.CreateBuilder(args);
// バックエンド APIvar api = builder.AddProject<Projects.Api>("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();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
// バックエンド APIconst const api: ProjectResource
api = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: { launchProfileOrOptions?: ProjectResourceOptions;}): ProjectResource (+1 overload)
Adds a .NET project resource
addProject("api", "./Api/Api.csproj") .ProjectResource.withExternalHttpEndpoints(): ProjectResource
Marks existing http or https endpoints on a resource as external.
withExternalHttpEndpoints();
// Vercel CLI を使用するフロントエンドconst const frontend: ExecutableResource
frontend = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("vercel-dev", "vercel", ".", ["dev", "--listen", "3000"]) .ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): ExecutableResource
Sets an environment variable
withEnvironment("API_URL", const api: ProjectResource
api.ProjectResource.getEndpoint(name: string): EndpointReference
Gets an endpoint reference
getEndpoint("http")) .ExecutableResource.withHttpEndpoint(options?: { port?: number; targetPort?: number; name?: string; env?: string; isProxied?: boolean;} | undefined): ExecutableResource (+1 overload)
Adds an HTTP endpoint
withHttpEndpoint({ port?: number | undefined
port: 3000, name?: string | undefined
name: "http" });
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();エンドポイントを構成する
Section titled “エンドポイントを構成する”実行可能リソースは、他のリソースが参照できる HTTP エンドポイントを公開できます:
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"));import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const frontend: ExecutableResource
frontend = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("webpack-dev", "npx", ".", ["webpack", "serve", "--port", "8080", "--host", "0.0.0.0"]) .ExecutableResource.withHttpEndpoint(options?: { port?: number; targetPort?: number; name?: string; env?: string; isProxied?: boolean;} | undefined): ExecutableResource (+1 overload)
Adds an HTTP endpoint
withHttpEndpoint({ port?: number | undefined
port: 8080, name?: string | undefined
name: "http" });
// 別のサービスがフロントエンドを参照できますconst const e2eTests: ExecutableResource
e2eTests = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("playwright", "npx", ".", ["playwright", "test"]) .ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): ExecutableResource
Sets an environment variable
withEnvironment("BASE_URL", const frontend: ExecutableResource
frontend.ExecutableResource.getEndpoint(name: string): EndpointReference
Gets an endpoint reference
getEndpoint("http"));実行可能ファイルの環境変数を構成します:
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(); });import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const app: ExecutableResource
app = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("api", "uvicorn", ".", ["main:app", "--reload", "--host", "0.0.0.0"]) .ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): ExecutableResource
Sets an environment variable
withEnvironment("DEBUG", "true") .ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): ExecutableResource
Sets an environment variable
withEnvironment("LOG_LEVEL", "info") .ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): ExecutableResource
Sets an environment variable
withEnvironment("START_TIME", new var Date: DateConstructornew () => Date (+3 overloads)
Date().Date.toISOString(): string
Returns a date as a string value in ISO format.
toISOString());PublishAsDockerFile を使った発行
Section titled “PublishAsDockerFile を使った発行”本番環境へデプロイするには、実行可能リソースをコンテナー化する必要があります。実行可能ファイルをどのようにパッケージ化するかを指定するには、PublishAsDockerFile メソッドを使用します:
var builder = DistributedApplication.CreateBuilder(args);
var app = builder.AddExecutable( "frontend", "npm", ".", "start", "--port", "3000") .PublishAsDockerFile();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const app: ExecutableResource
app = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("frontend", "npm", ".", ["start", "--port", "3000"]) .ExecutableResource.publishAsDockerFile(configure: (obj: ContainerResource) => Promise<void>): ExecutableResource
Publishes an executable as a Docker file
publishAsDockerFile(async () => {});PublishAsDockerFile() を呼び出すと、Aspire は発行プロセス中に Dockerfile を生成します。独自の Dockerfile を指定して、この動作をカスタマイズすることもできます:
発行用のカスタム Dockerfile
Section titled “発行用のカスタム Dockerfile”実行可能ファイルの作業ディレクトリに Dockerfile を作成します:
FROM node:22-alpineWORKDIR /appCOPY package*.json ./RUN npm ci --only=productionCOPY . .EXPOSE 3000CMD ["npm", "start"]次に、AppHost でそれを参照します:
var builder = DistributedApplication.CreateBuilder(args);
var app = builder.AddExecutable("frontend", "npm", ".", "start") .PublishAsDockerFile([new DockerfileBuildArg("NODE_ENV", "production")]);import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.aspire/modules/aspire.mjs';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const app: ExecutableResource
app = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addExecutable(name: string, command: string, workingDirectory: string, args: string[]): ExecutableResource
Adds an executable resource to the application model.
addExecutable("frontend", "npm", ".", ["start"]) .ExecutableResource.publishAsDockerFile(configure: (obj: ContainerResource) => Promise<void>): ExecutableResource
Publishes an executable as a Docker file
publishAsDockerFile(async () => {});ベスト プラクティス
Section titled “ベスト プラクティス”実行可能リソースを扱う際は、次の点を意識してください:
- 明示的なパスを使用する: 信頼性を高めるため、可能な場合は実行可能ファイルへの完全パスを使用します。
- 依存関係を処理する:
WithReferenceを使用して適切な依存関係を確立します。 - 明示的な開始を構成する: 自動的に開始すべきでない実行可能ファイルには
WithExplicitStart()を使用します。 - デプロイに備える: 本番シナリオでは常に
PublishAsDockerFile()を使用します。 - 環境を分離する: 機密な構成にはコマンドライン引数ではなく環境変数を使用します。
- リソース名を工夫する: 実行可能ファイルの目的が明確に分かる説明的な名前を使用します。