【Day 28】ボリューム(Named Volume)によるSQL Serverデータの安全な永続化 〜Docker管理領域によるmdf/ldfファイルの完全保護、docker-compose.ymlでのボリューム定義構文、一時コンテナを用いた安全バックアップ・リストア術、C# EF Core現場でのデータ保持〜
「物理サーバーのDドライブのように、SQL ServerのDBレコードを安全に守り抜くにはどうすればいいのか?」
前回のDay 27では、Dockerコンテナが「いつでも使い捨てて作り直せるステートレスなプロセス」であり、何も設定せずにデータを書き込むとコンテナ破棄(docker compose down)と同時にデータが消滅する原理を学びました。
では、業務システムの要である SQL Server のデータベース(.mdf / .ldf) は、具体的にどのように保護すべきなのでしょうか?
その答えが、Dockerが推奨する 「名前付きボリューム(Named Volume)」 です!
本講義では、SQL Server公式Linuxコンテナのデータ格納構造(/var/opt/mssql/data)を解剖し、docker-compose.yml での正しいボリューム宣言、一時コンテナを用いた安全バックアップ&リストア手法、そしてC# / Entity Framework Core開発における超快適なデータ保護サイクルを徹底解説します!
INDEX 本日の講義カリキュラム
- 第1章: 名前付きボリューム(Named Volume)の基本と仕組み 〜ホスト管理領域の完全隔離〜
- 第2章: SQL Server Linuxコンテナのデータ格納構造(/var/opt/mssql/data の秘密)
- 第3章: docker-compose.yml での volumes 定義構文 〜2層構造の完全理解〜
- 第4章: 実践!Docker CLIによるボリューム管理(create, ls, inspect, prune)
- 第5章: 現場必須!一時コンテナ(alpine)を使った安全なデータバックアップ&リストア手順
- 第6章: C# / ASP.NET Core & EF Core 現場での実践運用パターン
- 第7章: 本日のまとめと理解度チェッククイズ(次回予告:Day 29 ホットリロード)
第1章: 名前付きボリューム(Named Volume)の基本と仕組み 〜ホスト管理領域の完全隔離〜
従来のWindows ServerやHyper-V仮想マシンでは、OSドライブ(Cドライブ)とは別に データ専用の独立ドライブ(DドライブやSAN/NASボリューム) を用意し、SQL Serverのデータファイルを配置するのが鉄則でした。OSが故障したり再インストールが必要になったりしても、Dドライブさえデタッチして無事なら、いつでも新しいマシンにアタッチして復旧できたからです。
Dockerにおける 「名前付きボリューム(Named Volume)」 は、まさにこの 「独立した安全なデータドライブ」 に相当する機能です。
- ① ホストOSのファイル権限(UID/GID)の競合ゼロ: SQL ServerコンテナはLinux内部で特殊な
mssqlユーザー(UID 10001)で動作します。ホストPCのWindowsフォルダを直接直結(バインドマウント)するとNTFSのパーミッションエラーで起動失敗することが多発しますが、Named VolumeならDocker Engineが内部で安全な権限管理を自動代行します。 - ② 高速なI/O性能: Windows上でWSL2を使う場合、WindowsのNTFSドライブ(
/mnt/c/...)をマウントするとファイルアクセスが著しく低下します。Named VolumeはWSL2のExt4仮想ディスク内に直接確保されるため、ネイティブLinux並みの圧倒的なディスクI/O速度を誇ります。 - ③ 名前によるポータビリティ:
C:\Users\yamada\dataのような環境依存の絶対パスを書く必要がなく、sqlserver_dataという名前だけで全開発者・CI環境で共通運用できます。
Named Volumeの実体は、Docker Engineが管理するホスト上の専用領域(Linuxでは /var/lib/docker/volumes/<volume_name>/_data)に配置されます。コンテナが何百回起動・停止・破棄されようとも、このホスト管理領域の実体ファイルには指一本触れられません。
第2章: SQL Server Linuxコンテナのデータ格納構造(/var/opt/mssql/data の秘密)
Microsoft公式のSQL Server Linuxコンテナ(mcr.microsoft.com/mssql/server)を扱う際、エンジニアが必ず押さえておくべき絶対的なパスがあります。それが /var/opt/mssql/data です。
このディレクトリの中には、SQL Serverのエンジンが稼働するために不可欠なシステムデータベースおよびユーザーデータベースの実体ファイルが全て配置されます:
/var/opt/mssql/data/
├── master.mdf # システム構成・ログイン情報
├── mastlog.ldf # masterのトランザクションログ
├── model.mdf # 新規DB作成時のテンプレート
├── modellog.ldf # modelのトランザクションログ
├── msdbdata.mdf # ジョブやバックアップ履歴
├── msdblog.ldf # msdbのトランザクションログ
├── tempdb.mdf # 一時テーブル(起動毎に再生成)
├── templog.ldf # tempdbのトランザクションログ
├── MyCsharpAppDb.mdf # ★自作C#アプリのテーブル・データレコード実体
└── MyCsharpAppDb_log.ldf # ★自作C#アプリのトランザクションログ
つまり、コンテナ内の /var/opt/mssql/data ディレクトリをDockerのNamed Volumeにマウント してしまえば、SQL Serverが管理するすべてのデータファイル(.mdf / .ldf)がホスト側の安全なボリュームへ自動的に逃がされることになります!
第3章: docker-compose.yml での volumes 定義構文 〜2層構造の完全理解〜
ComposeファイルでNamed Volumeを利用する場合、初心者が最も躓きやすいのが 「2箇所に書く必要がある」 という点です。
以下の完成版 docker-compose.yml をご覧ください。
services:
db:
image: mcr.microsoft.com/mssql/server:2022-latest
container_name: sqlserver_container
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=YourStrong@Passw0rd
ports:
- "1433:1433"
volumes:
# 【階層①】サービス内マウント: <ボリューム名>:<コンテナ内パス>
- sqlserver_data:/var/opt/mssql/data
# 【階層②】トップレベル宣言: プロジェクト全体で利用するNamed Volumeを宣言
volumes:
sqlserver_data:
name: myproject_sql_volume # 任意のグローバルボリューム名を明示(省略可能)
この2層構造の役割を明確に区別しましょう:
- ① サービス内 volumes: 個々のコンテナに対して「どのボリュームを」「コンテナ内のどこに差し込む(マウントする)か」を指示する プラグの接続設定 です。
- ② トップレベル volumes: Docker Engineに対して「この名前の永続化ボリューム実体を1個確保せよ」と命じる 金庫自体の作成宣言 です。ここに書かないと、Composeは「そんなボリューム定義は存在しない」とエラーを出します。
第4章: 実践!Docker CLIによるボリューム管理(create, ls, inspect, prune)
普段は docker compose up で自動生成されるNamed Volumeですが、障害対応やディスクメンテナンス時にはDocker CLIから直接操作できることが現場エンジニアの必須スキルです。
| コマンド | 機能説明 | 実務でのユースケース |
|---|---|---|
| docker volume ls | 存在するボリュームの一覧表示 | 現在PCに溜まっているDBボリュームの確認 |
| docker volume inspect <名> | ボリュームの詳細情報(Mountpoint)表示 | ホストOS上の物理保存先パスの特定 |
| docker volume create <名> | 名前を指定して手動作成 | 事前に共通データボリュームを仕込んでおく場合 |
| docker volume rm <名> | 特定ボリュームの削除 | テスト環境を完全破棄したい時(※コンテナ停止要) |
| docker volume prune | どのコンテナにも繋がっていないボリューム一括削除 | SSD空き容量の劇的回復(※未接続ボリューム消滅注意) |
普段の docker compose down では、コンテナプロセスのみが破棄され、Named Volumeは無傷で残ります。
しかし、末尾に -v(または --volumes)を付与して docker compose down -v と叩くと、トップレベルで宣言されたNamed Volumeごと物理削除 されます!テストレコードを意図してリセットしたい場合を除き、日常の停止時には絶対に -v を付けないよう指差呼称してください。
第5章: 現場必須!一時コンテナ(alpine)を使った安全なデータバックアップ&リストア手順
「Named Volumeの中身をバックアップして別のPCに持っていきたい」「本番に近いテストデータを開発チーム全員に配布したい」というシチュエーションは現場で日常茶飯事です。
しかし、Named Volumeの実体フォルダ(/var/lib/docker/volumes/...)はroot権限で保護されており、Windowsエクスプローラーから直接ZIP圧縮することは困難です。
そこで、Dockerの世界で標準的に使われるプロの手法が 「超軽量な一時コンテナ(alpine)を用いたtarアーカイブバックアップ」 です!
docker run --rm \
-v sqlserver_data:/dbdata \
-v ${PWD}:/backup \
alpine tar czvf /backup/sqlserver_backup.tar.gz -C /dbdata .
# 【手順2: リストア(復元)】新規作成したボリュームにtar.gzを展開
docker run --rm \
-v sqlserver_data:/dbdata \
-v ${PWD}:/backup \
alpine tar xzvf /backup/sqlserver_backup.tar.gz -C /dbdata
このワンライナーがなぜエレガントなのか、その仕組みを紐解きましょう:
--rmオプションにより、tar圧縮・展開の処理が終わった瞬間に一時コンテナ(alpine)は自動で消滅します(ゴミが残りません)。- Named Volume(
sqlserver_data)を/dbdataに、ホスト側のカレントディレクトリ(${PWD})を/backupに同時にマウントします。 - コンテナ内部で
tarコマンドが走り、/dbdataの中身(.mdf/.ldfファイル群)を瞬時に圧縮して、ホスト側の/backup/sqlserver_backup.tar.gzに保存してくれます。
第6章: C# / ASP.NET Core & EF Core 現場での実践運用パターン
Named Volumeを導入することで、C#エンジニアの開発体験(Developer Experience)は劇的に進化します。
① EF Core マイグレーションとボリュームの共存
ASP.NET Coreアプリケーション起動時に DbContext.Database.Migrate() を呼び出す設計を採用している場合、初回起動時にテーブルが自動作成され、テストシードデータが投入されます。
もしボリュームがなければ、C#コードを修正してコンテナを再起動するたびに「初期化スクリプト」が最初から走り直し、手動で画面からポチポチ登録したテストユーザーや受注レコードが吹き飛んでいました。
using (var scope = app.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
// Named VolumeにDBファイルが存在すればマイグレーション履歴テーブル(__EFMigrationsHistory)
// を見て差分のみ適用されるため、既存データは完全に安全!
dbContext.Database.Migrate();
}
② チーム開発におけるGitとボリュームの運用ルール
チームでDockerを活用する際の鉄則は、「Gitで共有するのはコードとマイグレーション(.csファイル)だけであり、Named VolumeのDB実体ファイル(.mdf/.ldf)は絶対にGitにコミットしない」 ということです。
- Gitの役割: データベースの「スキーマ定義(設計図)」を全員で同期する。
- Volumeの役割: 各開発者のPC上で動作する「生データ(テストレコード)」をローカルで安全に保持する。
これにより、Gitのブランチを切り替えて新機能を実装し、コンテナを docker compose up -d --build で差分再ビルドしても、昨日登録したログインセッションや複雑なテストデータがそのまま保持されるため、開発効率が何十倍にも向上します!
第7章: 本日のまとめと理解度チェッククイズ
📌 本日の最重要チェックポイント
- Named VolumeはDocker管理の安全な独立データドライブ: ホストOSの権限競合を防ぎ、最高速のディスクI/Oを提供。
- SQL Serverの格納先は
/var/opt/mssql/data: ここをボリュームにマウントすることで、すべてのmdf/ldfファイルがコンテナ外へ保護される。 - Compose定義は「サービス内」と「トップレベル」の2層構造: サービス内でマウント先を指定し、最下部で実体宣言を行う。
- 日常は
down、リセット時のみdown -v:-vオプションを誤爆するとボリュームごとデータ消滅するため厳格注意。 - バックアップは一時コンテナ(alpine)のtarが業界標準: コンテナを汚染せず、ホスト側へクリーンにtar.gzアーカイブを出力可能。
🎯 理解度チェッククイズ
Q: docker-compose.ymlでNamed Volumeを利用してSQL Serverを起動している現場で、開発者が叩いたコマンドのうち、データベースのデータが「完全に消滅してしまう」ものはどれでしょうか?
- A.
docker compose stop - B.
docker compose down - C.
docker compose up -d --build - D.
docker compose down -v
正解と解説を見る
正解: D. docker compose down -v
通常の stop や down、再ビルドを伴う up -d --build では、Named Volumeは完全に維持されるためDBデータは消えません。しかし、-v(または --volumes)フラグを付けて実行すると、コンテナだけでなく定義されたボリューム自体が破棄されるため、データが完全に初期化されます。意図的なデータリセット以外では絶対に付与しないようにしましょう。
🚀 次回予告(Day 29)
次回は永続化のもう一つの主役、「バインドマウント(Bind Mount)によるソースコード即時反映(ホットリロード)」 を徹底攻略します!
C#コードを保存した瞬間にコンテナ内で自動再起動・即時反映される dotnet watch とバインドマウントの超高速開発サイクルを構築します。お楽しみに!
コメント
コメントを投稿