Run the Docker daemon as a non-root user (Rootless mode)

2025-05-31

通常のDockerの運用では、Dockerデーモン(dockerd)はシステム上のrootユーザーとして実行されます。これにより、Dockerコンテナはホストシステムのリソースに広範なアクセスを持つことになり、セキュリティ上の懸念が生じる可能性があります。

「Rootlessモード」とは、Dockerデーモンをrootユーザーではなく、通常の(非root)ユーザーとして実行するための機能です。これにより、Dockerコンテナがホストシステムに与える潜在的な影響を制限し、セキュリティを向上させることができます。

Rootlessモードの利点

  1. セキュリティの向上:

    • Dockerデーモンがroot権限で実行されないため、もしデーモンに脆弱性が見つかった場合でも、攻撃者がホストシステム全体を乗っ取るリスクが大幅に低減されます。
    • コンテナ内部でrootユーザーとして実行されるプロセスも、実際にはホストシステムの特定の非rootユーザーの権限で動作します。
  2. 権限の分離:

    • Dockerデーモンとコンテナの実行が、システム上の他のroot権限を必要とするプロセスから分離されます。
  3. より安全なマルチテナント環境:

    • 複数のユーザーが同じホストマシン上でDockerを利用する場合、各ユーザーが自身の権限内でDockerデーモンを実行できるため、互いの環境に影響を与えにくくなります。
  4. 設定の柔軟性:

    • ユーザーごとに異なるDocker環境を設定・管理しやすくなります。

Rootlessモードの仕組み

Rootlessモードでは、主に以下の技術が利用されます。

  • slirp4netns: コンテナのネットワークをユーザー空間で提供するために使用されます。
  • FUSE (Filesystem in Userspace): 一部のファイルシステム操作をユーザー空間で行うために使用されます。
  • ユーザー名前空間 (User Namespaces): Linuxカーネルの機能で、プロセスが独自のユーザーIDとグループIDのセットを持つことを可能にします。これにより、コンテナ内のrootユーザーは、ホストシステムの実際のrootユーザーとは異なるID空間で動作します。

Rootlessモードの制限事項

Rootlessモードは多くの利点を提供しますが、いくつかの制限事項もあります。

  • セットアップの複雑さ: 通常のDockerのセットアップよりも、初期設定がやや複雑になる場合があります。
  • パフォーマンスへの影響: わずかながらパフォーマンスのオーバーヘッドが発生する可能性があります。
  • 一部の機能が利用できない、または動作が異なる:
    • cgroup v1の特定の機能(例:リソース制限の正確性)や、一部のストレージドライバ(例:overlay2)が利用できない場合があります。
    • 一部のネットワーク機能(例:特定のポートへのバインド)に制限がある場合があります。
    • docker buildのキャッシュが通常とは異なる動作をする場合があります。


newuidmap / newgidmap が見つからない、または権限がない

エラー例:

error: newuidmap and newgidmap must be installed

または、dockerd-rootless.sh 実行時に mount: permission denied のようなエラーが表示される。

原因: Rootlessモードは、ユーザー名前空間(User Namespaces)を利用して、コンテナ内のrootユーザーをホストシステムの非rootユーザーにマッピングします。これには newuidmapnewgidmap というツールが必要です。これらがインストールされていないか、適切に設定されていない場合に発生します。

解決策:

  • /etc/subuid/etc/subgid の設定: Docker Rootlessモードをセットアップしたユーザーに対して、十分なサボートUID/GID(Subordinate UIDs/GIDs)の範囲が /etc/subuid/etc/subgid ファイルに割り当てられていることを確認してください。通常、Rootlessモードのインストールスクリプトが自動的に行いますが、手動で設定する必要がある場合もあります。 例: echo "your_user_name:100000:65536" | sudo tee -a /etc/subuid (同様に /etc/subgid も設定)
  • uidmap パッケージのインストール: ほとんどのLinuxディストリビューションでは、uidmap または同様のパッケージに newuidmapnewgidmap が含まれています。
    • Ubuntu/Debian: sudo apt-get install -y uidmap
    • CentOS/RHEL/Fedora: sudo yum install -y uidmap または sudo dnf install -y uidmap

