Dockerコマンドの--net=hostオプションは実際に何をするのか?

私はDockerの初心者です。docker runコマンドでこのオプションが何をするのか、明確な説明が見つからず、少し混乱しています。

このオプションを使って、ポートを指定せずにDockerコンテナ上で動作しているアプリケーションにアクセスできるのでしょうか?例えば、docker runコマンドで-p 8080:8080オプションを使用して、ポート8080でdockerイメージ経由でデプロイされたウェブアプリケーションを実行する場合、Dockerコンテナのip /theWebAppNameで8080ポートにアクセスしなければならないことは分かっています。しかし、--net=hostオプションがどのように機能するのか、うまく思いつきません。

ソリューション

Dockerのインストール後、デフォルトでは3つのネットワークがあります:

docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f3be8b1ef7ce        bridge              bridge              local
fbff927877c1        host                host                local
023bb5940080        none                null                local

私はこれをシンプルに保とうとしています。そのため、デフォルトでコンテナを起動すると、ブリッジ (docker0) ネットワーク内に作成されます。

$ docker run -d jenkins
1498e581cdba        jenkins             "/bin/tini -- /usr..."   3 minutes ago       Up 3 minutes        8080/tcp, 50000/tcp   friendly_bell

jenkinsのdockerfileでは、ポート808050000が公開されている。これらのポートは、ブリッジネットワーク上のコンテナ用に開放されている。そのため、ブリッジネットワーク内のすべてのものがポート 808050000 のコンテナにアクセスできる。ブリッジネットワーク内のすべてのものは、"Subnet": "172.17.0.0/16", のプライベート範囲内にある。もし外部からアクセスしたい場合は、ポートを -p 8080:8080 でマッピングする必要がある。これにより、コンテナのポートが実際のサーバー(ホスト・ネットワーク)のポートにマッピングされる。つまり、8080のサーバーにアクセスすると、ポート 8080のブリッジネットワークにルーティングされる。

これでホストネットワークもできた。コンテナのネットワークはコンテナ化されない。そのため、ホストネットワークでコンテナを起動すると、次のようになる(最初のもの):

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
1efd834949b2        jenkins             "/bin/tini -- /usr..."   6 minutes ago       Up 6 minutes                              eloquent_panini
1498e581cdba        jenkins             "/bin/tini -- /usr..."   10 minutes ago      Up 10 minutes       8080/tcp, 50000/tcp   friendly_bell

違いはポートだ。コンテナはホストネットワーク内にある。そのため、ホスト上でポート 8080 を開けば、すぐにコンテナにアクセスできる。

$ sudo iptables -I INPUT 5 -p tcp -m tcp --dport 8080 -j ACCEPT

ファイアウォールでポート 8080 を開き、ポート 8080 でサーバーにアクセスすると、jenkins にアクセスできる。このブログ]1も参考になると思います。

解説 (4)

net=host`オプションは、ネットワークの観点から、Dockerコンテナ内のプログラムをホスト自体で実行しているように見せるために使用する。 これにより、コンテナは通常よりも大きなネットワークアクセスができるようになる。

通常、ホストマシンからコンテナにポートを転送する必要があるが、コンテナがホストのネットワークを共有する場合、ネットワーク上のアクティビティはすべてホストマシン上で直接発生する。

これは、ポートを公開してコンテナ・ポートにマッピングする必要がなくなることを意味するが、同じホスト・ポートで2つのコンテナを動作させることはできないため、競合を避けるために、各コンテナがリッスンするポートを調整するためにDockerfileを編集する必要があることを意味する。 しかし、このオプションを使う本当の理由は、ポートレベルでコンテナに転送するのが難しいネットワークアクセスが必要なアプリを実行するためだ。

例えば、DHCPサーバーを実行したい場合、ネットワーク上のブロードキャスト・トラフィックをリッスンし、パケットからMACアドレスを抽出できる必要がある。 この情報はポート転送の過程で失われるため、Docker内でDHCPサーバーを実行するには、コンテナを--net=hostとして実行するしかない。

一般的に言えば、--net=hostが必要なのは、非常に特殊で異常なネットワークを必要とするプログラムを実行する場合だけである。

最後に、セキュリティの観点から、Dockerコンテナは単一のポートしかアドバタイズ(公開)しないにもかかわらず、多くのポートをリッスンすることができます。 しかし、--host=netを使うと、Dockerfileにリストされていないポートも含めて、コンテナがホスト上でリッスンしている全てのポートを取得することになります。 つまり、コンテナ(特にソフトウェアプロジェクトが提供する公式のものなど、あなたのものではない場合)を注意深くチェックし、不注意で余計なサービスをマシンに公開しないようにする必要があります。

解説 (0)
  1. --net="anyname"のように、独自の新しいネットワークを作成できます。
  2. これは、異なるコンテナからサービスを分離するために行う。
  3. 同じサービスが異なるコンテナで実行されているが、ポートマッピングは同じままだとする。 が同じままだとすると、最初のコンテナはうまく起動するが、2番目のコンテナの同じサービスは失敗する。 これを避けるには、ポートマッピングを変更するか、ネットワークを作成する。
解説 (0)