# ボリュームまたはバインド マウントを使用して Aspire プロジェクトのデータを保持する

Aspire プロジェクトを開始して停止するたびに、アプリはアプリ リソース コンテナーも作成し、破棄します。デバッグ セッション中にそれらのコンテナーに保存されたデータやファイルは、次のセッションでは失われます。多くの開発チームは、たとえば実行のたびにサンプル データでデータベースを再投入しなくて済むように、デバッグ セッション間でこのデータを保持したいと考えます。

この記事では、アプリの起動をまたいでデータを保持するように Aspire プロジェクトを構成する方法を学びます。ローカル開発中に連続したデータ セットを維持できることは、多くのシナリオで有用です。PostgreSQL、Redis、Azure Storage など、さまざまな Aspire リソース コンテナーの種類でボリュームやバインド マウントを活用できます。

## プロジェクト データを保持するタイミング

データベース リソースを含む Aspire ソリューションがあるとします。既定では、データはそのリソースのコンテナーに保存されます。アプリを停止するとすべてのリソース コンテナーが破棄されるため、そのデータは失われ、次にソリューションを実行したときには表示されません。この構成は、テストやデバッグのためにアプリ起動間でデータベースやストレージ サービスのデータを保持したい場合に問題を生みます。たとえば、次のような要件です:

- 複数回の再起動にまたがる長時間の開発セッション中、データベースで連続したデータ セットを扱いたい。
- Azure Blob Storage エミュレーター内で変化するファイル セットをテストまたはデバッグしたい。
- アプリの起動をまたいで Redis インスタンス内のキャッシュ データやメッセージを維持したい。

これらの目的は、ボリュームまたはバインド マウントを使って実現できます。これらの仕組みはコンテナー外、つまりコンテナー ホスト上のディレクトリにデータを保存するため、コンテナーと一緒に破棄されません。この方法により、Aspire プロジェクトの起動間でどのサービスのデータを保持するかを選べます。
**Note:** ボリュームとバインド マウントは、Docker または
  Podman などのコンテナー ランタイムの機能です。Aspire にはそれらを簡単に扱うメソッドが含まれています。

## ボリュームとバインド マウントの比較

ボリュームとバインド マウントはどちらも、コンテナー ホスト上のディレクトリにデータを保存します。このディレクトリはコンテナーの外にあるため、コンテナーが停止してもデータは破棄されません。ただし、ボリュームとバインド マウントの動作には違いがあります:

- **ボリューム**: コンテナー ランタイムがボリュームを作成および制御します。ボリュームはコンテナー ホストの中核機能から分離されています。
- **バインド マウント**: コンテナー ランタイムがホスト マシン上のファイルまたはディレクトリをマウントします。コンテナーとホスト マシンの両方がバインド マウントの内容にアクセスできます。

ボリュームはバインド マウントよりも安全で移植性が高く、パフォーマンスも優れています。可能な限りボリュームを使用してください。ホスト マシンからデータにアクセスまたは変更する必要がある場合にのみ、バインド マウントを使用します。

## ボリュームの使用

ボリュームはコンテナーによって生成されるデータを保持するための推奨方法で、Windows と Linux の両方でサポートされています。ボリュームは複数のコンテナーのデータを同時に保存でき、高いパフォーマンスを提供し、バックアップや移行も容易です。Aspire では `WithVolume` メソッドを使って各リソース コンテナーのボリュームを構成します。このメソッドは 3 つのパラメーターを受け取ります:

- **`name`**: ボリュームの省略可能な名前。
- **`target`**: 保持したいデータのコンテナー内ターゲット パス。
- **`isReadOnly`**: ボリューム内データを変更可能かどうかを示すブール値です。既定値は `false` です。

この記事の残りでは、分散アプリ ビルダーの基本がすでに定義されている Aspire の [AppHost プロジェクト](/ja/get-started/app-host/) にある `Program` クラスを確認していると想定します:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

// TODO:
//   ここでボリュームの構成と
//   永続パスワードの設定に関するさまざまなコード スニペットを検討する。

builder.Build().Run();
```

```typescript title="TypeScript — apphost.mts" twoslash
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

// TODO:
//   ここでボリュームの構成と
//   永続パスワードの設定に関するさまざまなコード スニペットを検討する。

