コンテンツにスキップ
Docs Try Aspire
Docs Try

コンテナー ファイル

Aspire には、ファイルやディレクトリをコンテナーへ挿入する API が用意されており、カスタムの構成ファイル、スクリプト、証明書、その他のアセットを使用してコンテナー化されたリソースを構成できます。相補的な API が 2 つあります:

  • WithContainerFiles: aspire run 実行時に、コンテナーの起動時点で開発用のファイルをコンテナーへ挿入します。
  • PublishWithContainerFiles: aspire publish 実行時に、発行用のビルド成果物として、あるリソースのコンテナーから別のリソースのコンテナーへファイルをコピーします。

WithContainerFiles 拡張メソッドは、指定した宛先パスにあるコンテナー内のファイルやディレクトリを作成または更新します。ニーズに応じて、宣言的にファイルを定義するインライン エントリ、ホスト ファイル システムからコピーするためのソース パス、動的にファイルを生成する非同期コールバックという 3 つの方法をサポートします。

インライン エントリのオーバーロードを使用すると、ContainerFileSystemItem オブジェクトを使ってファイルやディレクトリを宣言的に定義できます。これは、ファイル内容がビルド時点で分かっている場合や、文字列リテラルとして表現できる場合に便利です。

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();

前の例では:

  • 指定した内容を持つ JSON 構成ファイルが /app/config/appsettings.json に作成されます。
  • 実行可能なシェル スクリプトを含む入れ子の scripts ディレクトリが /app/config/scripts/ に作成されます。

ソース パスのオーバーロードを使用すると、ホスト マシン上のディレクトリからコンテナーへファイルをコピーできます。これは、既存の構成ファイルやアセットがディスク上にある場合に便利です。

AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
builder.AddContainer("myapp", "myapp:latest")
.WithContainerFiles("/app/config", "./config-files");
builder.Build().Run();

ソース パスがルート化された絶対パスでない限り、AppHost プロジェクト ディレクトリからの相対パスとして解釈されます。ソース ディレクトリ内のすべてのファイルは、起動時にコンテナー内の宛先パスへコピーされます。

コールバック オーバーロードを使用すると、コンテナーの起動時に動的にファイルを生成できます。このコールバックは ContainerFileSystemCallbackContext を受け取り、IServiceProvider とリソースの IResource モデルにアクセスできるため、サービスを解決したりアプリ モデルを検査したりできます。

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();

このコールバックはコンテナーが起動するたびに呼び出されるため、生成されるファイルには常に現在の状態が反映されます。

WithContainerFiles API は、抽象 ContainerFileSystemItem クラスを基底とする型階層を使用します。各型は、異なる種類のファイル システム エントリを表します。

ContainerFile は標準的なファイルを表します。ファイル データを指定するには、Contents (文字列) または SourcePath (ホスト上の絶対パス) のいずれかを設定します。両方を同時に設定することはできません。

AppHost.cs
// インライン内容を持つファイル
var configYaml = new ContainerFile
{
Name = "config.yaml",
Contents = "key: value"
};
// ホスト ファイル システムから取得するファイル
var dataCsv = new ContainerFile
{
Name = "data.csv",
SourcePath = "/path/to/data.csv"
};

この特定のファイルの作成に失敗してもコンテナーを起動できるようにするには、ContinueOnErrortrue に設定します:

AppHost.cs
var optionalJson = new ContainerFile
{
Name = "optional-config.json",
Contents = "{}",
ContinueOnError = true
};

ContainerDirectory は、入れ子にした ContainerFileSystemItem エントリを含められるディレクトリを表し、任意のディレクトリ ツリーを構築できます。

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 を構築することもできます:

AppHost.cs
var assetsDir = new ContainerDirectory
{
Name = "assets",
Entries = ContainerDirectory.GetFileSystemItemsFromPath(
"/path/to/assets",
searchOptions: SearchOption.AllDirectories)
};

ContainerOpenSSLCertificateFile は、PEM エンコードされた公開証明書を表します。Aspire は、証明書ファイルをコンテナーへ配置するだけでなく、同じディレクトリ内に OpenSSL 互換のシンボリック リンク ([subject hash].[n]) も自動で作成します。これは openssl rehash の実行と同等です。これにより、証明書の検証に OpenSSL を使用するコンテナーが、この証明書を自動的に検出できるようになります。

