深夜2時の緊急呼び出し
新しいサービスをデプロイ中、すべて順調に見えたその瞬間、こんなエラーが出る:
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.24/info: dial unix /var%2Frun%2Fdocker.sock: connect: permission denied
何も変更していない。昨日まで Docker は動いていた。それが今は動かない。2つのコマンドで何が壊れたかすぐわかる――修正は1分もかからない。
実際に何が起きているのか
Docker はデーモンとの通信に /var/run/docker.sock の Unix ソケットを使用します。このソケットは root と docker グループが所有し、パーミッションは 660 です。ユーザーが docker グループに属していない場合、OS は接続を完全に拒否します。
これは通常、以下の場合に発生します:
- docker グループへの追加なしで新しいユーザーアカウントが作成された
- Docker をインストールしたばかりで、まだログアウト・ログインし直していない
- CI/CD ランナーが非特権のサービスアカウントで実行されている
- システムのクリーンアップ中に
deluserが実行されたか、グループのメンバーシップが変更された
まず原因を確認する
何かを変更する前に、根本原因を確認しましょう。次の順番で実行してください:
1. 現在のユーザーとグループを確認する
whoami
groups
出力に docker がない?それが答えです。
2. ソケットのパーミッションを確認する
ls -la /var/run/docker.sock
期待される出力:
srw-rw---- 1 root docker 0 Mar 17 02:14 /var/run/docker.sock
所有者は root:docker、モードは 660 のはずです。600 や別のグループが表示される場合、それが原因です。
3. docker グループの存在を確認する
getent group docker
出力がない場合、グループがまだ存在しません。誰かを追加する前にグループを作成する必要があります。
修正する
方法1:ユーザーを docker グループに追加する(恒久的な修正)
開発マシンや自分がアカウントを所有するサーバーに適した方法です。
# 現在のユーザーを docker グループに追加する
sudo usermod -aG docker $USER
# ログアウトなしでグループの変更を適用する
newgrp docker
newgrp docker を実行すると、docker グループがすぐに有効な新しいシェルが起動します。テストしてみましょう:
docker ps
これが動作すれば、このセッションは完了です。すべての将来のターミナルで有効にするには、ログアウトしてログインし直してください。
自分ではなく特定のユーザーを対象にする場合:
sudo usermod -aG docker username
方法2:ソケットのパーミッションを修正する(緊急の一時対応)
今すぐ Docker を動かす必要があり、ログアウトできない?
sudo chmod 666 /var/run/docker.sock
即座に有効になります。トレードオフとして、マシン上のすべてのローカルユーザーが Docker を制御できるようになります――これは root 相当のアクセス権です。個人の開発マシンでは問題ありませんが、共有サーバーでは深刻な問題になります。
また、Docker は再起動時にこのパーミッションをリセットするため、恒久的な修正にはなりません。
方法3:docker グループが存在しない場合は作成する
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
方法4:sudo を使用する(長期的には非推奨)
sudo docker ps
2秒で解決できます。ただし長期的には、ボリュームのパーミッション問題が発生します――コンテナ内で書き込まれたファイルはホスト上で root が所有することになります。日常的なワークフローではなく、一時的なデバッグ用に使用してください。
修正を確認する
修正を適用したら、sudo なしで Docker が応答することを確認してください:
# 完全な接続確認
docker info
# 期待値:コンテナ数、ストレージドライバーなどのサーバー情報ブロック
# クライアント:
# コンテキスト: default
# デバッグモード: false
# サーバー:
# コンテナ数: 3
# 実行中: 1
# ...
# コンテナをエンドツーエンドで実行する
docker run --rm hello-world
docker info のサーバーブロックにエラーがなければ、ソケット接続は正常です。
CI/CD と自動化環境
GitHub Actions、GitLab CI、Jenkins のセルフホストランナーは通常、専用のサービスアカウントで実行されます。同じ修正が適用されます――そのアカウントを対象にするだけです:
# ランナーが実行されているユーザーを確認する
ps aux | grep runner
# そのユーザーを追加する
sudo usermod -aG docker gitlab-runner
sudo systemctl restart gitlab-runner
ホストソケットをコンテナにマウントする Docker-in-Docker の設定は、また別の問題です:
docker run -v /var/run/docker.sock:/var/run/docker.sock your-image
コンテナのユーザーはホスト上の docker グループの GID と一致する必要があります。GID が一致しない場合、全く同じパーミッションの壁にぶつかります――今度はコンテナの内側で。
パーミッションビットを解読する
深夜に srw-rw---- を見て頭が働かない時は、ToolCraft の Unix Permissions Calculator がそのビットを平易な言葉で即座に説明してくれます。ブラウザで動作し、データはどこにも送信されません。
教訓
- docker グループの設定をプロビジョニングスクリプトに組み込む。 Ansible、cloud-init、Terraform ユーザーデータ、手動のランブック――どれでも構いません。Docker インストール直後の標準ステップとして
usermod -aG dockerを追加してください。このエラーは適切にプロビジョニングされたマシンではほぼ発生しません。 newgrp dockerはここでの最強の味方です。 ログアウト不要。何かを閉じる前に修正を確認できる、グループを認識したシェルをすぐに提供してくれます。- ソケットを chmod 777 しない。
666でさえ意図的なトレードオフです。777は何の役にも立たない実行ビットを追加し、ある程度まともなセキュリティスキャンで検出されます。 - CI ランナーのパーミッションは初日に確認する。 新しい CI 環境を立ち上げる際は、
docker psをパイプラインの最初のステップにしてください。5秒の検証で、1週間後にパイプラインが失敗する30分のデバッグを防げます。

