できない.dev

Docker の .dockerignore が効かずファイルを除外できない

.dockerignore はビルドコンテキストのルート直下に置き、glob 構文と否定 (!) の順序を正しく書かないと無視されない。
ファイル名・配置・BuildKit の仕様差で詰まる。

#dockerignore#build#context#copy#buildkit

公開:

要約

.dockerignoreビルドコンテキストのルート直下 に置いた時だけ評価される。
サブディレクトリに置いた、ファイル名のスペルが違う、否定 ! の順序が逆、のいずれかで無視される。docker build --progress=plain でコンテキスト送信の様子を見ながら原因を切り分ける。

よくある原因

  1. 配置ミス: docker build . で渡したパスの直下に置かないと参照されない。docker build -f path/Dockerfile path/ のとき .dockerignorepath/ 直下
  2. ファイル名の typo / 大文字小文字: .dockerIgnore / dockerignore / .dockerignore.txt などはすべて無視される。
    Linux / macOS は大小区別する
  3. glob 構文の誤解: Docker の構文は 公式 dockerignore リファレンス に明記された独自仕様。** は再帰、! は否定で 後勝ち
  4. BuildKit / classic の差異: DOCKER_BUILDKIT=1 の有無で送られるファイル一覧の評価タイミングが変わる。
    CI と手元で違いやすい

解決策

1. 正しい配置を確認する

ls -la .dockerignore       # コンテキスト直下にあるか
docker build -t app .      # 「.」がコンテキスト

サブディレクトリ専用の .dockerignore を Docker は読まない(Compose のサービスごとに別コンテキストを指定する場合のみ意味を持つ)。

2. パターンを書き直す

# すべての .log を除外
**/*.log
 
# node_modules / .git は丸ごと除外
node_modules
.git
 
# ただし keepme.log だけは残す(否定は後ろに書く)
!keepme.log

否定 !マッチした除外を取り消す ため、先に広く除外してから例外を許可する順番でないと効かない。
詳細は Build context のドキュメント を参照。

3. 実際に送られたファイル量を確認する

DOCKER_BUILDKIT=1 docker build --progress=plain --no-cache -t app . 2>&1 | head -40

transferring context 行のサイズが想定より大きい場合、.dockerignore で除外しきれていない。du -sh .git node_modules などで大きい候補を洗い出す。

4. Compose で別コンテキストを使う場合

services:
  app:
    build:
      context: ./services/app
      dockerfile: Dockerfile

このとき .dockerignore./services/app/.dockerignore に置く。
プロジェクトルートの .dockerignore は参照されない。

この記事は役立ちましたか?