本文へ移動
Vast Cowのブログ
前のページへ戻る

Rootless Dockerの`--network host`が、いつの間にか本当に機能するようになっていた

この記事を編集

はじめに

Rootless Dockerで--network hostを使ったことがある人なら、次のような挙動に遭遇したことがあるかもしれません。

docker run --rm --network host \
  curlimages/curl http://127.0.0.1:8080

ホスト側で8080番ポートのサービスが動いているにもかかわらず、コンテナから接続できない。

通常のDocker(rootfulモード)では接続できるのに、rootlessモードでは接続できないという挙動です。

これは従来のRootless Dockerの制約でした。

ところが調べてみると、Docker Engine 29.5.0から、この制約が解消されていました。

以前は--network hostを指定しても実ホストのネットワーク名前空間を共有できませんでしたが、現在は通常のDockerに近い形で動作するようになっています。

この記事では、従来の動作、変更された仕組み、バージョン境界、動作確認方法を整理します。

従来のRootless Dockerでは--network hostが期待どおりに動かなかった

Dockerの--network hostは、コンテナがホストのネットワーク名前空間を共有するためのオプションです。

通常のDockerでは、次のような挙動になります。

しかし、従来のRootless Dockerでは事情が異なりました。

Rootless Dockerは、root権限を使用せずにDockerデーモンやコンテナを動作させるため、RootlessKitを利用します。

従来の構造を簡略化すると次のようになります。

実ホストのNetwork Namespace
│
└── RootlessKitのNetwork Namespace
    │
    ├── dockerd
    │
    └── コンテナ(--network host)

この構造では、--network hostを指定しても、コンテナが共有するのはRootlessKit側のネットワーク名前空間です。

実ホストのネットワーク名前空間ではありません。

そのため、コンテナ内で127.0.0.1:8080に接続しても、実ホストの127.0.0.1:8080には接続できませんでした。

また、コンテナ内でポートを待ち受けても、そのポートが実ホストに直接公開されるわけではありません。

実ホストにサービスを公開したい場合は、通常、--network hostではなく-pによるポートフォワーディングを使う必要がありました。

docker run --rm -p 8080:80 nginx:alpine

つまり、Rootless Dockerでは--network hostという指定自体は受け付けられるものの、rootfulモードとは意味が異なっていたわけです。

Docker Engine 29.5.0で仕様が変更された

この挙動が変更されたのは、2026年5月14日にリリースされたDocker Engine 29.5.0です。

公式リリースノートのNetworkingセクションには、次の変更が記載されています。

Rootless: Properly support --net=host and localhost registries.

関連する実装は、MobyのPull Request #47103です。

変更前後を整理すると、次のようになります。

項目29.4.3以前29.5.0以降
--network hostの指定可能可能
共有されるネットワーク名前空間RootlessKit側実ホスト側
ホストの127.0.0.1へのアクセス原則不可可能
コンテナの待受ポート実ホストとは分離実ホストと共有
-pによるポート公開無効無効

ポイントは、--network hostが新たに追加されたわけではなく、既存のオプションが本来期待される動作をするように修正されたという点です。

何が変わったのか

実装上の重要な変更の一つが、RootlessKitの--detach-netnsを利用するようになったことです。

Docker Engine 29.5.0のdockerd-rootless.shには、次の設定があります。

: "${DOCKERD_ROOTLESS_ROOTLESSKIT_DETACH_NETNS:=true}"

DOCKERD_ROOTLESS_ROOTLESSKIT_DETACH_NETNSのデフォルトがtrueになっています。

この設定により、DockerデーモンをRootlessKitのネットワーク名前空間から分離し、実ホストのネットワーク名前空間で動作させられます。

変更後の構造を簡略化すると、次のようになります。

実ホストのNetwork Namespace
│
├── dockerd(rootless)
│
├── コンテナ(--network host)
│
└── ホスト上のサービス

一方で、通常のbridgeネットワークを利用するコンテナについては、引き続きrootlessのネットワーク機構が使用されます。

つまり、rootlessモードそのものが廃止されたわけでも、すべてのコンテナがホストネットワークを共有するようになったわけでもありません。

--network hostを明示的に指定した場合に、実ホストのネットワーク名前空間を利用できるようになった、という変更です。

従来の動作に戻すこともできる

Docker Engine 29.5.0以降でも、次の環境変数によって新しい動作を無効化できます。

DOCKERD_ROOTLESS_ROOTLESSKIT_DETACH_NETNS=false

そのため、29.5.0以降であっても、起動設定によっては従来の挙動になる可能性があります。

実際に動作を確認する

Linux上のRootless Dockerで、ホストのlocalhostに接続できるか確認してみます。

1. Dockerのバージョンを確認

docker version --format '{{.Server.Version}}'

Docker Engine 29.5.0以降であることを確認します。

続いてrootlessモードかどうかを確認します。

docker info --format '{{json .SecurityOptions}}'

出力にrootlessが含まれていれば、rootlessモードで動作しています。

2. ホスト側でHTTPサーバーを起動

python3 -m http.server 8080 --bind 127.0.0.1

ホストのループバックインターフェースでHTTPサーバーを起動します。

3. コンテナから接続する

別のターミナルから次のコマンドを実行します。

docker run --rm --network host \
  curlimages/curl http://127.0.0.1:8080

Docker Engine 29.5.0以降の標準設定であれば、ホスト側のHTTPサーバーに接続できるはずです。

従来のRootless Dockerでは、この接続は通常失敗していました。

4. ネットワーク名前空間を比較する

さらに、ホストとコンテナが同じネットワーク名前空間を利用しているか確認できます。

ホスト側:

readlink /proc/self/ns/net

コンテナ側:

docker run --rm --network host alpine \
  readlink /proc/self/ns/net

両者で同じネットワーク名前空間のinode番号が表示されれば、ネットワーク名前空間が共有されていることを確認できます。

セキュリティ上の注意点

--network hostがrootfulモードに近い動作になったからといって、コンテナがホストのroot権限を取得するわけではありません。

Rootless Dockerのユーザー名前空間による権限制限は引き続き存在します。

ただし、ネットワークの分離はなくなります。

例えば、次の点には注意が必要です。

特に、127.0.0.1で待ち受けているサービスを「ホスト上のプロセスからしかアクセスできない」という前提で運用している場合は、--network hostを指定したコンテナからもアクセスできるようになる点に注意が必要です。

まとめ

Docker Engine 29.5.0で、Rootless Dockerの--network hostの挙動が変更されました。

従来はRootlessKit内部のネットワーク名前空間を共有するだけだったため、実ホストのlocalhostに直接アクセスできませんでした。

しかし、29.5.0以降では、RootlessKitの--detach-netnsを利用することで、実ホストのネットワーク名前空間を共有できるようになっています。

個人的には、Rootless Dockerの--network hostは実ホストとは別物、という認識のままだったので、この変更は意外でした。

Rootless Dockerでホストのlocalhostへ接続するために回避策を使っている場合は、Docker Engineのバージョンを確認してみる価値がありそうです。

参考資料


この記事を編集
この記事を共有:

コメント


前の記事
Certbotで無料SSL証明書を取得する方法と、DNS-01に対応した無料DDNSサービスの比較
次の記事
Codex CLIで承認確認をなくし、プロジェクト内の書き込みとネットワークアクセスを許可する方法