Run the Docker daemon as a non-root user (Rootless mode)
通常のDockerの運用では、Dockerデーモン(dockerd
)はシステム上のrootユーザーとして実行されます。これにより、Dockerコンテナはホストシステムのリソースに広範なアクセスを持つことになり、セキュリティ上の懸念が生じる可能性があります。
「Rootlessモード」とは、Dockerデーモンをrootユーザーではなく、通常の(非root)ユーザーとして実行するための機能です。これにより、Dockerコンテナがホストシステムに与える潜在的な影響を制限し、セキュリティを向上させることができます。
Rootlessモードの利点
-
セキュリティの向上:
- Dockerデーモンがroot権限で実行されないため、もしデーモンに脆弱性が見つかった場合でも、攻撃者がホストシステム全体を乗っ取るリスクが大幅に低減されます。
- コンテナ内部でrootユーザーとして実行されるプロセスも、実際にはホストシステムの特定の非rootユーザーの権限で動作します。
-
権限の分離:
- Dockerデーモンとコンテナの実行が、システム上の他のroot権限を必要とするプロセスから分離されます。
-
より安全なマルチテナント環境:
- 複数のユーザーが同じホストマシン上でDockerを利用する場合、各ユーザーが自身の権限内でDockerデーモンを実行できるため、互いの環境に影響を与えにくくなります。
-
設定の柔軟性:
- ユーザーごとに異なる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ユーザーにマッピングします。これには newuidmap
と newgidmap
というツールが必要です。これらがインストールされていないか、適切に設定されていない場合に発生します。
解決策:
/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
または同様のパッケージにnewuidmap
とnewgidmap
が含まれています。- Ubuntu/Debian:
sudo apt-get install -y uidmap
- CentOS/RHEL/Fedora:
sudo yum install -y uidmap
またはsudo dnf install -y uidmap
- Ubuntu/Debian:
特権ポート(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-nic
、pasta
など)を検討します。ただし、これらは追加のセットアップが必要な場合があります。 ping
の設定:ping
コマンドが動作しない場合、ホストシステムで特定のカーネルモジュール (ip_tables
など) がロードされているか確認する必要があります。
ボリュームマウント時のパーミッションエラー
エラー例:
ホストのディレクトリをコンテナにボリュームマウントした際に、コンテナ内のプロセスがファイルにアクセスできない(Permission denied
)。
原因: Rootlessモードでは、コンテナ内のユーザーIDとホスト上のユーザーIDが異なります。例えば、コンテナ内でrootとして動作するプロセスが、ホスト上の特定の非rootユーザーの権限でマウントされたボリュームにアクセスしようとすると、パーミッションの問題が発生します。
解決策:
chown
で権限を変更: 最終手段として、ホスト上でマウントするディレクトリの所有者をRootlessモードのユーザーに合わせるためにchown
を実行することも考えられますが、これは他のrootアプリケーションに影響を与える可能性があります。- コンテナ内のユーザー変更:
Dockerfile
でUSER
命令を使用し、コンテナ内のアプリケーションを非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
- Ubuntu/Debian:
- 環境変数の確認:
PATH
やDOCKER_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
- Ubuntu/Debian:
- カーネルのバージョン確認: ホストのLinuxカーネルが
overlay2
をRootlessモードでサポートするバージョンであるか確認します。
一般的なトラブルシューティングのヒント:
dockerd-rootless-setuptool.sh install
の再実行: セットアップツールを再度実行することで、不足している依存関係のインストールや設定の修正が行われる場合があります。- 公式ドキュメントの参照: Dockerの公式ドキュメントにあるRootlessモードのセクションは、常に最新の情報とトラブルシューティングのヒントが掲載されています。
- ログの確認:
~/.local/share/docker/rootless/dockerd.log
やjournalctl --user -u docker.service
のような場所にあるDockerデーモンのログを確認します。エラーの具体的な原因が記載されていることが多いです。
Dockerの「Rootlessモード」は、Dockerデーモンをroot権限なしで実行するための機能であり、プログラミングというよりは環境構築と運用のための設定に深く関わります。そのため、「プログラミングに関連する例コード」というよりは、Rootlessモードをセットアップし、それを利用するためのコマンドラインの例が中心になります。
以下に、Rootlessモードのセットアップから基本的な利用までの主要なステップを例コードとともに説明します。
前提条件の確認とインストール
Rootlessモードを使用する前に、newuidmap
と newgidmap
というツールがシステムにインストールされている必要があります。これらはユーザー名前空間(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
:newuidmap
とnewgidmap
を提供します。
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
dockerd
や rootlesskit
のプロセスが、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モードがデフォルトで非常に使いやすいです。