【Day 30】Git管理すべきファイルとVolumeに逃がすべきデータの境界線 〜コード(Git)・構成(Git/.env)・データ(Volume)の3層分離、巨大mdfバイナリ混入事故の防止、.gitignore徹底、チーム開発共有ルール〜
「Dockerプロジェクト内のファイル、何でもGitにコミットしていませんか?」
前回のDay 29では、ホストPCとコンテナを直結してC#のホットリロードを実現する「バインドマウント(Bind Mount)」を学びました。
コンテナ環境でのデータ永続化(Named Volume)と高速開発(Bind Mount)の両輪を手に入れた開発チームが、次に必ず直面するのが 「プロジェクト内のどのファイルをGitで管理し、何をVolumeやローカルに逃がすべきか?」という境界線の問題 です。
昔のオンプレミス現場では、ファイルサーバーの共有フォルダにソースコード、SQL Serverの .mdf ファイル、設定ファイル、果てはログまで何でも放り込み、誰かが上書きしてDBが破損するなどの地獄絵図が日常茶飯事でした。
もしこの悪習をそのまま現代のGit×Docker環境に持ち込み、巨大なデータベースファイルをGitにコミットしてしまうと、リポジトリが数十GBに膨れ上がり、チーム全員のPCでクローン不能になる壊滅的事故 を引き起こします。
本講義は第6部「データの永続化とボリューム」の総決算として、「コード(Git)」「構成(Git/.env)」「データ(Volume)」の3層分離原則 と、事故を未然に防ぐ現場ルールを完全解説します!
INDEX 本日の講義カリキュラム
- 第1章: 共有フォルダ破綻の歴史に学ぶ 〜なぜ「何でも詰め込み」は失敗するのか?〜
- 第2章: 現代コンテナ開発における「3層分離(コード・構成・データ)」の原則
- 第3章: 現場向け「ファイル行き先判定マトリクス」と3ステップ判定フロー
- 第4章: 巨大バイナリ混入の悲劇 〜.mdfをGitにpushするとリポジトリが崩壊する理由と.gitignoreの徹底〜
- 第5章: C# / .NET 現場での実践:appsettings.json(設定)とSQL Server実データ(Volume)の共存設計
- 第6章: チーム開発でのGit&Docker運用ルール策定ガイドライン
- 第7章: 第6部総決算のまとめと理解度チェッククイズ(次回予告:第7部 Dockerネットワーク入門)
第1章: 共有フォルダ破綻の歴史に学ぶ 〜なぜ「何でも詰め込み」は失敗するのか?〜
かつてのオンプレミスや仮想マシン(Hyper-V / VMware)全盛の時代、社内ネットワークには必ず \\fileserver\dev_share のような「開発用共有フォルダ」が存在していました。
そこには以下のようなあらゆる種類のファイルが無法地帯のように混在していました:
- Visual StudioのソリューションファイルやC#ソースコード
- SQL Serverにアタッチされている生の
app_data.mdfやapp_log.ldf - 各エンジニアが手元で実行した出力ログやエラーダンプ
- 本番サーバー接続文字列がハードコードされた設定ファイル
このような「何でも詰め込み」運用がもたらした結末は、多くのベテランエンジニアが身をもって体験してきた通り 「完全な破綻」 でした。
上図(左側)をご覧ください。共有フォルダでファイルを共有すると、次のような致命的トラブルが連日発生しました:
⚠️ 共有フォルダ運用が引き起こした3大悲劇
- ファイルロックとデータベース破損: 誰かがSQL Server Management Studio(SSMS)で接続したままにして排他ロックがかかり、他のメンバーが作業できなくなる。最悪の場合、同時書き込みでmdfヘッダーが破損し、全員のデータが全滅する。
- データの先祖返りとブラックボックス化: 「最新のDBデータはどれ?」「backup_20261020_final2.bak って誰が作ったの?」と誰も全体像を把握できなくなる。
- 秘密情報の漏洩リスク: パスワードや機密データが誰でもアクセス可能な平文ファイルとして放置され、情報セキュリティ上の重大な脆弱性となる。
現代のコンテナ開発では、この苦い歴史の反省から 「ファイルをその性質(ライフサイクルと変更頻度)に応じて厳密に分類し、それぞれ最適な仕組みで管理する」 というパラダイムシフトが確立されています。
第2章: 現代コンテナ開発における「3層分離(コード・構成・データ)」の原則
DockerとGitを組み合わせたモダンな開発環境では、すべての構成要素を以下の 「3層」 に厳格に分離して設計します。
C#の .cs ファイル、.csproj、Dockerfile、docker-compose.yml。
テキストベースで記述され、変更履歴(コミットログ)が厳密に記録されるべきチーム共通の資産。
.env や docker-compose.override.yml。
環境ごとに異なる機密情報。Gitにはテンプレート(.env.example)のみをコミットし、実ファイルは .gitignore で完全除外。
SQL Serverの .mdf/.ldf、ユーザー投稿画像、アクセスログ。
サイズが巨大で頻繁に更新されるバイナリ。Gitには一切入れず、Dockerの Named Volume に逃がして永続化。
この3層分離を徹底することで、「コードは安全に共有され」「パスワードは漏洩せず」「データベースはコンテナ破棄時も確実に保護される」という強固なアーキテクチャが完成します。
第3章: 現場向け「ファイル行き先判定マトリクス」と3ステップ判定フロー
プロジェクトに新しいファイルやフォルダが追加された際、チームメンバーが迷わず正しく配置できるよう、以下の 「判定3ステップフロー」 を確立しましょう。
このフローに基づいた現場向け判定マトリクスがこちらです:
| ファイル種類 | 具体例 | 管理場所 | 理由・注意点 |
|---|---|---|---|
| C# ソースコード | *.cs, *.csproj, *.sln |
Git管理 | アプリの本体。チームで共同開発。 |
| インフラ定義ファイル | Dockerfile, docker-compose.yml |
Git管理 | 環境の再現手順(IaC)。全員が同じ定義で起動。 |
| アプリケーション共通設定 | appsettings.json |
Git管理 | ログ設定や基本オプション。機密パスワードは含めない。 |
| 環境固有の機密情報 | .env, *.secrets.json |
Git除外(.gitignore) | DBパスワードやAPI鍵。漏洩防止のためGit厳禁。 |
| 設定ファイルのひな形 | .env.example |
Git管理 | 新人参加者がコピーして自分の .env を作るための見本。 |
| データベース実データ | *.mdf, *.ldf, *.bak |
Docker Named Volume | 巨大バイナリ。Gitに絶対入れずDocker管理領域へ。 |
| ビルド成果物・一時ファイル | bin/, obj/, .vs/ |
Git除外(.gitignore) | ソースからいつでも再生成可能。リポジトリ汚染の主因。 |
| 初期マスタデータSQL | init.sql, migrations/*.cs |
Git管理 | テーブル定義や初期投入用。テキスト形式なのでGitで共有。 |
第4章: 巨大バイナリ混入の悲劇 〜.mdfをGitにpushするとリポジトリが崩壊する理由と.gitignoreの徹底〜
なぜデータベースの実データファイル(.mdf や .ldf)をGitにコミットしてはいけないのでしょうか?
その理由は、「Gitの内部データ構造(スナップショット方式)」 にあります。
Gitはテキストファイル(C#コードなど)であれば行単位のコンパクトな差分(delta)を保存しますが、バイナリファイルに対しては 「1バイト変わるだけでもファイル全体を丸ごと新しいスナップショットとしてコミット履歴(.git/objects)に保存」 します。
💥 巨大バイナリ事故のシミュレーション
例えば 2GB の testdata.mdf をGitにコミットしたとします。
その後、SQL Serverでレコードを1件INSERTして再度コミットすると、さらに 2GB の新しいバイナリが .git に追加されます。
これを10回繰り返すだけで、リポジトリの容量は 20GB を超えます!
新しくチームに参加したエンジニアが git clone を実行すると、ダウンロードに数時間かかり、通信タイムアウトで失敗し続けるという悪夢が現実になります。
さらに恐ろしいことに、後から git rm testdata.mdf を実行してファイルを消去しても、過去のコミット履歴の中には20GBのバイナリが残り続けます。
履歴から完全に消去するには git-filter-repo などの危険な履歴書き換えコマンドが必要になり、チーム全員のローカル環境のリセットを強いられます。
この悲劇を100%未然に防ぐ唯一の方法が、プロジェクト開始初日における .gitignore の徹底 です!
# Docker × C# / .NET プロジェクト必須の .gitignore テンプレート ### 1. データベース実データ・バックアップ(絶対にコミット禁止!) ### *.mdf *.ldf *.ndf *.bak *.trn *.db *.sqlite ### 2. 環境変数・秘匿設定ファイル ### .env .env.local .env.*.local *.secrets.json ### 3. C# / .NET ビルド成果物・キャッシュ ### [Bb]in/ [Oo]bj/ [Dd]ebug/ [Rr]elease/ *.user *.suo .vs/ .idea/ ### 4. ログファイル・一時出力 ### *.log logs/ temp/ docker_volumes/
第5章: C# / .NET 現場での実践:appsettings.json(設定)とSQL Server実データ(Volume)の共存設計
C# / ASP.NET Core のエンタープライズ現場では、この境界線をどのようにコードとインフラで表現するのでしょうか?
具体的な appsettings.json と docker-compose.yml の連携設計を見てみましょう。
上図をご覧ください。設計の勘所は以下の2点です:
- 設定の抽象化(Git共有):
appsettings.jsonには「DBのホスト名(サービス名:db)」や「ポート(1433)」といった構造のみを記述し、パスワード部分は環境変数で上書き可能なプレースホルダーにしておきます。 - データの完全委任(Volume管理): SQL Serverコンテナが生成・管理する
/var/opt/mssql/dataは、DockerのNamed Volume(sqlserver_data)にマウントします。
① C#側の設定ファイル(Gitで管理・共有)
// appsettings.json (パスワードは空文字または環境変数上書き前提) { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "ConnectionStrings": { // ホスト名はコンテナサービス名「db」を指定!パスワードはComposeの環境変数で注入される "DefaultConnection": "Server=db,1433;Database=OrderDb;User Id=sa;Password=${DB_PASSWORD};TrustServerCertificate=True;" } }
② docker-compose.yml(Gitで管理・Volumeとパスワードを結合)
services: webapi: build: . ports: - "5000:5000" environment: # .env からパスワードを読み込み、C#の接続文字列を環境変数で完全注入 - ConnectionStrings__DefaultConnection=Server=db,1433;Database=OrderDb;User Id=sa;Password=${SA_PASSWORD};TrustServerCertificate=True; depends_on: db: condition: service_healthy db: image: mcr.microsoft.com/mssql/server:2022-latest environment: - ACCEPT_EULA=Y - MSSQL_SA_PASSWORD=${SA_PASSWORD} volumes: # ★実データ(.mdf / .ldf)はNamed Volumeに完全に退避! - sqlserver_data:/var/opt/mssql/data # 名前付きボリュームの宣言(Dockerホスト領域で独立永続化) volumes: sqlserver_data:
この構成にすることで、チームの誰もが生のDBファイルをGitにコミットすることなく、docker compose up -d を実行するだけで即座に安全で完全なローカル開発環境を立ち上げることができます。
第6章: チーム開発でのGit&Docker運用ルール策定ガイドライン
「Git管理とVolumeの境界線」をチーム全員で遵守するために、プロジェクトの README.md や開発ガイドラインに以下の 4大ゴールデンルール を明記しておくことを強く推奨します。
📋 チーム開発のための4大ゴールデンルール
開発用の初期データやテーブル構造を渡したい時は、バイナリのmdfファイルを渡すのではなく、EF Coreの dotnet ef migrations や、テキスト形式の seed_data.sql をGitで共有します。
環境変数キーを追加した時は、必ず .env.example にダミー値(例: SA_PASSWORD=YourPasswordHere123!)を追記してコミットします。新メンバーはこれをコピーして手元で動かせます。
手元のテストデータを完全にクリーンアップして初期状態に戻したい時は、docker compose down -v を実行するだけで、Named Volumeが初期化されマイグレーションが再実行されます。
GitHub ActionsなどのCIパイプラインで、万が一バイナリファイルや不要フォルダが含まれていた場合は自動でビルドを失敗させる静的解析ガードを設置するとさらに完璧です。
第7章: 第6部総決算のまとめと理解度チェッククイズ
これで第6部「データの永続化とボリューム(Volume & Bind Mount)」のカリキュラムはすべて完了です!
コンテナのステートレスな原則(Day 27)、Named Volumeによる安全なデータ保持(Day 28)、Bind Mountによる爆速ホットリロード(Day 29)、そして今回のGitとVolumeの境界線(Day 30)を学んだことで、データ永続化と開発効率を完璧に両立させるプロフェッショナルな基盤 が完成しました!
🎯 理解度チェッククイズ!
問: 新しい開発メンバーが「自分の手元のSQL Serverデータをチーム全員に配りたいので、mdfファイルをGitにコミットしてpushしました!」と言ってきました。シニアエンジニアとしてどうアドバイスし、どのように解決すべきでしょうか?
正解と解説を確認する
【アドバイスと対応手順】
- 即時差し戻しと履歴の除去: mdfファイルは巨大バイナリであり、リポジトリ肥大化・clone遅延の主因となるため、直ちにpushを差し戻すか
git resetでコミットを取り消す。 - .gitignore の適用:
*.mdf,*.ldfを.gitignoreに追加して再コミットを防止する。 - シードデータ(SQL/Migration)での共有: データをチームに配る場合は、mdfファイルではなく EF Core の
HasData()によるシーディングスクリプト、またはinit.sqlのようなテキストスクリプトを作成してGit管理する。 - Volumeの利用: 各メンバーは
docker compose up時にそのスクリプトを各自の Named Volume に流し込む運用に切り替える。
🚀 次回予告:第7部「Dockerネットワークの基礎とサービス間通信」突入!
次回Day 31からは、いよいよ 第7部「Dockerネットワーク」 がスタートします!
「なぜ docker-compose.yml の中では localhost ではなくサービス名(db)で通信できるのか?」
Docker内部に自動生成される仮想ブリッジネットワーク(Bridge Network)やDNSサーバーの驚くべき仕組みを徹底的に解き明かします。お楽しみに!
コメント
コメントを投稿