特権ポート(1024番未満のポート)へのバインドができない

エラー例: docker run -p 80:80 ... のように特権ポートを公開しようとすると、エラーが発生する。

原因: Rootlessモードでは、非rootユーザーとしてDockerデーモンが動作するため、デフォルトでは1024番未満の特権ポートにバインドする権限がありません。

解決策:

  • sysctl net.ipv4.ip_unprivileged_port_start の設定: システム全体の設定で、非特権ユーザーがバインドできるポートの開始番号を変更することもできますが、これはシステム全体のセキュリティに影響を与える可能性があるため注意が必要です。
  • iptables の設定: ユーザー名前空間内の iptables を使用して、特定の特権ポートへのアクセスをリダイレクトすることができます。 例: sudo iptables -t nat -A PREROUTING -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-port 8080 (ホストの80番ポートへのトラフィックを8080番にリダイレクト)
  • 高位ポートの使用: 可能な限り、8080番や8000番など、1024番以上のポートを使用するようにアプリケーションや設定を変更します。

Cgroups v1 の制限、またはリソース制限が期待通りに動作しない

エラー例: docker stats で表示されるリソース使用量が正しくない、またはコンテナのリソース制限が適用されない。

原因: RootlessモードでのCgroupsのサポートは、ホストシステムのCgroupsバージョンに依存します。Cgroups v1環境では、一部の機能(特に正確なリソース制限や docker top の動作)が制限される場合があります。Cgroups v2の方がより完全なサポートを提供します。

解決策:

  • リソース制限の確認: Rootlessモードのドキュメントで、Cgroups v2 環境でのリソース制限の設定方法を確認します。docker run --pids-limit などの一部のオプションは、Cgroups v1ではサポートされない場合があります。
  • Cgroups v2 の使用: 可能であれば、Cgroups v2 が有効になっているシステムでDocker Rootlessモードを使用します。多くの新しいLinuxディストリビューションでは、Cgroups v2がデフォルトで有効になっています。

ネットワーク関連のエラー(Pingができない、ネットワークパフォーマンスが遅い)

エラー例: コンテナ内からpingコマンドが動作しない、またはネットワークスループットが非常に遅いと感じる。

原因: Rootlessモードでは、デフォルトで slirp4netns というユーザー空間のネットワークスタックを使用します。これはroot権限なしで動作しますが、従来のブリッジネットワークに比べてパフォーマンスが劣る場合や、特定のプロトコル(ICMPなど)が制限される場合があります。

解決策:

  • パフォーマンスの考慮: 高いネットワークパフォーマンスが要求される本番環境では、Rootlessモードが適さない場合があります。
  • ネットワークドライバーの変更: slirp4netns 以外のRootlessモードでサポートされているネットワークドライバー(vpnkit や実験的な lxc-user-nicpasta など)を検討します。ただし、これらは追加のセットアップが必要な場合があります。
  • ping の設定: ping コマンドが動作しない場合、ホストシステムで特定のカーネルモジュール (ip_tables など) がロードされているか確認する必要があります。

ボリュームマウント時のパーミッションエラー

エラー例: ホストのディレクトリをコンテナにボリュームマウントした際に、コンテナ内のプロセスがファイルにアクセスできない(Permission denied)。

原因: Rootlessモードでは、コンテナ内のユーザーIDとホスト上のユーザーIDが異なります。例えば、コンテナ内でrootとして動作するプロセスが、ホスト上の特定の非rootユーザーの権限でマウントされたボリュームにアクセスしようとすると、パーミッションの問題が発生します。

解決策:

  • chown で権限を変更: 最終手段として、ホスト上でマウントするディレクトリの所有者をRootlessモードのユーザーに合わせるために chown を実行することも考えられますが、これは他のrootアプリケーションに影響を与える可能性があります。
  • コンテナ内のユーザー変更: DockerfileUSER 命令を使用し、コンテナ内のアプリケーションを非rootユーザーで実行するように変更します。そして、そのユーザーのUIDがホスト上のマウントポイントの所有者と一致するように調整します。
  • UID/GIDのマッピングの調整: コンテナ内で使用されるUID/GIDと、ホスト上のファイルの所有者のUID/GIDが一致するように、/etc/subuid および /etc/subgid のマッピング範囲を調整するか、コンテナ内でユーザーを作成してそのUID/GIDを使用するようにします。

