`.dockerignore`テンプレートのglobパターンを`**`に変更し、深いネストのファイルを確実に除外
Railsアプリ生成時の.dockerignoreテンプレートで、単一階層のglobパターン(*)を再帰的パターン(**)に置き換え、サブディレクトリ以下のファイルがDockerビルドコンテキストに含まれてしまう問題を修正しました。
背景
従来の*パターンはディレクトリ直下のファイルにしかマッチせず、深くネストされたファイルがDockerビルドコンテキストに混入するリスクがありました。Dockerの.dockerignoreにおける*は1階層のワイルドカードであり、/tmp/*と書いてもtmp/cache/assets/sprockets/v4.0.0/ab/abcdef1234...のような深いパスはマッチしません。
この制約により、以下のファイルが意図せずビルドコンテキストに含まれていました:
-
Sprocketsのアセットキャッシュ(
tmp/cache/assets/sprockets/v4.0.0/...):深くネストされており、ビルドコンテキストを不必要に肥大化させる -
サーバーPIDファイル(
tmp/pids/server.pid):サブディレクトリ内のため除外されない -
Active Storageのディスクサービスが管理するファイル(
storage/ab/cd/abcdefghijklmn):キープレフィックスによる2階層の構造のため、アップロードされたユーザーファイルがイメージに混入するリスクがあった
特にActive Storageの問題は、開発環境でアップロードしたユーザーデータが本番向けDockerイメージに含まれてしまうというセキュリティ上の懸念にもなりえます。
技術的な変更
railties/lib/rails/generators/rails/app/templates/dockerignore.ttに対して、4行の追加と8行の削除が行われました。
変更前:
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/.keep
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/.keep
/app/assets/builds/*
変更後:
/log/**
/tmp/**
!/log/.keep
!/tmp/.keep
!/tmp/pids/.keep
/storage/**
!/storage/.keep
!/tmp/storage/.keep
/app/assets/builds/**
変更のポイントは2つあります。第1に、/log/*・/tmp/*・/storage/*・/app/assets/builds/*の*をすべて**に変更しました。これにより任意の深さのサブディレクトリ以下まで再帰的にマッチするようになります。第2に、/tmp/pids/*と/tmp/storage/*という個別のパターンを削除しました。これらは/tmp/**に包含されるため冗長であり、また*パターンのままでは/tmp/**と組み合わせても意味がありませんでした。
.keepファイルの否定パターン(!プレフィックス)はすべて維持されており、ディレクトリ構造を保持するための.keepファイルは引き続きビルドコンテキストに含まれます。
設計判断
/tmp/pids/*と/tmp/storage/*の個別パターンを削除し、`/tmp/`一本に集約する**方針が採用されました。
/tmp/**が有効であれば/tmp/pids/*は冗長になります。さらに、/tmp/pids/.keepと/tmp/storage/.keepの否定パターンも/tmp/.keepと並べてまとめて記述するよう整理され、可読性が向上しています。コメント「Ignore pidfiles, but keep the directory.」も/tmp/pids/*の削除とともに取り除かれており、テンプレートのノイズが減っています。
また、**への変更は既存のDockerfileの動作を壊しません。**は*のスーパーセットとして機能し、これまで除外されていたファイルは引き続き除外され、さらに深いネストのファイルも新たに除外されるようになります。
まとめ
この変更は、.dockerignoreの*と**の挙動の違いという見落とされやすい落とし穴を修正するものです。特にActive Storageを使用するアプリケーションでは、開発中にアップロードしたファイルがDockerイメージに混入するリスクがなくなり、イメージの肥大化防止とセキュリティの両面で意義があります。