🐳

Dockerバインドマウントでのファイルシステム差分による大文字/小文字問題

に公開

これは何?

ローカル環境では正常に動いていたコードが、CI環境では動かない、という現象に遭遇しました。調査の結果、ファイルシステムごとで大文字/小文字の扱いが違うことが原因であると判明しました。

この記事では、その調査で得た学びを備忘録としてまとめました。

起きた事象、原因、解決策について

発生した事象

起きた事象について簡単に説明すると、ローカル環境ではファイル名の大文字/小文字を区別しない(以降case-insensitive)が、CI環境ではファイル名の大文字/小文字を区別する(以降case-sensitive)、ということが原因でファイルの読み込みエラーが発生していました。

具体的には、期待するファイル名が hogeFuga.json の場合に以下のような挙動を確認しました。

環境 コード上でhogeFuga.jsonと指定 コード上でhogefuga.jsonと指定
ローカル (macOS / APFS)
CI (Ubuntu 20.04 / ext4)

原因

上記の違いが起こったのはdockerのバインドマウントを利用していることが原因でした。ホスト側のファイルシステムをコンテナにマウントするので、ホストであるmacOSのAPFSの挙動がそのままコンテナに反映された、ということです。

※APFSはデフォルトがcase-insensitive

解決策

ドキュメントの内容と実際の挙動に乖離があることは気になりましたが、ひとまずCI環境(ubuntu)でも動作させたいという要件を達成するためにコードをcase-sensitiveで動くように修正しました。

これで無事ローカル環境、CI環境どちらでもコードが動作するようになりました。

まとめ

  • Dockerのバインドマウントではホストのファイルシステムの特性がそのまま反映される
    • MacではAPFS、Linuxではext4を採用
      • APFS:case-insensitive
      • ext4:case-sensitive
    • 環境差分を無くすために、ファイル名はcase-sensitiveで統一するのが無難

Docker(コンテナ型仮想化)で環境差分を吸収できると慢心していましたが、バインドマウントを利用する場合はホスト側のファイルシステムの違いに注意が必要、という学びがありました。

補足

APFSでcase-sensitiveなマウントを作成する方法

どうやらボリュームの作り方を工夫すれば大文字/小文字の区別をさせられるようです。
https://forums.docker.com/t/volume-mounts-case-insensitive/18867/3
https://github.com/docker/for-mac/issues/320#issuecomment-428656077

同じような事象に関する資料

調べてみると同じようなことが起きている数年前の資料がいくつか出てきました。
https://please-sleep.cou929.nu/afps-and-docker-for-mac-fs-case-sensitivity.html
https://qiita.com/ABE_TAKASHI/items/5bfd526862385d301f53
https://qiita.com/yutachaos/items/544a6b547303ca7bcb85
https://stackoverflow.com/questions/64645430/why-does-mac-osx-still-exhibit-case-insensitivity-when-using-docker-desktop-for

ファイルシステムの確認

Mac

$ diskutil info / | grep 'File System Personality'

もしくは

$ mount | grep '/dev/disk'

Linux

$ df -T

もしくは

$ mount

Discussion