できない.dev

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 に切り替えれば解消する。

よくある原因

  1. uid 不一致: コンテナの実行ユーザー(イメージ既定の root 以外)の uid がホスト側のファイル所有者と違う
  2. SELinux 拒否: RHEL / Fedora 系で avc: denied が出る(bind mount にラベルが無い)
  3. userns-remap: rootless / Docker Desktop で uid が再マップされ、ホスト側の uid と食い違う(公式の userns-remap ドキュメント 参照)
  4. 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 myimage

named volume は Docker が所有権を管理するため、ホスト側の権限と関係なく書き込める。
永続化目的なら bind mount より移植性が高い。

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