動かない時
bind mount で permission denied
bind mount したディレクトリにコンテナから書き込めない、読めない問題。UID/GID 不一致、SELinux の `:z`/`:Z` ラベル、rootless コンテナの user namespace を順に切り分けます。
症状
docker run -v $(pwd):/app ...でコンテナ内から/appに書き込むとPermission denied- 書けはするがホスト側から見ると
root:rootの所有になってしまい後で困る - RHEL / Fedora / CentOS Stream で 何もしていないのに
Permission denied(他のディストリでは動くのに) - rootless Podman / rootless Docker で実行中、ホスト UID と違う UID で所有されてしまう
原因 1: UID/GID 不一致
bind mount は Linux カーネルにとって「ホストの同じディレクトリ」そのものです。
ファイルの所有 UID/GID はホストの値であり、コンテナ内のプロセスが書き込むときも UID はコンテナプロセスのものになります。
- ホスト側でディレクトリが UID=1000 所有で
mode=755(rwxr-xr-x)になっている - コンテナ内アプリは
USER node(UID=1000 のことが多い)やroot(UID=0)で動いている - UID が一致せず、かつ
othersに書き込み権限がないため失敗する、または root で書いた結果ホストから見てroot:rootになる
原因 2: SELinux ラベル(RHEL 系)
RHEL・Fedora・CentOS Stream など SELinux が enforcing で動く環境では、bind mount 元のディレクトリがコンテナ用のラベル(container_file_t)を持っていないとコンテナから触れません。
UID が正しくてもカーネル層で拒否されるため、ls -l からは原因が分からず詰まります。
ls -lZ で SELinux コンテキストを見ると unconfined_u:object_r:user_home_t:s0 のようにホーム用のラベルのままになっています。
これが container_file_t に変わっていないのが原因です。
原因 3: rootless の user namespace(UID シフト)
rootless Podman や rootless Docker では、コンテナ内の UID=0 はホストから見ると「UID=100000+α」といった別の UID にマッピングされます(/etc/subuid の設定による)。
- ホストで自分の UID(例: 1000)で所有しているディレクトリを bind mount する
- コンテナ内で UID=0(ホストから見ると 100000)として書き込むと Permission denied
- コンテナ内で意図的に UID=1 で動かす設定にすると、ホストから見ると UID=100001 で所有され、元ユーザーから触れないファイルが生成される
確認コマンド
bash
# ホスト側: 所有とパーミッション
ls -la ./data
stat ./data
# ホスト側: SELinux コンテキスト(RHEL 系)
ls -laZ ./data
getenforce # Enforcing / Permissive / Disabled
# コンテナ内: 実効 UID/GID
docker run --rm -v $(pwd)/data:/app alpine id
docker run --rm -v $(pwd)/data:/app alpine stat /app
# rootless 環境の UID マッピング
cat /etc/subuid /etc/subgid
podman unshare cat /proc/self/uid_map解決策
- UID/GID 不一致:
- コンテナ側の UID をホストに合わせる:
docker run --user $(id -u):$(id -g) -v $(pwd):/app ... - Dockerfile で
USER 1000などと固定し、ホスト側で同じ UID を使う運用に揃える - 書き込み対象は専用のデータディレクトリに切り、ホスト側で
chown -R 1000:1000 ./data
- コンテナ側の UID をホストに合わせる:
- SELinux(RHEL 系):
- 共有マウント(他コンテナとも共有して良い)なら
:zを付ける:-v $(pwd):/app:z - 専用マウント(このコンテナ専用)なら
:Zを付ける:-v $(pwd):/app:Z - どちらもカーネルが自動で
container_file_tラベルを設定する。:Zは他コンテナから触れなくなるので、共有の有無で使い分ける - 切り分け中にだけ
setenforce 0で一時的に Permissive にするのは OK。恒久的に無効化する運用は避ける
- 共有マウント(他コンテナとも共有して良い)なら
- rootless:
- ホスト UID をそのままコンテナに持ち込む:
podman run --userns=keep-id ...(Podman)または Docker の--userns-remap設定を見直す - 書き込み先はホームの書ける場所(
$HOME配下)にし、/etc/subuidのレンジがログインユーザーに割り当てられていることを確認
- ホスト UID をそのままコンテナに持ち込む:
- 対症療法としての緩和策:
- どうしても急ぐときはホスト側で
chmod 777 ./dataが動くが、本番・共有環境では厳禁。切り分けが終わったら必ず戻す
- どうしても急ぐときはホスト側で
