コンテナー ファイル
Aspire には、ファイルやディレクトリをコンテナーへ挿入する API が用意されており、カスタムの構成ファイル、スクリプト、証明書、その他のアセットを使用してコンテナー化されたリソースを構成できます。相補的な API が 2 つあります:
WithContainerFiles:aspire run実行時に、コンテナーの起動時点で開発用のファイルをコンテナーへ挿入します。PublishWithContainerFiles:aspire publish実行時に、発行用のビルド成果物として、あるリソースのコンテナーから別のリソースのコンテナーへファイルをコピーします。
開発時にファイルを挿入する
Section titled “開発時にファイルを挿入する”WithContainerFiles 拡張メソッドは、指定した宛先パスにあるコンテナー内のファイルやディレクトリを作成または更新します。ニーズに応じて、宣言的にファイルを定義するインライン エントリ、ホスト ファイル システムからコピーするためのソース パス、動的にファイルを生成する非同期コールバックという 3 つの方法をサポートします。
インライン エントリ
Section titled “インライン エントリ”インライン エントリのオーバーロードを使用すると、ContainerFileSystemItem オブジェクトを使ってファイルやディレクトリを宣言的に定義できます。これは、ファイル内容がビルド時点で分かっている場合や、文字列リテラルとして表現できる場合に便利です。
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();前の例では:
- 指定した内容を持つ JSON 構成ファイルが
/app/config/appsettings.jsonに作成されます。 - 実行可能なシェル スクリプトを含む入れ子の
scriptsディレクトリが/app/config/scripts/に作成されます。
ソース パス
Section titled “ソース パス”ソース パスのオーバーロードを使用すると、ホスト マシン上のディレクトリからコンテナーへファイルをコピーできます。これは、既存の構成ファイルやアセットがディスク上にある場合に便利です。
var builder = DistributedApplication.CreateBuilder(args);
builder.AddContainer("myapp", "myapp:latest") .WithContainerFiles("/app/config", "./config-files");
builder.Build().Run();ソース パスがルート化された絶対パスでない限り、AppHost プロジェクト ディレクトリからの相対パスとして解釈されます。ソース ディレクトリ内のすべてのファイルは、起動時にコンテナー内の宛先パスへコピーされます。
非同期コールバック
Section titled “非同期コールバック”コールバック オーバーロードを使用すると、コンテナーの起動時に動的にファイルを生成できます。このコールバックは ContainerFileSystemCallbackContext を受け取り、IServiceProvider とリソースの IResource モデルにアクセスできるため、サービスを解決したりアプリ モデルを検査したりできます。
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();このコールバックはコンテナーが起動するたびに呼び出されるため、生成されるファイルには常に現在の状態が反映されます。
ファイルの種類
Section titled “ファイルの種類”WithContainerFiles API は、抽象 ContainerFileSystemItem クラスを基底とする型階層を使用します。各型は、異なる種類のファイル システム エントリを表します。
ContainerFile
Section titled “ContainerFile”ContainerFile は標準的なファイルを表します。ファイル データを指定するには、Contents (文字列) または SourcePath (ホスト上の絶対パス) のいずれかを設定します。両方を同時に設定することはできません。
// インライン内容を持つファイルvar configYaml = new ContainerFile{ Name = "config.yaml", Contents = "key: value"};
// ホスト ファイル システムから取得するファイルvar dataCsv = new ContainerFile{ Name = "data.csv", SourcePath = "/path/to/data.csv"};この特定のファイルの作成に失敗してもコンテナーを起動できるようにするには、ContinueOnError を true に設定します:
var optionalJson = new ContainerFile{ Name = "optional-config.json", Contents = "{}", ContinueOnError = true};ContainerDirectory
Section titled “ContainerDirectory”ContainerDirectory は、入れ子にした ContainerFileSystemItem エントリを含められるディレクトリを表し、任意のディレクトリ ツリーを構築できます。
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 を構築することもできます:
var assetsDir = new ContainerDirectory{ Name = "assets", Entries = ContainerDirectory.GetFileSystemItemsFromPath( "/path/to/assets", searchOptions: SearchOption.AllDirectories)};ContainerOpenSSLCertificateFile
Section titled “ContainerOpenSSLCertificateFile”ContainerOpenSSLCertificateFile は、PEM エンコードされた公開証明書を表します。Aspire は、証明書ファイルをコンテナーへ配置するだけでなく、同じディレクトリ内に OpenSSL 互換のシンボリック リンク ([subject hash].[n]) も自動で作成します。これは openssl rehash の実行と同等です。これにより、証明書の検証に OpenSSL を使用するコンテナーが、この証明書を自動的に検出できるようになります。
builder.AddContainer("myapp", "myapp:latest") .WithContainerFiles("/certs", [ new ContainerOpenSSLCertificateFile { Name = "ca-cert.pem", Contents = pemCertificateString } ]);ファイルのアクセス許可と所有者
Section titled “ファイルのアクセス許可と所有者”WithContainerFiles のすべてのオーバーロードは、ファイルの所有者とアクセス許可を制御するための省略可能なパラメーターを受け取ります。
所有者とグループ
Section titled “所有者とグループ”defaultOwner と defaultGroup パラメーターは、作成されるすべてのファイルとディレクトリに適用される既定の UID と GID を設定します。どちらも指定しない場合は 0 (root) が既定値です。任意の ContainerFileSystemItem にある Owner および Group プロパティを使用して、個々の項目の所有者を上書きできます。
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);この例では、shared.txt は既定の owner/group である 33 を継承し、user-only.txt は UID/GID 1000 で上書きします。
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 を直接設定できます:
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);永続コンテナー
Section titled “永続コンテナー”ContainerLifetime.Persistent を持つコンテナーでは、コンテナー ファイル エントリの内容を変更するとコンテナーが再作成されます。意図しないコンテナー再起動を避けるため、WithContainerFiles で書き込まれるデータは、特定のアプリ モデル構成に対して冪等になるようにしてください。
発行時にファイルを挿入する
Section titled “発行時にファイルを挿入する”PublishWithContainerFiles メソッドは、aspire publish の実行中に、あるリソースのコンテナーから別のリソースのコンテナーへファイルをコピーします。これは、発行時にコンテナーへファイルを挿入するための推奨アプローチです。
代表的なユース ケースは、シングルページ アプリケーション (SPA) や静的な JavaScript フロントエンドを、本番デプロイ用のリバース プロキシまたは Web サーバー コンテナーに埋め込むことです。開発時には、Vite や React のようなフロントエンド アプリは通常、スタンドアロンの開発サーバーとして実行されます。一方、本番環境では、コンパイル済みの静的アセットはバックエンド API や Nginx のような専用 Web サーバーから配信されることが一般的です。PublishWithContainerFiles は、ビルド済みのフロントエンド出力を発行プロセスの一部として配信先コンテナーへコピーすることで、このギャップを埋めます。手動でのファイル コピーやマルチステージ Dockerfile は不要です。
バックエンドにフロントエンドを埋め込む
Section titled “バックエンドにフロントエンドを埋め込む”var builder = DistributedApplication.CreateBuilder(args);
var frontend = builder.AddViteApp("frontend", "../frontend");
var api = builder.AddProject<Projects.Api>("api") .PublishWithContainerFiles(frontend, "./wwwroot");
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();
const const frontend: ViteAppResource
frontend = 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("frontend", "../frontend");
const 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.publishWithContainerFiles(source: IResourceWithContainerFiles, destinationPath: string): ProjectResource
Configures the resource to copy container files from the specified source resource during publishing.
publishWithContainerFiles(const frontend: ViteAppResource
frontend, "./wwwroot");
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();この例では:
frontendリソースはコンテナー内でビルドされ、コンパイル済みの JavaScript、CSS、HTML を生成します。- 発行時に、Aspire はそれらのファイルを
frontendコンテナーからapiコンテナー内の./wwwrootへコピーします。 - 結果として得られる
apiコンテナーには API コードとフロントエンドの静的アセットの両方が含まれ、アプリケーション全体を配信する準備が整います。
YARP からフロントエンドを配信する
Section titled “YARP からフロントエンドを配信する”フロントエンド アセットを専用のリバース プロキシ コンテナーへ埋め込むこともできます:
var builder = DistributedApplication.CreateBuilder(args);
var frontend = builder.AddViteApp("frontend", "../frontend");
var nginx = builder.AddYarp("gateway") .PublishWithStaticFiles(frontend);
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();
const const frontend: ViteAppResource
frontend = 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("frontend", "../frontend");
const const nginx: YarpResource
nginx = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addYarp(name: string): YarpResource
Adds a YARP container to the application model.
addYarp("gateway") .YarpResource.publishWithStaticFiles(resourceWithFiles: IResourceWithContainerFiles): YarpResource
In publish mode, generates a Dockerfile that copies static files from the specified resource into /app/wwwroot.
publishWithStaticFiles(const frontend: ViteAppResource
frontend);
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();これにより、外部ボリューム マウントや実行時のファイル コピーを必要としない、フロントエンド アプリケーションを配信する自己完結型の Nginx コンテナーが生成されます。
PublishWithContainerFiles は発行モードでのみ適用され、aspire run 中は効果がありません。宛先リソースは IContainerFilesDestinationResource (例: ProjectResource) を実装し、ソース リソースは IResourceWithContainerFiles を実装している必要があります。
ソース パスをカスタマイズする
Section titled “ソース パスをカスタマイズする”既定では、ソース リソースは構成済みの出力パスに基づいて、自身のコンテナーからファイルをエクスポートします。ソース コンテナー内のどのパスからコピーするかを指定するには、WithContainerFilesSource を使用します:
var frontend = builder.AddViteApp("frontend", "../frontend") .WithContainerFilesSource("/app/dist");
var api = builder.AddProject<Projects.Api>("api") .PublishWithContainerFiles(frontend, "./wwwroot");以前に構成したソース パスを削除してから新しいものを追加するには、ClearContainerFilesSources を使用します。