Rootless Docker 完全ガイド - 仕組み・セットアップ・注意点まとめ
Rootless Docker を使うと、root 権限なしで Docker デーモンを動かせるため、ホストへの影響を最小限に抑えたセキュアなコンテナ実行が実現できます。本記事では仕組みの基礎から実際のセットアップ・よくあるハマりどころまでを実務目線でまとめます。
Rootless Docker とは
通常の Docker デーモン (dockerd) は root ユーザーとして動作します。これはコンテナを特権なしで隔離するうえで必要な権限ですが、ホストシステムへの影響範囲が広くなるというリスクがあります。
Rootless Docker は、Docker デーモンおよびコンテナを一般ユーザー権限内で動作させる仕組みです。2020 年の Docker 20.10 から正式サポートされました。
通常の Docker:
root → dockerd → container
Rootless Docker:
一般ユーザー → rootlesskit → dockerd → container
仕組み
rootlesskit
rootlesskit は「Linux の名前空間を使って、あたかも root であるかのような環境」を一般ユーザーに提供するラッパーツールです。Rootless Docker の根幹をなすコンポーネントで、dockerd はこの中で動作します。
User Namespace
Linux カーネルの user namespace により、コンテナ内の UID 0(root)をホスト上の一般ユーザー UID にマッピングします。
コンテナ内: UID 0 (root)
↕ /etc/subuid マッピング
ホスト上: UID 1000 (alice) → UID 100000〜165535
マッピングの設定ファイル:
# /etc/subuid
alice:100000:65536
# /etc/subgid
alice:100000:65536
cgroup v2
cgroup v2 では、一般ユーザーが自身のプロセスに対してリソース制限を設定できます(delegation 機能)。Rootless Docker はこれを利用して、root なしでもメモリ・CPU 制限が効くようになっています。
cgroup v2 が有効かどうかは以下で確認できます。
# 方法1: cgroup.controllers ファイルの存在確認(推奨)
ls /sys/fs/cgroup/cgroup.controllers
# cpu cpuset hugetlb io memory pids ← 表示されれば cgroup v2
# 方法2: マウント情報から確認
mount | grep cgroup2
# cgroup2 on /sys/fs/cgroup type cgroup2 ... ← これが表示されれば有効
ネットワーク (slirp4netns / pasta)
root なしでは TUN/TAP デバイスを直接扱えないため、ユーザー空間のネットワークスタック実装が使われます。
- slirp4netns: 従来の標準実装。NAT 方式でホストネットワークに接続。
- pasta: より新しい実装で slirp4netns より高速。Docker 27 以降で推奨。
インストール・セットアップ
前提条件の確認
# カーネルバージョン (5.11+ 推奨)
uname -r
# cgroup v2 有効確認
cat /proc/1/cgroup
# 0::/ と表示されれば cgroup v2
# subuid/subgid の確認
grep $(whoami) /etc/subuid /etc/subgid
必要パッケージのインストール
sudo apt update
sudo apt install -y \
uidmap \
dbus-user-session \
fuse-overlayfs \
slirp4netns
| パッケージ | 用途 |
|---|---|
uidmap | newuidmap / newgidmap コマンドを提供 |
dbus-user-session | ユーザーセッション用 D-Bus(systemd 連携に必要) |
fuse-overlayfs | overlay2 ストレージドライバの代替 |
slirp4netns | ユーザー空間ネットワーク |
Rootless Docker のインストール
方法 1: 公式スクリプトを使う(推奨)
curl -fsSL https://get.docker.com/rootless | sh
スクリプト実行後、指示に従って環境変数を設定します。
# ~/.bashrc や ~/.zshrc に追記
export PATH=$HOME/bin:$PATH
# XDG_RUNTIME_DIR が設定されている場合
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
# 明示的なパスで書く場合(より確実)
# export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
方法 2: Docker CE パッケージから移行する
# docker-ce-rootless-extras をインストール
sudo apt install -y docker-ce-rootless-extras
# Rootless モードのセットアップ実行(一般ユーザーで実行)
dockerd-rootless-setuptool.sh install
systemd ユーザーサービスとして登録
# サービス有効化・起動
systemctl --user enable docker
systemctl --user start docker
# ログイン不要で起動させる(サーバー用途)
sudo loginctl enable-linger $(whoami)
# 動作確認
systemctl --user status docker
docker info
動作テスト
docker run --rm hello-world
docker run --rm -p 8080:80 nginx
メリット
| メリット | 説明 |
|---|---|
| セキュリティ向上 | デーモン侵害時でもホスト root を奪取されにくい |
| マルチユーザー対応 | 各ユーザーが独立した Docker 環境を持てる |
| CI 環境での利用 | 特権不要のため SaaS CI などでも動作しやすい |
| コンテナランタイム侵害時の被害局所化 | コンテナエスケープが成功してもユーザー権限内にとどまる |
デメリット・制限事項
| デメリット | 内容 |
|---|---|
| 1024 以下のポートはバインドできない | ルーティングの工夫が必要(後述) |
| overlay2 が使えない環境がある | fuse-overlayfs にフォールバック(速度低下) |
| cgroup v1 環境ではリソース制限が一部無効 | Ubuntu 22.04 以降は基本 v2 なので問題少ない |
| ネットワーク性能がやや低下 | slirp4netns/pasta 経由のオーバーヘッド |
| AppArmor / SELinux との相性 | ディストリビューションによって追加設定が必要 |
よくあるハマりどころ・注意点
1. 1024 以下のポートがバインドできない
Rootless コンテナはユーザー権限で動くため、-p 80:80 のような特権ポートバインドが失敗します。
# エラー例
docker run -p 80:80 nginx
# Error response from daemon: driver failed programming external connectivity
対策 1: ポート番号を変える(推奨)
docker run -p 8080:80 nginx
対策 2: net.ipv4.ip_unprivileged_port_start を変更する
# 一時的に変更
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
# 恒久的に変更
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/99-rootless-docker.conf
sudo sysctl --system
2. overlay2 ストレージドライバが使えない
カーネルが unprivileged overlay を許可していない環境では fuse-overlayfs が使われます。
docker info | grep "Storage Driver"
# Storage Driver: fuse-overlayfs ← overlay2 より遅い
# overlay2 を有効にするには(Ubuntu 22.04+)
echo '{ "storage-driver": "overlay2" }' > ~/.config/docker/daemon.json
systemctl --user restart docker
カーネル 5.11+ かつ Ubuntu 22.04 以降では設定なしで overlay2 が使えることが多いです。
3. cgroup v2 の delegate 設定
コンテナへのリソース制限(--memory, --cpus)が効かない場合は、systemd の delegate 設定を確認します。
# delegate が有効か確認
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers
# memory pids cpu io ← これらが表示されれば OK
# 有効でない場合は /etc/systemd/system/user@.service.d/ に設定を追加
sudo mkdir -p /etc/systemd/system/user@.service.d/
cat <<EOF | sudo tee /etc/systemd/system/user@.service.d/delegate.conf
[Service]
Delegate=cpu cpuset io memory pids
EOF
sudo systemctl daemon-reload
4. DOCKER_HOST 環境変数の設定忘れ
Rootless Docker のソケットは /run/user/<UID>/docker.sock に配置されます。通常の /var/run/docker.sock ではないため、docker コマンドで接続できないことがあります。
# 症状: docker コマンドがエラーになる
docker ps
# Cannot connect to the Docker daemon at unix:///var/run/docker.sock
# 解決: DOCKER_HOST を設定する
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
docker ps # 正常に動作する
5. ネットワーク名前解決が遅い
slirp4netns 経由では DNS ルックアップが遅くなることがあります。pasta へ切り替えると改善するケースがあります。
# pasta をインストール
sudo apt install -y pasta
# daemon.json で pasta を指定
cat <<EOF > ~/.config/docker/daemon.json
{
"rootless-network-driver": "pasta"
}
EOF
systemctl --user restart docker
6. ボリュームマウント時の UID/GID ズレ
ホストのディレクトリをコンテナにマウントすると、User Namespace のマッピングにより「コンテナ内では書き込めない」問題が発生することがあります。
# 症状: マウントしたディレクトリに書き込めない
docker run -v $HOME/data:/app/data myimage
# permission denied: /app/data/output.txt
# 解決: コンテナ実行ユーザーを明示する
docker run -u $(id -u):$(id -g) -v $HOME/data:/app/data myimage
7. 公開ポートがローカルホスト限定になる
Rootless Docker では、-p 8080:80 のようにポートを公開してもデフォルトで 127.0.0.1 にしかバインドされず、他端末からアクセスできないことがあります。
# 他端末や VM からアクセスさせたい場合は 0.0.0.0 を明示する
docker run -p 0.0.0.0:8080:80 nginx
サーバー上で SSH ログアウト後もコンテナを動かし続けたい場合は loginctl enable-linger が必須です。
8. systemd linger 未設定でログアウト後にコンテナが止まる
sudo loginctl enable-linger $(whoami)
# 確認
loginctl show-user $(whoami) | grep Linger
# Linger=yes ← これが表示されれば OK
業務での使いどころ
CI/CD 環境
GitHub Actions self-hosted runner や Jenkins エージェントで root なし Docker が使えます。
# GitHub Actions での例
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Build image
env:
DOCKER_HOST: unix://${{ env.XDG_RUNTIME_DIR }}/docker.sock
run: docker build -t myapp .
マルチテナント開発サーバー
複数の開発者が同一ホストを共有する環境では、各ユーザーが独立した Docker 環境を持てるため、互いのコンテナが干渉しません。
# alice のコンテナは alice の権限内で動作
# bob のコンテナは bob の権限内で動作
# 互いのコンテナやイメージは見えない
セキュリティ要件が厳しい本番環境
コンテナランタイムへの攻撃が成功しても、ホスト root を奪取されない点が評価されています。ただし、本番投入前は十分な検証が必要です。
代替案との比較
| ツール | rootless 対応 | 特徴 |
|---|---|---|
| Rootless Docker | ◎ | Docker エコシステムとの互換性が高い |
| Podman rootless | ◎ | デーモンレスで systemd ソケットアクティベーション対応 |
| nerdctl + containerd | ◯ | OCI 準拠。rootless は nerdctl + bypass4netns で実現 |
| Lima (macOS) | ◎ | macOS 向け。内部で rootless containerd を使用 |
Podman と Docker の使い分けの観点:
- Podman が向く場合: デーモンプロセスを持ちたくない、systemd との統合を重視する、RHEL/Fedora 環境が多い
- Rootless Docker が向く場合: 既存の Docker Compose や Docker Hub ワークフローをそのまま使いたい、Docker エコシステムへの依存が大きい
まとめ
Rootless Docker は「セキュリティを高めたいが Docker エコシステムを手放したくない」という場面に有効な選択肢です。
- User Namespace + rootlesskit でユーザー権限内に Docker デーモンを閉じ込める
- cgroup v2 delegate でリソース制限も一般ユーザーから設定可能
- ポートや overlay2、DOCKER_HOST などのハマりどころは事前に把握しておく
- Podman rootless とは互換性・デーモン有無などで使い分ける
Ubuntu 22.04+ ならほぼ追加設定なしで動作するため、まず開発環境で試してみることをおすすめします。