await builder.build().run();
```

最初に示すコード スニペットでは `WithVolume` API を使用して SQL Server リソースのボリュームを構成します。次のコードは Aspire AppHost プロジェクトで SQL Server リソースにボリュームを構成する方法を示しています:

```csharp title="C# — AppHost.cs"
var sql = builder.AddSqlServer("sql")
                 .WithVolume(target: "/var/opt/mssql")
                 .AddDatabase("sqldb");
```

```typescript title="TypeScript — apphost.ts"
const sql = await builder.addSqlServer("sql");
await sql.withVolume("/var/opt/mssql");
const sqldb = await sql.addDatabase("sqldb");
```

この例では `/var/opt/mssql` がコンテナー内のデータベース ファイルへのパスを設定します。

すべての Aspire コンテナー リソースでボリュームを利用でき、さらに一部ではリソースから派生した名前付きボリュームを追加するための便利な API が提供されています。`WithDataVolume` メソッドを例にすると、次のコードは先ほどの例と機能的に等価ですが、より簡潔です:

```csharp title="C# — AppHost.cs"
var sql = builder.AddSqlServer("sql")
                 .WithDataVolume()
                 .AddDatabase("sqldb");
```

```typescript title="TypeScript — apphost.ts"
const sql = await builder.addSqlServer("sql");
await sql.withDataVolume();
const sqldb = await sql.addDatabase("sqldb");
```

AppHost プロジェクト名が `VolumeMount.AppHost` の場合、`WithDataVolume` メソッドは自動的に `VolumeMount.AppHost-sql-data` という名前付きボリュームを作成し、SQL Server コンテナー内の `/var/opt/mssql` パスにマウントします。命名規則は次のとおりです:

- `{appHostProjectName}-{resourceName}-data`: ボリューム名は AppHost プロジェクト名とリソース名から派生します。

## バインド マウントの使用

バインド マウントを使うと、コンテナー内部とホスト マシン上のプロセスの両方からデータへアクセスできます。たとえばバインド マウントを確立した後、ホスト コンピューター上でそこにファイルをコピーできます。そのファイルはリソースのコンテナー内でバインド先パスから利用できます。Aspire では `WithBindMount` メソッドを使って各リソース コンテナーのバインド マウントを構成します。このメソッドは 3 つのパラメーターを受け取ります:

- **`source`**: コンテナーにマウントするホスト マシン上のフォルダーへのパス。
- **`target`**: フォルダーのコンテナー内ターゲット パス。
- **`isReadOnly`**: バインド マウント内データを変更可能かどうかを示すブール値です。既定値は `false` です。

次のコード スニペットでは `WithBindMount` API を使用して SQL Server リソースのバインド マウントを構成しています:

```csharp title="C# — AppHost.cs"
var sql = builder.AddSqlServer("sql")
                 .WithBindMount(source: @"C:\SqlServer\Data", target: "/var/opt/mssql")
                 .AddDatabase("sqldb");
```

```typescript title="TypeScript — apphost.ts"
const sql = await builder.addSqlServer("sql");
await sql.withBindMount("C:\\SqlServer\\Data", "/var/opt/mssql");
const sqldb = await sql.addDatabase("sqldb");
```

この例では:

- `source: @"C:\SqlServer\Data"` は、バインドされるホスト コンピューター上のフォルダーを設定します。
- `target: "/var/opt/mssql"` は、コンテナー内のデータベース ファイルへのパスを設定します。

ボリュームと同様に、一部の Aspire コンテナー リソースではバインド マウントを追加するための便利な API が提供されています。`WithDataBindMount` メソッドを例にすると、次のコードは先ほどの例と機能的に等価ですが、より簡潔です:

```csharp title="C# — AppHost.cs"
var sql = builder.AddSqlServer("sql")
                 .WithDataBindMount(source: @"C:\SqlServer\Data")
                 .AddDatabase("sqldb");
```

```typescript title="TypeScript — apphost.ts"
const sql = await builder.addSqlServer("sql");
await sql.withDataBindMount("C:\\SqlServer\\Data");
const sqldb = await sql.addDatabase("sqldb");
```

## 永続パスワードの作成

名前付きボリュームでは、アプリ起動間で一貫したパスワードが必要です。Aspire にはランダムなパスワード生成機能が用意されています。先ほどの例をもう一度見てみましょう。ここではパスワードが自動生成されます:

```csharp title="C# — AppHost.cs"
var sql = builder.AddSqlServer("sql")
                 .WithDataVolume()
                 .AddDatabase("sqldb");
