Watch Aspire live streamsドキュメント試す

既存のアプリに Aspire を追加する

新しいテンプレートを基準にソリューションを作り直す代わりに、すでにあるアプリへ Aspire を追加しましょう。最短ルートは aspire init と AI コーディング エージェントの組み合わせです。これによりサービスを自動検出し、 AppHost へ配線できます。より細かく制御したい場合は、下に手動手順も用意しています。

なぜ既存のアプリに Aspire を追加するのか?

Section titled “なぜ既存のアプリに Aspire を追加するのか?”

分散アプリケーションが大きくなるほど、ローカル開発は壊れやすいスクリプト、コピペされた接続文字列、起動順序の暗黙知の寄せ集めになりがちです。 Aspire は、すでに持っているリソースに対して単一のオーケストレーション層を提供します。関係性をコードで一度定義すれば、サービス検出、構成の注入、起動順序、ダッシュボードでの可視化を Aspire が処理します。

Aspire は段階的にも導入できます。まずは、コンテナー、データベース、キャッシュ、キュー、バックグラウンド ワーカー、ローカル開発コマンドのように、手作業では整合を保ちにくい部分からモデリングしてください。準備ができたらテレメトリを追加し、アプリの成長に合わせてモデルを深めていけます。

開始する前に、次を確認してください:

  • Aspire CLI をインストール済み
  • Aspire を追加する既存のアプリケーションまたはワークスペースがあること
  • 既存サービスが必要とするランタイムとツール

推奨: 「aspireify」スキル付きの AI コーディング エージェントを使う

Section titled “推奨: 「aspireify」スキル付きの AI コーディング エージェントを使う”

