症状

Docker コンテナ内でボリュームマウントしたディレクトリにアクセスすると permission denied エラーが発生する。


結論:まずこれを確認

  1. ホスト側のディレクトリ/ファイルの所有者・パーミッションを確認する
  2. コンテナ内で実行しているユーザーの UID/GID を確認する
  3. SELinux/AppArmor が有効な環境では :z または :Z オプションを試す

トラブルシューティングフロー

    flowchart TD
    A[permission denied 発生] --> B{ホスト側の<br>パーミッションは?}
    B -->|読み取り不可| C[chmod/chown で修正]
    B -->|問題なし| D{コンテナの<br>実行ユーザーは?}
    D -->|root| E{SELinux/AppArmor<br>有効?}
    D -->|root| F[UID/GID 不一致を確認]
    E -->|Yes| G[:z オプションを追加]
    E -->|No| H[Docker Desktop <br>ファイル共有設定を確認]
    F --> I[--user オプションで<br>UID を指定]
    C --> J[再度アクセス確認]
    G --> J
    H --> J
    I --> J
  

よくある原因

  • ホスト側のパーミッション不足 - マウント元のディレクトリ/ファイルに適切な権限がない
  • UID/GID の不一致 - コンテナ内ユーザーとホスト側ファイルの所有者が異なる
  • SELinux のラベル問題 - SELinux 有効環境でコンテキストラベルが付与されていない
  • AppArmor の制限 - AppArmor プロファイルがアクセスを拒否している
  • Docker Desktop のファイル共有設定 - 共有対象ディレクトリに含まれていない(Mac/Windows)
  • 読み取り専用マウント - :ro オプションで書き込みが制限されている
  • 名前付きボリュームの初期化問題 - ボリューム作成時の所有者が異なる

確認手順

ステップ1: エラーメッセージを確認する

    # コンテナのログを確認
docker logs <container_name>

# コンテナ内でコマンド実行時のエラーを確認
docker exec -it <container_name> ls -la /path/to/mount
  

🔍 チェックポイント: Permission denied の対象がファイルかディレクトリか、読み取りか書き込みかを特定する


ステップ2: ホスト側のパーミッションを確認する

    # マウント元のパーミッションを確認
ls -la /host/path/to/directory

# 所有者とグループを確認
stat /host/path/to/directory
  

🔍 チェックポイント: 出力例 drwxr-xr-x 2 user user - 所有者以外は書き込み不可


ステップ3: コンテナ内の実行ユーザーを確認する

    # コンテナ内のユーザーID を確認
docker exec -it <container_name> id

# 出力例: uid=1000(appuser) gid=1000(appuser) groups=1000(appuser)
  

🔍 チェックポイント: ホスト側ファイルの所有者 UID とコンテナ内ユーザーの UID が一致しているか


ステップ4: UID/GID を一致させる

方法A: コンテナ起動時にユーザーを指定

    # ホスト側ユーザーの UID で実行
docker run --user $(id -u):$(id -g) -v /host/path:/container/path image_name
  

方法B: ホスト側のパーミッションを変更

    # 誰でも読み書き可能にする(セキュリティリスクあり)
chmod -R 777 /host/path/to/directory

# または特定ユーザーに所有権を変更
sudo chown -R 1000:1000 /host/path/to/directory
  

🔍 チェックポイント: docker exec -it <container_name> touch /path/to/mount/test でファイル作成できれば成功


ステップ5: SELinux 環境での対処

    # SELinux の状態を確認
getenforce

# ボリュームマウント時に :z オプションを追加
docker run -v /host/path:/container/path:z image_name

# 複数コンテナで共有する場合は :Z(大文字)
docker run -v /host/path:/container/path:Z image_name
  

🔍 チェックポイント: Enforcing と表示される場合は SELinux が有効


ステップ6: Docker Desktop の設定を確認する(Mac/Windows)

Mac の場合:

  1. Docker Desktop → Settings → Resources → File Sharing
  2. マウントしたいディレクトリが一覧に含まれているか確認
  3. 含まれていない場合は追加して Apply & Restart

🔍 チェックポイント: /Users/Volumes/tmp などはデフォルトで共有対象


NG行動(やってはいけないこと)

  • chmod 777 を本番環境で使う - セキュリティリスクが高い。開発環境での一時的な確認のみに留める
  • コンテナを常に root で実行する - セキュリティ上推奨されない。必要最小限の権限で実行する
  • SELinux を無効化する - システム全体のセキュリティが低下する。:z オプションで対処する
  • 原因特定せずに sudo を多用する - 根本原因が隠れて再発する

よくある質問(FAQ)

Q1: Docker Compose の場合はどうする?

A: volumes セクションで同様に :z オプションを指定できる。user ディレクティブで UID を指定することも可能。

    services:
  app:
    image: myapp
    user: "1000:1000"
    volumes:
      - ./data:/app/data:z
  

Q2: 名前付きボリュームでも同じ症状が出る?

A: 出る場合がある。名前付きボリュームはコンテナ初回起動時に作成され、その時のユーザーが所有者になる。docker volume inspect <volume_name> で Mountpoint を確認し、ホスト側から所有者を変更する。

Q3: WSL2 環境で発生する場合は?

A: WSL2 と Windows 間のファイルシステム変換が原因の場合がある。/mnt/c/ 配下ではなく WSL2 内のファイルシステム(/home/ など)を使用すると改善することがある。


関連するエラー・症状

  • (関連記事準備中)
  • (関連記事準備中)
  • (関連記事準備中)

解決しない場合

公式ドキュメント

確認すべきログファイル

    # Docker デーモンのログ(Linux)
journalctl -u docker.service

# コンテナのログ
docker logs --tail 100 <container_name>

# SELinux の拒否ログ
sudo ausearch -m avc -ts recent
  

次に調べるキーワード

  • docker volume uid gid
  • docker userns-remap
  • selinux docker context
  • docker rootless mode permission