AppHost.cs
builder.AddContainer("myapp", "myapp:latest")
.WithContainerFiles("/certs", [
new ContainerOpenSSLCertificateFile
{
Name = "ca-cert.pem",
Contents = pemCertificateString
}
]);

ファイルのアクセス許可と所有者

Section titled “ファイルのアクセス許可と所有者”

WithContainerFiles のすべてのオーバーロードは、ファイルの所有者とアクセス許可を制御するための省略可能なパラメーターを受け取ります。

defaultOwnerdefaultGroup パラメーターは、作成されるすべてのファイルとディレクトリに適用される既定の UID と GID を設定します。どちらも指定しない場合は 0 (root) が既定値です。任意の ContainerFileSystemItem にある Owner および Group プロパティを使用して、個々の項目の所有者を上書きできます。

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);

この例では、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 を直接設定できます:

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);

ContainerLifetime.Persistent を持つコンテナーでは、コンテナー ファイル エントリの内容を変更するとコンテナーが再作成されます。意図しないコンテナー再起動を避けるため、WithContainerFiles で書き込まれるデータは、特定のアプリ モデル構成に対して冪等になるようにしてください。

PublishWithContainerFiles メソッドは、aspire publish の実行中に、あるリソースのコンテナーから別のリソースのコンテナーへファイルをコピーします。これは、発行時にコンテナーへファイルを挿入するための推奨アプローチです。

代表的なユース ケースは、シングルページ アプリケーション (SPA) や静的な JavaScript フロントエンドを、本番デプロイ用のリバース プロキシまたは Web サーバー コンテナーに埋め込むことです。開発時には、Vite や React のようなフロントエンド アプリは通常、スタンドアロンの開発サーバーとして実行されます。一方、本番環境では、コンパイル済みの静的アセットはバックエンド API や Nginx のような専用 Web サーバーから配信されることが一般的です。PublishWithContainerFiles は、ビルド済みのフロントエンド出力を発行プロセスの一部として配信先コンテナーへコピーすることで、このギャップを埋めます。手動でのファイル コピーやマルチステージ Dockerfile は不要です。

バックエンドにフロントエンドを埋め込む

Section titled “バックエンドにフロントエンドを埋め込む”
AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var frontend = builder.AddViteApp("frontend", "../frontend");
var api = builder.AddProject<Projects.Api>("api")
.PublishWithContainerFiles(frontend, "./wwwroot");
builder.Build().Run();

この例では:

  1. frontend リソースはコンテナー内でビルドされ、コンパイル済みの JavaScript、CSS、HTML を生成します。
  2. 発行時に、Aspire はそれらのファイルを frontend コンテナーから api コンテナー内の ./wwwroot へコピーします。
  3. 結果として得られる api コンテナーには API コードとフロントエンドの静的アセットの両方が含まれ、アプリケーション全体を配信する準備が整います。

YARP からフロントエンドを配信する

Section titled “YARP からフロントエンドを配信する”

フロントエンド アセットを専用のリバース プロキシ コンテナーへ埋め込むこともできます:

AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var frontend = builder.AddViteApp("frontend", "../frontend");
var nginx = builder.AddYarp("gateway")
.PublishWithStaticFiles(frontend);
builder.Build().Run();

これにより、外部ボリューム マウントや実行時のファイル コピーを必要としない、フロントエンド アプリケーションを配信する自己完結型の Nginx コンテナーが生成されます。

PublishWithContainerFiles は発行モードでのみ適用され、aspire run 中は効果がありません。宛先リソースは IContainerFilesDestinationResource (例: ProjectResource) を実装し、ソース リソースは IResourceWithContainerFiles を実装している必要があります。

ソース パスをカスタマイズする

Section titled “ソース パスをカスタマイズする”

既定では、ソース リソースは構成済みの出力パスに基づいて、自身のコンテナーからファイルをエクスポートします。ソース コンテナー内のどのパスからコピーするかを指定するには、WithContainerFilesSource を使用します:

AppHost.cs
var frontend = builder.AddViteApp("frontend", "../frontend")
.WithContainerFilesSource("/app/dist");
var api = builder.AddProject<Projects.Api>("api")
.PublishWithContainerFiles(frontend, "./wwwroot");

以前に構成したソース パスを削除してから新しいものを追加するには、ClearContainerFilesSources を使用します。