既存アプリへ Aspire を追加する最速の方法は、 aspire init で骨組みを作ってから、配線を aspireify エージェント スキルに任せることです。このスキルは、リソース検出、依存関係の配線、 OpenTelemetry の設定、検証を自動で行います。

  1. リポジトリのルートで aspire init を実行します:

    Aspire を初期化する
    aspire init

    プロンプトが表示されたら AppHost 言語( C# または TypeScript)を選ぶか、 --language csharp / --language typescript を指定します。コマンドは最小構成の AppHost、 aspire.config.json、および aspireify スキルをエージェントのスキル ディレクトリへ作成します。ルートに既存の package.json がある JavaScript または TypeScript アプリでは、既存アプリ パッケージのモジュール設定を変更しないように、TypeScript AppHost は aspire-apphost/ サブフォルダーに作成されます。

  2. AI コーディング エージェントに aspireify スキルの実行を依頼します。エージェントは次を行います:

    • リポジトリをスキャンし、既存のプロジェクト、サービス、コンテナー、インフラストラクチャを検出する
    • 検出したリソース、含める対象、その他の確認事項を開始前に質問する
    • WithReference、 WaitFor、エンドポイント、ボリュームを使って AppHost へ配線する
    • 各サービスに ServiceDefaults を追加し、 OpenTelemetry を構成する
    • aspire start を実行してセットアップを検証する
  3. エージェントが成功を報告したら、自分でも aspire start を実行してダッシュボードを開き、想定どおりか確認します。問題があればエージェントに伝えてください。 Aspire にはトラブルシューティング用のツールが豊富にあります。

aspire init コマンドと aspireify スキルの詳細は、 CLI リファレンス: aspire init を参照してください。


配線を完全に制御したい場合や、 aspireify スキルが内部で何をしているか理解したい場合は、次の手動手順に従ってください。これは初期セットアップ後に AppHost を拡張またはカスタマイズする際のリファレンスにもなります。

AppHost はオーケストレーション層です。ここでの選択はオーケストレーションの記述方法を変えるものであり、 Aspire が何をオーケストレーションできるかを制限するものではありません。

TypeScript AppHost は、リポジトリが Node.js ワークスペース中心の場合や、 TypeScript でパス ベースのオーケストレーションを記述したい場合に適しています。

  • apphost.mts で管理。既存の JavaScript または TypeScript アプリでは、aspire init が aspire-apphost/ の下に作成します
  • npm、 pnpm、 yarn、 Bun など主要なパッケージ マネージャーで実行可能
  • 既存のパッケージ マネージャーおよびモノレポのワークフローに自然に適合
  1. TypeScript 言語オプションを付けて、ワークスペース ルートで aspire init を実行します:

    TypeScript AppHost で Aspire を初期化する
    aspire init --language typescript
  2. ホスティング統合を追加します:

    ホスティング統合を追加する
    aspire add redis
    aspire add postgres
  3. aspire-apphost/apphost.mts でリソースを配線します:

    apphost.mts
    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 cache: RedisResource
    cache
    = 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 db: PostgresDatabaseResource
    db
    = (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
    ('mydb');
    const
    const api: ProjectResource
    api
    = await
    const builder: IDistributedApplicationBuilder
    builder
    .
    IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: {
    launchProfileOrOptions?: string | ProjectResourceOptions;
    }): ProjectResource (+1 overload)

    Adds a .NET project resource

    addProject
    ('api', '../src/Api/MyApp.Api.csproj')
    .
    ProjectResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
    connectionName?: string;
    optional?: boolean;
    name?: string;
    } | undefined): ProjectResource (+1 overload)

    Adds a reference to another resource

    withReference
    (
    const db: PostgresDatabaseResource
    db
    )
    .
    ProjectResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
    connectionName?: string;
    optional?: boolean;
    name?: string;
    } | undefined): ProjectResource (+1 overload)

    Adds a reference to another resource

    withReference
    (
    const cache: RedisResource
    cache
    )
    .
    ProjectResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): ProjectResource

    Waits for another resource to be ready

    waitFor
    (
    const db: PostgresDatabaseResource
    db
    );
    await
    const builder: IDistributedApplicationBuilder
    builder
    .
    IDistributedApplicationBuilder.addViteApp(name: string, appDirectory: string, options?: {
    runScriptName?: string;
    }): ViteAppResource (+1 overload)

    Adds a Vite app to the distributed application builder.

    addViteApp
    ('web', '../services/web')
    .
    ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
    connectionName?: string;
    optional?: boolean;
    name?: string;
    } | undefined): ViteAppResource (+1 overload)

    Adds a reference to another resource

    withReference
    (
    const api: ProjectResource
    api
    )
    .
    ExecutableResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): ViteAppResource

    Waits for another resource to be ready

    waitFor
    (
    const api: ProjectResource
    api
    );
    await
    const builder: IDistributedApplicationBuilder
    builder
    .
    IDistributedApplicationBuilder.build(): DistributedApplication

    Builds the distributed application

    build
    ().
    DistributedApplication.run(cancellationToken?: cancellationToken): void

    Runs the distributed application

    run
    ();

セットアップ後の典型的なワークスペース構成は次のとおりです:

  • aspire.config.json (new)
  • package.json (Aspire 委譲スクリプトを追加)
  • ディレクトリaspire-apphost/ (new)
    • apphost.mts
    • ディレクトリ.aspire/modules/
      • …
    • package.json
    • tsconfig.apphost.json
  • ディレクトリservices/
    • ディレクトリweb/
      • package.json
      • ディレクトリsrc/
        • …
  • ディレクトリsrc/
    • ディレクトリApi/
      • MyApp.Api.csproj

シナリオ: ホスティング統合を使った既存サービス

Section titled “シナリオ: ホスティング統合を使った既存サービス”

この方法は、実行したいワークロードに対するファーストクラスなリソース型がすでに Aspire にある場合に使います。これによりアプリケーション モデルは、汎用シェル コマンドへ落とし込むのではなく、そのサービスが何で何に依存するかに集中できます。

代表例は Node.js アプリ、 Vite フロントエンド、 Python ワーカー、 Uvicorn ベース API です。

apphost.mts — Existing services with hosting integrations
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 cache: RedisResource
cache
= 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 api: UvicornAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addUvicornApp(name: string, appDirectory: string, app: string): UvicornAppResource

Adds a Uvicorn-based Python application to the distributed application builder with HTTP endpoint configuration.

addUvicornApp
('api', '../services/api', 'main:app')
.
UvicornAppResource.withUv(options?: {
install?: boolean;
args?: string[];
} | undefined): UvicornAppResource (+1 overload)