```

```typescript title="TypeScript — apphost.ts"
const sql = await builder.addSqlServer("sql");
await sql.withDataVolume();
const sqldb = await sql.addDatabase("sqldb");
```

`AddSqlServer` 呼び出し時に `password` パラメーターを指定しないため、Aspire は SQL Server リソース用パスワードを自動生成します。
**Caution:** これは永続パスワードではありません。代わりに AppHost を実行するたびに
  変わります。

_永続_ パスワードを作成するには、生成されたパスワードを上書きする必要があります。これを行うには、AppHost プロジェクト ディレクトリで次のコマンドを実行してローカル シークレットを設定します:

```bash title="Aspire CLI"
aspire secret set Parameters:sql-password <password>
```

これらのシークレットの命名規則を理解することが重要です。パスワードは `Parameters:sql-password` キーで構成に保存されます。命名規則は次のパターンです:

- `Parameters:{resourceName}-password`: SQL Server リソース（名前は `"sql"`）の場合、パスワードは `Parameters:sql-password` キーで構成に保存されます。

同じパターンは、次の表に示す他のサーバーベース リソースの種類にも適用されます:

| リソースの種類 | ホスティング パッケージ                                                                          | リソース名の例 | 上書きキー                     |
| ------------- | ---------------------------------------------------------------------------------------- | --------------------- | -------------------------------- |
| MySQL         | [📦 Aspire.Hosting.MySql](https://www.nuget.org/packages/Aspire.Hosting.MySql)           | `mysql`               | `Parameters:mysql-password`      |
| Oracle        | [📦 Aspire.Hosting.Oracle](https://www.nuget.org/packages/Aspire.Hosting.Oracle)         | `oracle`              | `Parameters:oracle-password`     |
| PostgreSQL    | [📦 Aspire.Hosting.PostgreSQL](https://www.nuget.org/packages/Aspire.Hosting.PostgreSQL) | `postgresql`          | `Parameters:postgresql-password` |
| RabbitMQ      | [📦 Aspire.Hosting.RabbitMq](https://www.nuget.org/packages/Aspire.Hosting.RabbitMq)     | `rabbitmq`            | `Parameters:rabbitmq-password`   |
| SQL Server    | [📦 Aspire.Hosting.SqlServer](https://www.nuget.org/packages/Aspire.Hosting.SqlServer)   | `sql`                 | `Parameters:sql-password`        |

生成されたパスワードを上書きすることで、アプリ起動間でパスワードを一貫して保てます。別の方法として `AddParameter` メソッドを使用し、パスワードとして利用できるパラメーターを作成することもできます。次のコードは SQL Server リソースの永続パスワードを作成する方法を示しています:

```csharp title="C# — AppHost.cs"
var sqlPassword = builder.AddParameter("sql-password", secret: true);

var sql = builder.AddSqlServer("sql", password: sqlPassword)
                 .WithDataVolume()
                 .AddDatabase("sqldb");
```

```typescript title="TypeScript — apphost.ts"
const sqlPassword = await builder.addParameter("sql-password", { secret: true });

const sql = await builder.addSqlServer("sql", { password: sqlPassword });
await sql.withDataVolume();
const sqldb = await sql.addDatabase("sqldb");
```

`AddParameter` メソッドは `sql-password` という名前のパラメーターを作成し、それをシークレットとして扱います。続いて `AddSqlServer` メソッドを `password` パラメーター付きで呼び出し、SQL Server リソースのパスワードを設定します。詳しくは [外部パラメーター](/ja/fundamentals/external-parameters/) を参照してください。

## 次のステップ

前述のコードにあるボリュームの概念は、アプリ起動間で保持されるデータを使ったデータベース シードなど、さまざまなサービスに適用できます。次のチュートリアルで示したリソース実装と組み合わせて試してみてください:

- [チュートリアル: Aspire と Entity Framework Core を使用して ASP.NET Core アプリを SQL Server に接続する](/ja/integrations/databases/efcore/sql-server/sql-server-get-started/)
- [Aspire オーケストレーションの概要](/ja/get-started/app-host/)