Dockerのネットワークについて入門メモ

Platform Engineer

Dockerのネットワークについて気になったのでメモしておきます。

Docker ネットワークの基本概念

Namespace と仮想ブリッジ

Docker コンテナは Linux のカーネル機能である「Namespace」を活用し、プロセス空間やネットワーク空間を独立させています。ネットワークの空間が分離されることによって、各コンテナは独自のネットワークスタック(IP アドレス、ルーティングテーブルなど)を持ち、ほかのコンテナやホストからは「別のマシン」として振る舞います。

Docker がコンテナ用にデフォルトで作成する「docker0」と呼ばれる仮想ブリッジ(Linux ブリッジ)は、コンテナが外部のネットワークに出る際の中継地点となります。各コンテナには仮想イーサネットデバイス(veth インターフェース)が割り当てられ、この veth が docker0 ブリッジに接続されます。

コンテナ A (vethA) --+   
|-- docker0(仮想ブリッジ) -- ホストOS(eth0 など) -- 外部ネットワーク
コンテナ B (vethB) --+

NAT によるアドレス変換

Docker デーモンはデフォルトでホストの NIC(ネットワーク・インターフェース)と通信するとき、NAT (Network Address Translation) を利用します。各コンテナはプライベート IP アドレス(172.17.x.x など)を持ち、外部からはホストの IP と特定のポート番号を通じてアクセスします。

例として、ホストのポート 8080 をコンテナの 80 ポートに割り当てる場合は以下のように実行します。

docker run -d -p 8080:80 nginx

このとき外部ネットワークからは http://<ホストのIP>:8080/ にアクセスすると、コンテナの 80 番ポートのサービスに到達できるようになります。( KubernetesのNodePortと同じ)

Docker ネットワークの種類

Docker には複数のネットワークモードが用意されています。主なものを確認してみましょう。

bridge ネットワーク(デフォルト)

Docker のデフォルトネットワークモードです。コンテナはホストが作成した仮想ブリッジ(例: docker0)に接続されます。先ほどやった-p オプションでポートマッピングを設定することで、ホストからコンテナにアクセスできます。
コンテナ間通信では、同じブリッジに属するコンテナはプライベート IP (例: 172.17.0.2 など) で直接通信できます。

# 独自の bridge ネットワークを作成して使用する例
docker network create my-bridge

docker run -d --name web1 --network my-bridge nginx
docker run -d --name web2 --network my-bridge nginx

# コンテナ同士で ping やアプリケーション通信が可能
docker exec -it web1 bash -c "apt-get update && apt-get install -y iputils-ping"
docker exec -it web1 ping web2

試したら無事に通信できました。

host ネットワーク

ホストのネットワークスタックをコンテナが直接使うモードです。コンテナはホストと同じ IP アドレスを利用します。このモードの場合、ポートマッピング (-p) は無視され、コンテナ内で稼働するアプリケーションはホストが持つポートを直接使うことになります。

docker run -d --network host nginx

注意:

  • セキュリティ的にホストOSと分離が弱くなります。
  • Linux でのみ利用可能です(Windows/Mac では基本的に対応していません)。

none ネットワーク

ネットワークインターフェースが一切付与されないモードです。コンテナ内部でネットワークを使用しない特殊なケース(ネットワーク不要のバッチ処理など)に向いています。

overlay ネットワーク

複数の Docker ホスト間を仮想ネットワークでつなぐために使われるモードです。Docker Swarm などを使った分散環境で活躍します。本稿では詳細は割愛しますが、複数の物理ホスト(ノード)間でも各コンテナが同じネットワークセグメントのように通信できるのが特徴です。

コンテナ同士の通信方法

同じネットワーク下に属するコンテナ間

先ほどの例のように --network my-bridge などで同じネットワークを指定すると、コンテナ間はプライベート IP やホスト名を通して直接通信できます。コンテナのホスト名はコンテナ名がデフォルトで使われることが多いため、ping web2 のように通信できたりします。

別のネットワークに属するコンテナ間

コンテナが別々のネットワーク(bridge)に所属している場合は、デフォルトでは相互に通信できません。セキュリティを分けたい場合はこの構成が有効です。もし通信が必要になったら、ネットワークを統一するか、外部サービス経由で疎通させるなどの方法を取ります。

docker-compose でのコンテナ間通信

複数コンテナを連携させる場合は docker-compose.yml を使うケースが多いです。docker-compose では自動的に専用のネットワークを作り、同じ Compose プロジェクトのコンテナは同一ネットワーク内で通信が可能です。

version: '3'
services:
web:
image: nginx
ports:
- "8080:80"
db:
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=secret

上記の例では webdb は同じネットワークに属しているため db:3306 のようにコンテナ名を使って通信できます。

(おまけ)Windows ホスト上での Docker ネットワーク

Docker Desktop (WSL2 / Hyper-V)

Windows で Docker を利用する際は、通常「Docker Desktop for Windows」をインストールします。このとき、WSL2 バックエンドや Hyper-V を用いて Linux 環境が動作し、その中で Docker デーモンが動いています。今はWSL2が主流みたいです。Hyper-VバックエンドでのDockerも試してみたいですね。

  • WSL2 バックエンド
    WSL2 は軽量な仮想マシンのような形で Linux カーネルが動作しており、その内部で Docker コンテナが稼働します。ネットワーク的には、Windows ホストと WSL2 Linux が NAT で接続されているイメージです。
    Windows ホストからコンテナにアクセスする場合、ホストのポートをコンテナに割り当てる -p オプションが有効です。Docker Desktop が内部的にルーティングを設定し、localhost:<ポート> 経由でコンテナへアクセスできます。
  • Hyper-V バックエンド
    Hyper-V を用いて Linux VM を起動し、その中で Docker が動きます。この場合も基本的には NAT を介して通信されます。
    Windows ネットワークアダプターには「vEthernet (DockerNAT)」のような名前の仮想アダプターが作成され、そのアダプター経由でコンテナと通信可能になります。

ただWindowsのDocker Desktopで動いているコンテナはどのようにして外と通信できているのかを見るのは結構難しかったです。以下のポストがわかりやすかったので共有しておきます

WindowsでのDocker Networkを理解する - Qiita
Windows上でWSLとDockerを併用しながら、Stable DiffusionやLLMなど生成AIの環境や、将棋AIの環境を構築するにあたって、Dockerコンテナとのネットワークがようやく…

まとめ

  • Docker コンテナは Linux の Namespace 技術によってネットワークが分離されている。
  • デフォルトでは bridge(docker0)と NAT を組み合わせて外部に接続し、ホストの IP:ポートをコンテナに割り当てる。
  • コンテナ間は同じネットワークに属していればプライベート IP やコンテナ名で直接通信できる。
  • Windows ホスト上の Docker では、Docker Desktop が WSL2/Hyper-V の仮想環境を用意し、NAT によるポートフォワードでコンテナと通信している。

以上Dockerのネットワークについてのメモでした。

タイトルとURLをコピーしました