Adds a UV environment setup task to ensure the virtual environment exists before running the Python application.

withUv
()
.
ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): UvicornAppResource (+1 overload)

Adds a reference to another resource

withReference
(
const cache: RedisResource
cache
)
.
ExecutableResource.withExternalHttpEndpoints(): UvicornAppResource

Marks existing http or https endpoints on a resource as external.

withExternalHttpEndpoints
();
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addPythonApp(name: string, appDirectory: string, scriptPath: string): PythonAppResource

Adds a Python application to the application model.

addPythonApp
('worker', '../workers/inventory-sync', 'worker.py')
.
ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): PythonAppResource (+1 overload)

Adds a reference to another resource

withReference
(
const cache: RedisResource
cache
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addViteApp(name: string, appDirectory: string, options?: {
runScriptName?: string;
}): ViteAppResource (+1 overload)

Adds a Vite app to the distributed application builder.

addViteApp
('web', '../services/web')
.
ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): ViteAppResource (+1 overload)

Adds a reference to another resource

withReference
(
const api: UvicornAppResource
api
)
.
ExecutableResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): ViteAppResource

Waits for another resource to be ready

waitFor
(
const api: UvicornAppResource
api
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

ワークロードに専用ホスティング API がまだない場合でも、 AddExecutable または addExecutable を使って実行可能リソースとしてモデル化すれば、同じアプリケーション モデルに参加させられます。

ファーストクラス ワークロードのガイダンスは、 JavaScript integration、 Python integration、 Multi-language architecture を参照してください。

シナリオ: 既存コンテナーと共有インフラストラクチャ

Section titled “シナリオ: 既存コンテナーと共有インフラストラクチャ”

この方法は、重要な境界がランタイム環境そのものにある場合に使います。たとえば公開済みコンテナー イメージ、共有データベース、キャッシュ、キュー、既存インフラストラクチャ トポロジなどです。まず共有リソースをモデル化し、その後それらを利用するワークロードを接続して、接続性、構成、起動順序を明示化します。

対象インフラストラクチャに対するファーストクラス統合が Aspire にある場合は、最初にそれを追加します:

ホスティング統合を追加する
aspire add postgres
aspire add redis
apphost.mts — Existing containers and shared infrastructure
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 db: PostgresDatabaseResource
db
= (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
('orders');
const
const cache: RedisResource
cache
= 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 api: ContainerResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addContainer(name: string, image: string | AddContainerOptions): ContainerResource

Adds a container resource to the application.

addContainer
('api', {
AddContainerOptions.image?: string | undefined
image
: 'ghcr.io/contoso/orders-api',
AddContainerOptions.tag?: string | undefined
tag
: 'latest' })
.
ContainerResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): ContainerResource (+1 overload)

Adds a reference to another resource

withReference
(
const db: PostgresDatabaseResource
db
)
.
ContainerResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): ContainerResource (+1 overload)

Adds a reference to another resource

withReference
(
const cache: RedisResource
cache
)
.
ContainerResource.withHttpEndpoint(options?: {
port?: number;
targetPort?: number;
name?: string;
env?: string;
isProxied?: boolean;
} | undefined): ContainerResource (+1 overload)

Adds an HTTP endpoint

withHttpEndpoint
({
port?: number | undefined
port
: 8080,
targetPort?: number | undefined
targetPort
: 8080,
name?: string | undefined
name
: 'http' });
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addContainer(name: string, image: string | AddContainerOptions): ContainerResource

Adds a container resource to the application.

addContainer
('web', {
AddContainerOptions.image?: string | undefined
image
: 'ghcr.io/contoso/orders-web',
AddContainerOptions.tag?: string | undefined
tag
: 'latest' })
.
ContainerResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): ContainerResource (+1 overload)

Adds a reference to another resource

withReference
(
const api: ContainerResource
api
)
.
ContainerResource.withHttpEndpoint(options?: {
port?: number;
targetPort?: number;
name?: string;
env?: string;
isProxied?: boolean;
} | undefined): ContainerResource (+1 overload)

Adds an HTTP endpoint