Dockerデーモンが起動しない / システムサービスとして起動しない

エラー例: dockerd-rootless.sh を実行してもデーモンが起動しない、または systemctl --user start docker が失敗する。

原因: 環境変数の設定ミス、依存パッケージの不足、または systemd --user セッションの問題。

解決策:

  • ユーザーセッションの確認: ログインシェルがD-Busユーザーセッションを正しく開始しているか確認します。loginctl enable-linger <your_user_name> を実行すると、ユーザーがログアウトした後もユーザーサービスが実行され続けるようになります。
  • dbus-user-session のインストール: systemctl --user コマンドを使用するために、dbus-user-session パッケージがインストールされているか確認します。
    • Ubuntu/Debian: sudo apt-get install -y dbus-user-session
  • 環境変数の確認: PATHDOCKER_HOST などの必要な環境変数が正しく設定されているか確認します。Rootlessモードのインストールスクリプト(dockerd-rootless-setuptool.sh)を実行することで、これらの設定が自動的に行われます。

overlay2 ストレージドライバが動作しない

エラー例: コンテナを起動しようとすると、overlay2 ドライバに関するエラーが表示される。

原因: Rootlessモードのoverlay2ストレージドライバは、特定のカーネルバージョン(例: 5.11以降)を必要とする場合があります。また、fuse-overlayfs がインストールされていない場合にも問題が発生することがあります。

解決策:

  • 別のストレージドライバの使用: vfs などの別のサポートされているストレージドライバに切り替えることを検討します。ただし、vfs はパフォーマンスが劣る可能性があります。
  • fuse-overlayfs のインストール: fuse-overlayfs パッケージをインストールします。多くのディストリビューションで利用可能です。
    • Ubuntu/Debian: sudo apt-get install -y fuse-overlayfs
  • カーネルのバージョン確認: ホストのLinuxカーネルがoverlay2をRootlessモードでサポートするバージョンであるか確認します。

一般的なトラブルシューティングのヒント:

  • dockerd-rootless-setuptool.sh install の再実行: セットアップツールを再度実行することで、不足している依存関係のインストールや設定の修正が行われる場合があります。
  • 公式ドキュメントの参照: Dockerの公式ドキュメントにあるRootlessモードのセクションは、常に最新の情報とトラブルシューティングのヒントが掲載されています。
  • ログの確認: ~/.local/share/docker/rootless/dockerd.logjournalctl --user -u docker.service のような場所にあるDockerデーモンのログを確認します。エラーの具体的な原因が記載されていることが多いです。


Dockerの「Rootlessモード」は、Dockerデーモンをroot権限なしで実行するための機能であり、プログラミングというよりは環境構築と運用のための設定に深く関わります。そのため、「プログラミングに関連する例コード」というよりは、Rootlessモードをセットアップし、それを利用するためのコマンドラインの例が中心になります。

以下に、Rootlessモードのセットアップから基本的な利用までの主要なステップを例コードとともに説明します。

前提条件の確認とインストール

Rootlessモードを使用する前に、newuidmapnewgidmap というツールがシステムにインストールされている必要があります。これらはユーザー名前空間(User Namespaces)を正しく機能させるために不可欠です。

インストール例 (Ubuntu/Debian):

sudo apt-get update
sudo apt-get install -y uidmap dbus-user-session fuse-overlayfs slirp4netns
  • slirp4netns: Rootlessモードのデフォルトのネットワークバックエンドです。
  • fuse-overlayfs: Rootlessモードで推奨されるストレージドライバである overlay2 を非rootで利用するために必要です。
  • dbus-user-session: systemd --user サービスを管理するために必要です。
  • uidmap: newuidmapnewgidmap を提供します。

Rootlessモードのセットアップ

Docker 20.10以降のバージョンでは、専用のセットアップツールが提供されており、これを使うのが最も簡単です。

セットアップツールの実行: Dockerがインストールされている非rootユーザーで以下のコマンドを実行します。

