クイックスタート:5分で立ち上げるRootless Docker
一般ユーザーアカウントを持つUbuntu 22.04またはDebian 12サーバーがあれば、永続的なroot権限を付与することなく、すぐにDockerデーモンを起動できます。
ステップ1:依存パッケージのインストール
Rootless Dockerには、UID/GIDをマッピングするためのuidmapと、ユーザースペースで仮想ネットワークスタックを作成するためのslirp4netnsが必要です。以下のコマンドを実行してインストールします:
sudo apt-get update
sudo apt-get install -y uidmap dbus-user-session slirp4netns
自身のユーザーに対してsubuidの範囲設定ファイルが準備されているか確認します:
grep $(whoami) /etc/subuid /etc/subgid
出力がubuntu:100000:65536のような形式であれば、コンテナに65,536個の仮想UIDを割り当てる準備が整っています。
ステップ2:インストールスクリプトの取得と実行
sudo権限から完全にログアウトし、一般ユーザーとして以下のコマンドを実行します:
curl -fsSL https://get.docker.com/rootless | sh
ステップ3:ソケットの定義とサービスの有効化
スクリプトによってユーザーのランタイムディレクトリに専用ソケットが作成されます。Docker CLIがこれを認識できるよう、~/.bashrcに環境変数を追加します:
echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc
echo 'export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock' >> ~/.bashrc
source ~/.bashrc
systemdのユーザーインスタンス経由でバックグラウンドサービスを有効化します:
systemctl --user enable --now docker
systemctl --user status docker
ステップ4:動作確認
サンプルコンテナを実行して確認します:
docker run --rm hello-world
ウェルカムメッセージが表示されれば、デーモンは正常に稼働しています。このプロセス全体が、完全に分離されたユーザー名前空間内で実行されます。
リスクの本質:デフォルトのDockerはなぜ危険なのか?
実質的なroot権限付与となるDockerグループ
多くのシステム管理者は、sudoなしでコマンドを実行できるようにするため、安易にユーザーをdockerグループに追加しがちです。しかし、これは重大なセキュリティホールを生み出します。Dockerソケットにアクセスできるユーザーは誰でも、ホストのルートディレクトリ/をコンテナにマウントし、コマンド1つで/etc/shadowファイルを改ざんできてしまいます。
コンテナエスケープのリスク
Webアプリケーションは常にRCE(リモートコード実行)の脅威に晒されています。さらに、有名なruncの脆弱性CVE-2019-5736や、ファイル記述子リークの脆弱性CVE-2024-21626(Leaky Vessels)のように、ランタイム層自体に脆弱性が存在することもあります。
Dockerデーモンがホストのroot権限で稼働している場合、攻撃者はコンテナから脱出(ブレイクアウト)した瞬間、サーバー全体の制御権を手に入れることになります。その結果、悪意あるコードにシステムを乗っ取られ、機密データが窃取される事態に陥ります。
Rootless Dockerによる多層防御の仕組み
Rootless Dockerは、Linuxのユーザー名前空間(User Namespaces)を活用することで、このリスク構造を根本から覆します。コンテナ内では、アプリケーションは自身をroot(UID 0)として認識しますが、ホストOS側から見ると、そのプロセスは単なる一般ユーザー(例:UID 1001)として実行されています。
万が一攻撃者がコンテナを侵害してホスト側に脱出できたとしても、権限は一般ユーザー(UID 1001)にとどまります。システムファイルを上書きしたり、他のユーザーのプロセスに干渉したりすることはできないため、ホストシステムへの被害を防ぐことができます。
本番環境向け設定:ポート開放・Linger・リソース制限
1. 1024未満の特権ポートを開放する
Linuxではデフォルトで、一般ユーザーが80や443などの1024未満のポートをバインドすることが制限されています。NginxやTraefikを直接リッスンさせるには、カーネルの特権ポートしきい値を引き下げる必要があります:
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/50-rootless-docker.conf
sudo sysctl --system
この設定により、Rootless DockerでPermission Deniedエラーを起こすことなく、80番や443番ポートを問題なくマッピングできるようになります。
2. SSHログアウト後もコンテナを維持する(Linger)
デフォルトでは、systemdはSSHセッションが切断されるとユーザーの全プロセスをクリーンアップします。コンテナを独立したサービスとして24時間365日常駐稼働させるには、linger機能を有効化する必要があります:
loginctl enable-linger $(whoami)
3. cgroup v2によるCPUおよびメモリの制限
Rootlessモードでコンテナのリソース制限を行うには、ホストでcgroup v2が有効になっている必要があります。以下のコマンドで確認してください:
docker info | grep -i cgroup
出力結果がCgroup Version: 2であってもコントローラーの不足に関する警告が出る場合は、一般ユーザーがCPUやメモリリソースを管理できるよう、systemdの委任(delegation)を設定します:
sudo mkdir -p /etc/systemd/system/[email protected]
cat <<EOF | sudo tee /etc/systemd/system/[email protected]/delegate.conf
[Service]
Delegate=cpu cpuset io memory pids
EOF
sudo systemctl daemon-reload
これで通常どおりリソースを制限してコンテナを起動できます:
docker run -d --name cache-redis --memory="512m" --cpus="1.0" redis:alpine
Rootless運用における実践ノウハウ
RootfulとRootlessのスムーズな切り替え
サーバー上でシステム全体の通常Docker(Rootful)とユーザーごとのRootless Dockerが共存している場合、環境変数を都度exportする代わりにDocker Contextを使って切り替えるのが便利です:
# Rootless用のコンテキストを作成
docker context create rootless-local --description "User daemon" --docker "host=unix://$XDG_RUNTIME_DIR/docker.sock"
# 作業コンテキストを切り替え
docker context use rootless-local
Unixソケット経由でのDocker Engine APIのデバッグ
内部CI/CDパイプラインにおいて、ソケット経由でDocker APIを直接呼び出すことは多くの自動化タスクで役立ちます。curlを使用してコンテナ一覧を取得できます:
curl --unix-socket $XDG_RUNTIME_DIR/docker.sock http://localhost/containers/json
Docker APIから返されるJSONデータは非常に長大で視認性が悪いことがよくあります。取得したペイロードをtoolcraft.app JSON Formatterに貼り付けることで、マウント階層やネットワークパラメータを整形・可視化できます。余計な拡張機能をインストールすることなく、直感的に設定の不備を発見できるため便利です。
ネットワークパフォーマンスのトレードオフ
仮想ネットワーク層であるslirp4netnsはパケット処理を完全にユーザースペースで行うため、従来のブリッジネットワークと比較してわずかにレイテンシが増加します。スループットは15〜30%低下する可能性があり、高負荷時にはCPU使用率が約5〜10%余計に消費されます。
毎秒数万リクエストを処理するマイクロサービスなどを運用する場合は、pastaドライバー(パッケージが利用可能であればDocker Engine 24.0以降でデフォルト)への移行を検討するか、最大限のパフォーマンスが必要な場合は--net=hostの利用を検討してください。

