docker『Permission Denied』の原因と対処法

docker『Permission Denied』の原因と対処法

「権限がない」系エラーは大きく2種類に分かれる。①クライアントがDockerデーモンへ接続できない(/var/run/docker.sock など)②コンテナ内/ボリューム/ホストファイルのアクセスが拒否される。まず「どの層で拒否されたか(デーモン接続・ホストFS・コンテナFS・セキュリティ機構)」を切り分け、グループ権限・UID/GID・SELinux/AppArmor・マウントオプション・実行ビット/行末/NOEXEC等を順に確認する。

発生条件の分類(どこで拒否されたかを特定)

# 典型メッセージ例
# 1) デーモン接続時
permission denied while trying to connect to the Docker daemon socket
connect /var/run/docker.sock: permission denied

# 2) 実行時/マウント時(ホスト or コンテナ内)
EACCES: permission denied, open '/data/file'
bash: ./start.sh: Permission denied

# 3) セキュリティ機構
AVC denied (SELinux) / AppArmor DENIED / Operation not permitted (capability不足)

デーモン接続エラー(docker.sockの権限/グループ)

# 自分のグループに docker が含まれるか
id -nG | tr ' ' '\n' | grep -x docker || echo "not in docker group"

# 参加と反映
sudo usermod -aG docker "$USER"
newgrp docker   # もしくは再ログイン
docker ps       # 確認

# 一時回避(根本ではない)
sudo docker ps

ホスト→コンテナの権限不一致(UID/GIDの差異)

# ホスト側の所有者/モードを確認
ls -l /path/to/hostdir
stat -c '%u:%g %a %n' /path/to/hostdir

# コンテナ内の実行ユーザーを確認
docker run --rm alpine id
docker run --rm --user 1000:1000 alpine id

# 解決アプローチ
# 1) --user でホストのUID/GIDに合わせる
docker run --rm -v /host/data:/app/data --user $(id -u):$(id -g) image:tag cmd

# 2) ホスト側の所有権/モードを調整(必要最小限で)
sudo chown -R $USER:$USER /host/data
chmod -R u+rwX /host/data

SELinux(RHEL/CentOS/Fedora)での拒否(:z/:Z または chcon)

# バインドマウント時のラベル付与(推奨)
docker run -v /host/data:/app/data:Z  image:tag    # 独占ラベル
docker run -v /host/data:/app/data:z  image:tag    # 共有ラベル

# 既存ディレクトリへラベル適用(最終手段)
sudo chcon -Rt svirt_sandbox_file_t /host/data

# SELinux状態確認
getenforce     # Enforcing/Permissive/Disabled

AppArmor/Capability/セキュリティ制約の回避(最小限で)

# 追加Capability(必要なものだけ)
docker run --cap-add SYS_ADMIN image:tag ...

# AppArmorプロファイルを外す(検証用途のみ)
docker run --security-opt apparmor=unconfined image:tag ...

# rootlessとデバイス/特権操作の非互換に注意
docker info | grep -i rootless

「Permission denied: 実行ファイル」対策(実行ビット/行末/NOEXEC)

# 実行ビット付与
chmod +x ./start.sh

# 行末がCRLFのときbashが失敗する
file start.sh           # CRLFならdos2unixで変換
dos2unix start.sh

# NOEXECマウント上での実行は不可(/tmpなど)
mount | grep noexec
# 別パスへ移動、またはマウントオプションを見直す

Dockerfile/ビルド時の権限(COPY/WORKDIR/–chown)

# 正しい権限でコピーし、実行ビットを付ける
FROM alpine:3.20
RUN adduser -D app && mkdir -p /app
WORKDIR /app
COPY --chown=app:app . /app
RUN chmod +x /app/start.sh
USER app
CMD ["/app/start.sh"]

ボリューム・匿名ボリュームの読取専用/モード問題

# 読取専用マウントだと書込みでEACCES
docker run -v /host/data:/data:ro image:tag sh -c "echo x > /data/a"  # 失敗

# 書込みが必要なら:rw(デフォルト)にする
docker run -v /host/data:/data:rw image:tag ...

Docker Desktop(macOS/Windows)での共有フォルダ権限

# GUI: Settings → Resources → File Sharing にホストディレクトリを追加
# CLIでの確認例(Mac)
ls -led /path/to/share    # posix/ACLでdenyが入っていないか

・企業端末のDLP/アンチウイルスがブロックする例に注意。許可ポリシーへ追加。

WSL2/Windows固有の拒否(NTFS/ACL/管理者権限)

# WSL2内での権限
wsl.exe -d Ubuntu -- sh -lc "id && umask && mount | grep drvfs"

# Windows側パス(/mnt/c/...)をバインドする際はACLの読み書き権限を確認
icacls C:\path\to\share

Kubernetesでの「書けない」:fsGroup / initContainerで整合

# securityContextでグループ書込みを付与
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      securityContext:
        fsGroup: 2000
      containers:
        - name: app
          image: app:1.0
          volumeMounts:
            - name: data
              mountPath: /data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: pvc-data


# initContainerで所有権/パーミッションを整える
initContainers:
  - name: fix-perms
    image: busybox
    command: ["sh","-c","chown -R 1000:1000 /data && chmod -R u+rwX,g+rwX /data"]
    volumeMounts:
      - name: data
        mountPath: /data

rootlessモードの制約(デバイス/特権操作/ポート割当)

# rootlessで失敗する典型(/dev/bus/usb, マウント, 低番ポート<1024)
docker info | grep -i rootless
# 低番ポートは1024以上に変更、またはauthbind/iptables設定を調整

トラブル発生時の最低限ログと再現テンプレ

# 直近エラーとバージョン
docker version
docker info

# 問題のコンテナでの権限とマウントを確認
docker inspect <container> --format '{{json .HostConfig.Binds}}'
docker exec -it <container> sh -lc "id && ls -l /mnt && mount | head"

# 最小再現(read-only / uidずれを意図的に再現)
docker run --rm -v /host/data:/data:ro alpine sh -c "echo test > /data/x"

NG→OK早見表(クイック修正)

# NG: docker グループ不参加 → OK:
sudo usermod -aG docker $USER && newgrp docker

# NG: UID/GID不一致 → OK:
docker run --user $(id -u):$(id -g) -v /host/data:/app/data image

# NG: SELinuxで拒否 → OK:
docker run -v /host/data:/app/data:Z image
# または chcon -Rt svirt_sandbox_file_t /host/data

# NG: スクリプト実行権限なし/CRLF → OK:
chmod +x start.sh && dos2unix start.sh

# NG: read-onlyマウントで書込み → OK:
-v /host/data:/data:rw

# NG: Desktopで未共有のフォルダ → OK:
Settings → Resources → File Sharing に追加

チェックリスト(上から順に潰す)

# 1) どの層で拒否?(デーモン接続 / マウント / 実行)
# 2) 自分はdockerグループか、sudo無しでdocker psは動くか
# 3) マウント先のUID/GIDとコンテナのUSERは一致しているか
# 4) SELinuxなら :z/:Z or chcon、AppArmor/Capabilityは最小付与か
# 5) 実行ビット、行末LF、NOEXECマウントを確認したか
# 6) Desktop/WSL2では共有フォルダとACLを許可したか
# 7) K8sではfsGroup/initContainerで整合を取ったか
# 8) 変更後は docker inspect / exec で実際に権限が直ったか