Docker のボリュームマウントで permission denied になり書き込めない
bind mount したホストディレクトリに対しコンテナ側の uid/gid が一致しないと書き込めない。
--user で uid を揃える、:Z で SELinux ラベルを付ける、named volume に切り替える、の 3 系統で対処する。
#volume#permission#bind-mount#uid#selinux
公開:
要約
Permission denied が bind mount の中で起きるのは、コンテナ内プロセスの uid/gid とホスト側ディレクトリの所有者が一致していない ことが原因の大半。--user で実行 uid を揃える、:Z で SELinux ラベルを付ける、もしくは named volume に切り替えれば解消する。
よくある原因
- uid 不一致: コンテナの実行ユーザー(イメージ既定の
root以外)の uid がホスト側のファイル所有者と違う - SELinux 拒否: RHEL / Fedora 系で
avc: deniedが出る(bind mount にラベルが無い) - userns-remap: rootless / Docker Desktop で uid が再マップされ、ホスト側の uid と食い違う(公式の userns-remap ドキュメント 参照)
- mount 種別の取り違え: macOS / Windows でホストパスを直接 bind し、所有権の概念が崩れる
解決策
1. ホストの uid/gid で実行
docker run --rm \
-u "$(id -u):$(id -g)" \
-v "$PWD:/work" \
alpine sh -c 'touch /work/hello'コンテナ内で書いたファイルが ホスト側でも自分の所有 で残る。
開発端末で最も手早い対処。
2. SELinux ラベルを付ける
docker run -v "$PWD:/work:Z" alpine ...:Z は そのコンテナ専用 にラベルを付け、:z は他のコンテナと共有可能にする。
詳細は bind mount の公式ドキュメント を参照。
3. コンテナ内で所有者を揃える
RUN useradd -u 1000 -m appuser && \
mkdir -p /data && chown appuser:appuser /data
USER appuserイメージ側で uid 1000 を作っておけば、ホスト側のユーザー(多くの Linux で uid 1000)とぶつからない。
4. named volume を使う
docker volume create app-data
docker run -v app-data:/data myimagenamed volume は Docker が所有権を管理するため、ホスト側の権限と関係なく書き込める。
永続化目的なら bind mount より移植性が高い。