config.json の bind mount が EACCES になるとき、環境変数に逃がす
- 記録日
- 2026-08-04
- 対象
- NAS 独自 OS 上の Docker / docker compose
- 症状
- 設定ファイルのマウント時に EACCES で起動失敗
コンテナの設定ファイルを、ホスト側に置いて bind mount する。よくあるやり方だが、NAS ベンダーの独自 OS 上ではこれが素直に通らないことがある。
services:
app:
image: example/app
volumes:
- ./config.json:/app/config.json:ro # ここで EACCES
共有フォルダの実体が、独自の権限管理レイヤの下にあるためで、ホスト側でいくら chmod や chown をしてもコンテナ内のプロセスから読めない、という状況になる。
ディレクトリごとマウントしても解決しないことがある
単一ファイルの bind mount は inode 単位でのマウントになるため相性問題を起こしやすい、というのは一般論として知られている。だからディレクトリごとマウントするのが定石なのだが、権限レイヤ側で弾かれている場合はこれでも通らない。
コンテナ側が対応していれば、環境変数に逃がす
最近のイメージは、設定を環境変数で丸ごと渡せるものが増えている。CONFIG のような変数に JSON をそのまま入れる方式で、これならファイルシステムを一切経由しない。
services:
app:
image: example/app
environment:
CONFIG: |
{
"listen": "0.0.0.0:8080",
"options": {
"verbose": false
}
}
YAML のブロックスカラー(|)で書けるので、JSON をエスケープする必要もない。設定が docker-compose.yml に集約されるため、バックアップ対象が 1 ファイルで済むという副次的な利点もある。
使えるかどうかの確認
イメージの entrypoint を読むのが確実だが、手っ取り早くはドキュメントで _FILE サフィックスや CONFIG 系の環境変数がサポートされているかを見る。対応していない場合は、素直に named volume を使い、初回だけコンテナ内から設定を書き込む方式に切り替えるのが早い。
教訓
- NAS の独自 OS 上の Docker は、素の Linux と同じ挙動を期待しない
- 権限で詰まったら、ファイルシステムを経由しない経路がないか探す
- 回避策が見つかったら、なぜそれを選んだかを compose ファイルにコメントで残す。半年後の自分は理由を覚えていない