dockerd-rootless-setuptool.sh install

このコマンドは、以下のことを行います。

  • 必要に応じて /etc/subuid/etc/subgid にエントリを追加するよう促します(これは手動またはスクリプトが自動的に行うことがあります)。
  • ~/.profile~/.bashrc などに設定すべき環境変数を表示します。
  • ~/.config/systemd/user/docker.service にsystemdユーザーユニットを作成します。

出力される環境変数の例: dockerd-rootless-setuptool.sh install の実行後、以下のようなメッセージが表示され、環境変数の設定を促されます。

[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger <your_user_name>`
[INFO] Make sure the following environment variables are set (or add them to ~/.bashrc):
       export PATH=/usr/bin:$PATH
       export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock

環境変数の設定: 指示に従って、これらの環境変数をユーザーのシェル設定ファイル(例: ~/.bashrc, ~/.profile)に追加し、シェルを再起動またはsourceコマンドで読み込み直します。

# ~/.bashrc または ~/.profile に追加
export PATH="/usr/bin:$PATH"
export DOCKER_HOST="unix:///run/user/$(id -u)/docker.sock"

# 設定を反映
source ~/.bashrc # または source ~/.profile

デーモンの起動: systemd --user を使ってDockerデーモンを起動します。

systemctl --user start docker.service

システム起動時の自動起動設定(オプション): ユーザーがログインしていない状態でもDockerデーモンを起動し続けるには、以下のコマンドを実行します。

sudo loginctl enable-linger $(whoami)
systemctl --user enable docker.service

RootlessモードでのDockerコマンドの実行

環境変数が正しく設定されていれば、通常のDockerコマンドをroot権限なしで実行できます。

Dockerバージョンの確認:

docker version

出力の "Server" セクションに "Rootless: true" のような表示があれば、Rootlessモードで動作しています。

Hello Worldコンテナの実行:

docker run hello-world

通常通り "Hello from Docker!" のメッセージが表示されれば成功です。

Nginxコンテナの実行(非特権ポート): Rootlessモードでは、デフォルトで1024番未満のポートにはバインドできません。Webサーバーなどを実行する場合は、1024番以上のポートを使用します。

docker run -d -p 8080:80 --name my-nginx nginx:latest
  • ホストの8080番ポートがコンテナの80番ポートにマッピングされます。

コンテナ内のユーザーの確認: Rootlessモードで実行されたコンテナ内のrootユーザーは、ホスト上では非rootユーザーにマッピングされています。

docker run --rm ubuntu whoami

通常、root と表示されますが、これはコンテナ内のユーザー名前空間におけるrootです。

ホスト上でのプロセスの確認(別のターミナルで実行):

ps aux | grep dockerd
ps aux | grep rootlesskit

dockerdrootlesskit のプロセスが、rootユーザーではなく、Docker Rootlessモードをセットアップしたユーザーとして実行されていることが確認できるはずです。

daemon.json の設定(Rootlessモードの場合)

RootlessモードのDockerデーモンは、通常の/etc/docker/daemon.jsonではなく、ユーザーのホームディレクトリ以下の設定ファイルを読み込みます。

設定ファイルの場所: ~/.config/docker/daemon.json

例: ロギングドライバーの変更: ~/.config/docker/daemon.json を編集または新規作成します。

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

変更を適用するには、Dockerデーモンを再起動します。

systemctl --user restart docker.service

Docker Compose の利用

RootlessモードでDocker Composeを使用する場合も、特別な設定は不要です。環境変数が正しく設定されていれば、通常のDocker Composeコマンドがそのまま動作します。

例: docker-compose.yml:

version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80" # Rootlessモードでは非特権ポートを使用
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro

Docker Composeの実行:

docker compose up -d

Dockerfileでの非rootユーザーの利用

Rootlessモードはデーモン側のセキュリティを強化しますが、コンテナ内部でも特権を減らすことがベストプラクティスです。Dockerfile内で明示的に非rootユーザーを作成し、アプリケーションをそのユーザーで実行します。

Dockerfileの例:

# ベースイメージ
FROM ubuntu:latest

# アプリケーションユーザーの作成
RUN groupadd -r appuser && useradd -r -g appuser -s /sbin/nologin -M appuser

# 作業ディレクトリの設定
WORKDIR /app

# ファイルをコピーして、appuserが所有するようにする
COPY --chown=appuser:appuser . /app

# ポートの公開(アプリケーションがこのポートでListenする場合)
EXPOSE 8080

# アプリケーションを非rootユーザーで実行
USER appuser

# アプリケーションの実行コマンド
CMD ["python", "app.py"]

イメージのビルド:

docker build -t my-app-rootless .

コンテナの実行:

docker run -d -p 8080:8080 my-app-rootless


DockerのRootlessモードはDockerエコシステムの一部ですが、コンテナを非rootで実行するという目的においては、他のツールやアプローチも存在します。

Podman (ポッドマン)

特徴:

  • Systemdとの統合: デーモンレスであるため、PodmanはSystemdのユーザーサービスと非常に相性が良く、ユーザーがログインしていなくてもコンテナを自動起動・管理できます。
  • Kubernetes Podの概念: PodmanはKubernetesのPodの概念をネイティブにサポートしており、複数のコンテナを共有ネットワークやストレージを持つPodとして実行できます。podman play kube コマンドでKubernetesのマニフェストを直接実行できる点も特徴です。
  • Docker CLI互換: 多くのDockerコマンド(podman run, podman build, podman images など)がDocker CLIと互換性があるため、Dockerユーザーは比較的容易に移行できます。
  • Rootless by default: PodmanはデフォルトでRootlessモードで動作するように設計されており、特別な設定なしに非rootユーザーとしてコンテナを実行できます。
  • Daemonless (デーモンレス): Podmanの最も大きな特徴は、Dockerのように常駐するデーモンプロセス(dockerd)を必要としないことです。これにより、単一障害点がなくなり、セキュリティとシンプルさが向上します。各Podmanコマンドは、実行するユーザーの権限で直接コンテナを起動します。

プログラミング/運用例 (Dockerとの比較): Docker Rootlessモードでの環境変数設定が不要で、デフォルトで非root実行が可能です。

# Podmanのインストール (Ubuntu/Debianの例)
sudo apt update
sudo apt install podman

# Podmanでコンテナを実行(非rootユーザーで実行される)
podman run -d -p 8080:80 --name my-nginx-podman nginx:latest

# Podmanでイメージをビルド
podman build -t my-app-podman .

# Docker Composeの代替 (podman-compose または quadlet)
# podman-composeをインストール後、docker-compose.ymlをそのまま利用可能
# quadletはsystemdサービスファイルを自動生成するRed Hatのツール

Pros: 真にrootlessな設計、シンプルさ、Kubernetesとの親和性、Systemdとの優れた統合。 Cons: Docker Swarmのようなオーケストレーション機能は持たない(Kubernetesを使用することを前提とする)。一部のDocker Compose機能で追加の設定が必要な場合がある。

containerd + nerdctl

特徴:

  • nerdctl: containerdを操作するためのDocker互換CLIツールです。Dockerのコマンドラインインターフェースに慣れているユーザーにとって、containerdをより使いやすくします。nerdctlもRootlessモードをサポートしています。
  • containerd: CNCF(Cloud Native Computing Foundation)が管理する、軽量で高性能なコンテナランタイムです。Dockerデーモンは内部的にcontainerdを使用しています。より低レベルのコンテナ管理を提供します。

プログラミング/運用例: nerdctlを使ってcontainerdをRootlessモードで実行することができます。

# nerdctlのインストール (環境によって異なるが、多くはリリースアーカイブから手動インストール)
# 例: https://github.com/containerd/nerdctl/releases からバイナリをダウンロードしPATHに追加

# Rootless containerdデーモンの起動
# 通常は`containerd-rootless.sh`のようなヘルパースクリプトを使うか、
# systemd --user で管理する。
# 例: systemctl --user start containerd.service

# nerdctlでコンテナを実行
nerdctl run -d -p 8080:80 --name my-nginx-nerdctl nginx:latest

# イメージのビルド (BuildKitが必要)
nerdctl build -t my-app-nerdctl .

Pros: Dockerの内部ランタイムを直接利用するため、より軽量で低レベルな制御が可能。Docker CLI互換。 Cons: Docker Daemonを介さないため、設定や管理がDockerに比べてやや複雑になることがある。

Singularity (旧 Sylabs Singularity、現 Apptainer)

特徴:

  • BYO (Bring Your Own) 環境: ユーザーが独自の環境(ライブラリ、ツールなど)をコンテナに持ち込み、ホストシステムに依存せずに実行できるようにします。
  • 既存のDockerイメージの利用: Docker HubなどからDockerイメージを直接プルして実行できます。
  • セキュリティと再現性: デフォルトで非特権ユーザーとしてコンテナを実行し、ホストシステムへの特権昇格のリスクを最小限に抑えます。イメージは単一のファイル(.sif形式)としてパッケージ化され、配布や再現性が容易です。
  • HPC (高性能計算) 環境に特化: 主に科学研究、HPC、AI/MLなどの分野で利用されることを想定して設計されています。

プログラミング/運用例: Singularityは主に singularity コマンドを使用します。

# Dockerイメージをプルして実行
singularity pull docker://ubuntu:latest
singularity run ubuntu_latest.sif bash

# DockerイメージをSingularityイメージ(.sifファイル)に変換
singularity build my-app.sif docker://my-app-image:latest

# 特定のディレクトリをバインドして実行
singularity run --bind /data:/mnt my-app.sif /mnt/script.sh

Pros: HPC環境での高いセキュリティと再現性、既存のDockerイメージの利用が可能。 Cons: 一般的なWebアプリケーション開発やCI/CDパイプラインにはPodmanやDockerほど適していない。Dockerの全機能と互換性があるわけではない(特にDockerfileのUSER rootコマンドなど)。

Buildah (ビルダー)

特徴:

  • Dockerfile不要: Dockerfileを使用せずに、コマンドラインで直接イメージレイヤーを追加していくことも可能です。
  • Rootless Image Building: Rootlessモードでイメージをビルドできるため、root権限なしでセキュアなイメージ構築が可能です。
  • Daemonless: イメージビルドにデーモンを必要としません。
  • イメージビルドに特化: Buildahは、OCI(Open Container Initiative)互換のコンテナイメージを構築することに特化したツールです。Dockerのdocker buildコマンドに相当する機能を提供します。

プログラミング/運用例: Buildahはイメージビルドに重点を置いており、実行にはPodmanなどと組み合わせることが多いです。

# Buildahのインストール (Ubuntu/Debianの例)
sudo apt update
sudo apt install buildah

# ベースイメージの取得(作業コンテナの作成)
buildah from ubuntu:latest
# -> 新しい作業コンテナのコンテナIDが表示される

# ファイルを追加
buildah copy <container_id> ./app /app

# コマンドを実行
buildah run <container_id> apt-get update && apt-get install -y python3

# 新しいイメージとしてコミット
buildah commit <container_id> my-custom-image:latest

# イメージをDocker Hubにプッシュ
buildah push my-custom-image:latest docker.io/myuser/my-custom-image:latest

Pros: イメージビルドに特化し、高い柔軟性を提供。Rootlessでの安全なビルドが可能。 Cons: コンテナの実行機能は持たないため、Podmanなどと組み合わせて使う必要がある。

「Dockerデーモンを非rootユーザーで実行する」という目的において、Docker自身のRootlessモードは非常に強力な選択肢ですが、システム設計や利用目的によっては、Podman、containerd + nerdctl、Singularity、Buildahといった代替ツールも検討する価値があります。

  • 安全なイメージビルドに特化したいなら: Buildah が強力なツールとなります。
  • より低レベルなコンテナランタイムを直接操作したい、またはKubernetesのエコシステムに深く関わるなら: containerd + nerdctl が候補になります。
  • HPCや科学技術計算でセキュリティと再現性を重視するなら: Singularity が適しています。
  • 一般的な開発・運用でRootlessを重視するなら: Podman が最も直接的なDockerの代替となり、Rootlessモードがデフォルトで非常に使いやすいです。