withHttpEndpoint
({
port?: number | undefined
port
: 3000,
targetPort?: number | undefined
targetPort
: 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
();

このシナリオは、 Docker Compose がすでにシステムの形を表現できている場合に使います。 Compose ファイルを、ワークロード、共有インフラストラクチャ、公開ポート、依存関係のエッジを示す地図として扱い、その関係を AppHost へ再定義します。

目標は、各フィールドを 1 行ずつ翻訳することではなく、同じ関係性をより明確なリソース モデルとして表現することです。

docker-compose.yml
services:
postgres:
image: postgres:latest
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=mydb
ports:
- "5432:5432"
api:
build: ./api
environment:
- DATABASE_URL=postgres://postgres:postgres@postgres:5432/mydb
depends_on:
- postgres
web:
build: ./web
environment:
- API_URL=http://api:8080
depends_on:
- api

これらのシナリオは出発点であり、排他的なモードではありません。実際の多くのアプリでは、ワークロード固有リソース、コンテナー、共有インフラストラクチャ、プロジェクト パス参照、ときどき必要なカスタム コマンドを 1 つのアプリケーション モデルに混在させます。重要なのは、依存関係、エンドポイント、構成、起動動作が明示化されることです。

さらに例を確認するには、 Project resources、 C# file-based apps、 Executable resources、 Migrate from Docker Compose を参照してください。

テレメトリ構成を追加する(任意)

Section titled “テレメトリ構成を追加する(任意)”

テレメトリは AppHost 自体ではなく、それを出力するワークロード側で構成します。 Aspire はローカル オーケストレーション時に OTLP 宛先と共有ダッシュボードを各ワークロードへ提供しますが、各サービスでは引き続きランタイムに適した可観測性ライブラリを使用します。

アプリに Node.js または TypeScript サービスが含まれる場合は、サービス内で OpenTelemetry を構成し、 Aspire が提供する OTLP エンドポイントへ送信します。

  1. OpenTelemetry パッケージをインストールします:

    OpenTelemetry パッケージをインストールする
    npm install @opentelemetry/api @opentelemetry/sdk-node \
    @opentelemetry/auto-instrumentations-node \
    @opentelemetry/exporter-trace-otlp-grpc \
    @opentelemetry/exporter-metrics-otlp-grpc
  2. テレメトリのブートストラップ ファイルを作成します:

    telemetry.ts
    import { NodeSDK } from '@opentelemetry/sdk-node';
    import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
    const sdk = new NodeSDK({
    instrumentations: [getNodeAutoInstrumentations()],
    });
    sdk.start();
  3. アプリのエントリ ポイントで最初にそれを import します:

    src/server.ts
    import './telemetry';
    import express from 'express';
    const app = express();

他のランタイムでは、すでに利用しているランタイムに合う OpenTelemetry SDK またはインストルメンテーション ライブラリを使い、ローカル オーケストレーション時に Aspire が提供する OTLP エンドポイントへテレメトリを送信してください。

AppHost で必要なリソースと関係性を表現できたら、 Aspire CLI で全体をまとめて起動します。

  1. AppHost を含むディレクトリで、次を実行します:

    Aspire でアプリケーションを実行する
    aspire run
  2. CLI が AppHost を検出し、リソースを起動し、ダッシュボード URL を出力するまで待ちます。

    出力例
    Finding apphosts...
    Dashboard: https://localhost:17068/login?t=example
    Press CTRL+C to stop the apphost and exit.
  3. ブラウザーでダッシュボードを開き、次を確認します:

    • すべてのリソースが正常に起動する
    • サービス依存関係が想定どおりの順序で表示される
    • ログ、トレース、メトリクスを確認できる
    • エンドポイントと環境変数が正しい
  4. フロントエンドから API 呼び出し、ワーカー ジョブ、データベース アクセスなど、実際に重視するアプリ フローを実行して確認します。

  5. ターミナルで ⌃+CControl + CControl + C を押してシステムを停止します。

ここまでで、コア ワークフローは完成です。アプリが必要とするリソースを記述し、それらに依存するワークロードを接続し、 Aspire にローカル開発時のシステム全体を実行させます。ここからは、アプリ全体を一度に作り替えるのではなく、段階的にセットアップを深めていけます。