はじめに
このラボでは、Linux 環境におけるネットワーク層接続の基本原則を探求します。Docker コンテナを使用して 2 つの独立したノードをシミュレートし、ip コマンドで静的 IP アドレスを手動で割り当てる方法を学びます。その後、ping ユーティリティを使用して、共有仮想ネットワーク上のこれらのノード間の直接通信パスをテストします。
まず同じサブネット上でノードを設定し、接続が成功することを確認します。次に、一方のノードを異なるサブネットに再設定し、予測可能な通信障害である「Destination Host Unreachable」エラーを体験します。この実践的な演習は、IP サブネットが直接通信をどのように制御するか、そして異なる論理ネットワーク上のデバイスがルーターなしで接続できない理由を明確かつ実践的に実証します。
2 ノードの実験環境を準備する
このステップでは、実験の基盤となる環境をセットアップします。完全な仮想マシンを使用する代わりに、軽量で隔離された Docker コンテナを活用して、2 つの独立したネットワークノードをシミュレートします。これらのノード間の通信を可能にするために、まずカスタム Docker ネットワークを作成します。この仮想ネットワークは物理的なネットワークスイッチのように機能し、両方のノードを同じ共有通信セグメントに配置します。
ノード用に Ubuntu 22.04 の Docker イメージをプルしましょう。
docker pull ubuntu:22.04
まず、2 つのノードが使用する仮想ネットワークを作成します。このネットワークを lab_net と名付け、特定の IP アドレス範囲を割り当てます。これは後続のステップで重要になります。
ターミナルで次のコマンドを実行してください。
docker network create --subnet=192.168.56.0/24 lab_net
このコマンドは、lab_net という名前の新しいブリッジネットワークを作成し、192.168.56.0/24 サブネットを使用するように構成するように Docker に指示します。出力としてネットワークの長いユニーク ID が表示され、その作成が確認されます。
e8c1c2a3b4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1
次に、最初のノードである node1 という名前のコンテナを起動し、lab_net ネットワークに接続します。
docker run -d --name node1 --network lab_net --cap-add=NET_ADMIN ubuntu:22.04 sleep infinity
このコマンドの内訳を見てみましょう。
docker run: 新しいコンテナを作成および開始するための標準コマンドです。-d: コンテナを「デタッチ」モードで実行します。つまり、バックグラウンドで実行されます。--name node1: コンテナにシンプルで覚えやすい名前を付けます。--network lab_net: コンテナを、先に作成した仮想ネットワークに接続します。--cap-add=NET_ADMIN: コンテナにNET_ADMINケーパビリティを付与します。これは、IP アドレスの追加などのネットワーク設定を変更するために必要です。ubuntu:22.04: 使用している Docker イメージで、標準的な Ubuntu 環境を提供します。sleep infinity: コンテナをアクティブに保つために無限に実行されるシンプルなコマンドです。
次に、同様のコマンドを使用して 2 番目のノード node2 を起動します。
docker run -d --name node2 --network lab_net --cap-add=NET_ADMIN ubuntu:22.04 sleep infinity
最後に、両方のノードが正しく実行されていることを確認しましょう。docker ps コマンドは、現在実行中のすべてのコンテナを一覧表示します。
docker ps
以下のような出力が表示され、node1 と node2 が両方とも起動していることが確認されるはずです。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 ubuntu:22.04 "sleep infinity" 5 seconds ago Up 4 seconds node2
g7h8i9j0k1l2 ubuntu:22.04 "sleep infinity" 15 seconds ago Up 14 seconds node1
両方のノードが同じ仮想ネットワーク上で実行されているため、実験環境の準備が整いました。次のステップでは、IP アドレスを設定し、それらの接続性をテストします。
ip addr を使用して最初のノードに静的 IP を設定する
このステップでは、最初のコンテナ node1 に静的 IP アドレスを割り当てます。静的 IP は手動で設定され、変更されないアドレスです。一方、動的 IP は DHCP サーバーによって自動的に割り当てられることがよくあります。私たちのシミュレーションでは、静的 IP を使用することで、ネットワーク構成を正確に制御できます。
すべての操作は、ホストマシンのメインターミナルから行います。docker exec コマンドを使用して、node1 コンテナの 内部 でコマンドを実行します。
まず、ベースの ubuntu:22.04 イメージは非常に最小限です。必要なネットワークツールをインストールする必要があります。node1 コンテナ内でパッケージリストを更新することから始めましょう。
docker exec node1 apt-get update
コンテナが最新のパッケージ情報を取得するにつれて、出力が表示されます。
次に、iproute2 パッケージ(ip コマンドを提供します)と iputils-ping パッケージ(後で使用する ping コマンドを提供します)をインストールします。
docker exec node1 apt-get install -y iproute2 iputils-ping
ツールがインストールされたので、node1 の現在のネットワーク構成を確認しましょう。標準的な Docker コンテナ内のネットワークインターフェースは、通常 eth0 という名前です。
docker exec node1 ip addr show eth0
出力には eth0 インターフェースの詳細が表示されます。Docker の内部 DHCP サーバーによって既に IP アドレスが割り当てられている場合があります(例:192.168.56.2)。ここに独自の静的 IP を追加します。
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:38:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.56.2/24 brd 192.168.56.255 scope global eth0
valid_lft forever preferred_lft forever
ここで、node1 に静的 IP アドレス 192.168.56.10 を割り当てます。/24 はネットマスク 255.255.255.0 の CIDR 表記で、ネットワークのサイズを定義します。
docker exec node1 ip addr add 192.168.56.10/24 dev eth0
このコマンドは、成功した場合、何も出力しないはずです。変更を確認するために、再度 ip addr show eth0 コマンドを実行してください。
docker exec node1 ip addr show eth0
元の IP アドレスに加えて、secondary としてマークされた新しい静的 IP アドレスが表示されるはずです。これにより、node1 がアドレス 192.168.56.10 で構成されたことが確認されます。
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:38:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.56.2/24 brd 192.168.56.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.56.10/24 scope global secondary eth0
valid_lft forever preferred_lft forever
同じサブネット内の 2 番目のノードに静的 IP を設定する
このステップでは、2 番目のノード node2 に静的 IP アドレスを設定します。2 つのデバイスがルーターなしで直接通信するには、同じ論理サブネットに存在する必要があります。node2 には、node1 に使用したのと同じ 192.168.56.0/24 サブネットから IP アドレスを割り当てます。この設定は、両方が同じローカルネットワークの一部である、クロスオーバーケーブルで接続された 2 台の PC を論理的に模倣します。
まず、node1 の場合と同様に、node2 コンテナ内に必要なネットワークツールをインストールする必要があります。パッケージリストの更新から始めましょう。
docker exec node2 apt-get update
次に、node2 に iproute2 および iputils-ping パッケージをインストールします。
docker exec node2 apt-get install -y iproute2 iputils-ping
ツールがインストールされたので、node2 に静的 IP アドレスを割り当てることができます。192.168.56.11 を使用します。これは node1 (192.168.56.10) と同じサブネットにありますが、ユニークなアドレスです。
docker exec node2 ip addr add 192.168.56.11/24 dev eth0
このコマンドは、node2 コンテナの eth0 ネットワークインターフェースに、/24 のネットマスクを持つ IP アドレス 192.168.56.11 を追加します。コマンドが成功した場合、何も出力されません。
IP アドレスが正しく割り当てられたことを確認するために、node2 のネットワーク構成を確認しましょう。
docker exec node2 ip addr show eth0
出力には、新しく追加された静的 IP アドレスが secondary としてマークされて表示されるはずです。これにより、node2 が正しく構成され、接続性をテストする次のステップの準備ができたことが確認されます。
11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:38:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.56.3/24 brd 192.168.56.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.56.11/24 scope global secondary eth0
valid_lft forever preferred_lft forever
ping を使用してノード間の直接接続を確認する
このステップでは、node1 と node2 間のネットワーク接続をテストします。両方のノードが同じサブネットに IP アドレスを持つようになったので、直接通信できるはずです。ping コマンドを使用します。これは基本的なネットワークユーティリティで、ターゲットホストに小さなデータパケット(ICMP Echo Request)を送信し、応答を待ちます。成功した応答は、2 つのデバイス間にネットワークパスが存在することを確認します。
この成功したテストは、2 台の PC をクロスオーバーケーブルで接続した場合に似ており、両方のデバイスが同じローカルネットワーク上にあり、直接互いを認識できます。
まず、node1 から node2 を ping してみましょう。node1 コンテナ内で ping コマンドを実行し、node2 の IP アドレス 192.168.56.11 をターゲットにします。
docker exec node1 ping -c 4 192.168.56.11
このコマンドの内訳を見てみましょう。
docker exec node1:node1コンテナ内で後続のコマンドを実行します。ping: 接続性をテストするユーティリティです。-c 4:pingに正確に 4 つのパケットを送信してから停止するように指示するフラグです。これがないと、pingは無期限に実行されます。192.168.56.11:node2の宛先 IP アドレスです。
成功した出力が表示され、node2 からの応答が受信されるはずです。
PING 192.168.56.11 (192.168.56.11) 56(84) bytes of data.
64 bytes from 192.168.56.11: icmp_seq=1 ttl=64 time=0.123 ms
64 bytes from 192.168.56.11: icmp_seq=2 ttl=64 time=0.087 ms
64 bytes from 192.168.56.11: icmp_seq=3 ttl=64 time=0.091 ms
64 bytes from 192.168.56.11: icmp_seq=4 ttl=64 time=0.085 ms
--- 192.168.56.11 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3074ms
rtt min/avg/max/mdev = 0.085/0.096/0.123/0.015 ms
"4 packets transmitted, 4 received, 0% packet loss" という行は、接続が機能していることを確認します。次に、node2 から node1 を ping して、逆方向の接続を確認しましょう。
docker exec node2 ping -c 4 192.168.56.10
ここでも、成功した一連の応答が表示され、通信が双方向であることを確認する必要があります。
PING 192.168.56.10 (192.168.56.10) 56(84) bytes of data.
64 bytes from 192.168.56.10: icmp_seq=1 ttl=64 time=0.099 ms
64 bytes from 192.168.56.10: icmp_seq=2 ttl=64 time=0.088 ms
64 bytes from 192.168.56.10: icmp_seq=3 ttl=64 time=0.092 ms
64 bytes from 192.168.56.10: icmp_seq=4 ttl=64 time=0.089 ms
--- 192.168.56.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3081ms
rtt min/avg/max/mdev = 0.088/0.092/0.099/0.004 ms
成功です!両方のノードは、あたかも同じローカルネットワークセグメント上の 2 台のコンピューターであるかのように、互いに通信できます。
2 番目のノードを別のサブネットに再構成する
このステップでは、2 つのノード間の直接通信を意図的に切断します。これは、node2 を node1 とは完全に異なる IP サブネットに再構成することで行います。これは、2 つのデバイスが物理的に接続されているが、論理的には異なるネットワークに分離されているシナリオをシミュレートします。
現在、node1 は 192.168.56.0/24 サブネットにあります。ここで node2 を 192.168.58.0/24 サブネットに移動させます。3 番目の数字(オクテット)が異なる(56 対 58)ため、これらは別のサブネットと見なされます。
node2 が新しいネットワークで完全に分離されていることを確認するために、まず eth0 インターフェースからすべての既存の IP アドレスを削除する必要があります。これには、以前に追加した静的 IP と、Docker が自動的に割り当てた元の IP の両方が含まれます。ip addr flush コマンドがこの作業に適したツールです。
docker exec node2 ip addr flush dev eth0
このコマンドは eth0 からすべての IP 構成を削除し、クリーンな状態を保証します。成功した場合、何も出力されないはずです。
次に、新しいサブネットに属する新しい IP アドレス 192.168.58.11 を追加しましょう。
docker exec node2 ip addr add 192.168.58.11/24 dev eth0
変更を確認するために、node2 のネットワーク構成を再度確認しましょう。
docker exec node2 ip addr show eth0
古い IP アドレスがすべて削除され、新しい IP アドレス(192.168.58.11)のみが存在することがわかります。これにより、node2 が 192.168.56.0/24 サブネットに存在しなくなったことが確認されます。
11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:38:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.58.11/24 scope global eth0
valid_lft forever preferred_lft forever
node1 が 192.168.56.0/24 サブネットにあり、node2 が 192.168.58.0/24 サブネットにあるため、これらは論理的に分離されました。
接続テストと失敗の観察
この最後のステップでは、再度ノード間で ping を試みます。node2 が新しいサブネットで完全に分離されたため、通信は失敗すると予想されますが、ネットワーク層の動作を示す 2 つの異なる重要な方法で失敗します。
まず、node1 から node2 の新しい IP アドレス(192.168.58.11)を ping してみましょう。
docker exec node1 ping -c 4 192.168.58.11
出力を観察してください。コマンドはタイムアウトし、100% のパケットロスが発生します。
PING 192.168.58.11 (192.168.58.11) 56(84) bytes of data.
--- 192.168.58.11 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3076ms
このタイムアウトは、node1 がまだ Docker ネットワークへのルートを持っているため、ping パケットを送信するからです。ネットワークはそれを node2 に転送します。しかし、node2 はもはやそのネットワーク上に存在せず、戻るルートも持っていないため、応答を送信できません。node1 からの ping は応答を得られません。
次に、逆方向をテストしましょう。node2 から node1 を ping してみてください。
docker exec node2 ping -c 4 192.168.56.10
今回は、ほとんどすぐに異なるエラーメッセージが表示されます。
ping: connect: Network is unreachable
ping: connect: Network is unreachable というメッセージは重要です。これは node2 のオペレーティングシステムからの即時の応答です。OS がルーティングテーブルを確認し、宛先 192.168.56.10 がパスのないネットワーク上にあることを認識し、パケットの送信を試みることさえ拒否したことを意味します。これは ip addr flush を使用した直接の結果であり、すべてのルートがクリアされ、コンテナが他のネットワークから完全に分離されました。
この実験は、IP サブネット化とルーティングの重要な役割を効果的に示しました。デバイスが同じサブネット上にある場合、直接通信できます。異なるサブネット上にある場合、それらの間のトラフィックを転送するには、適切なルートを持つルーターのようなレイヤー 3 デバイスが必要です。
まとめ
この実験では、カスタムブリッジネットワークに接続された Docker コンテナを使用して、2 ノードのネットワーク環境をシミュレートする方法を学びました。ip addr コマンドを使用してネットワークインターフェイスに静的 IP アドレスを構成するという、不可欠な Linux スキルを実践しました。両方のノードに同じサブネットから IP アドレスを割り当てることで、ping ユーティリティを使用してそれらの間の直接的なレイヤー 3 接続を正常に検証し、ローカルネットワークセグメントでの通信に必要な基本的な要件を示しました。
この実験では、元のネットワーク構成を完全にフラッシュした後、一方のノードを異なるサブネットの IP アドレスで再構成することにより、重要なネットワーク概念をさらに示しました。その後の ping を介した通信の試みは、一方の方向でのタイムアウトと、もう一方での「宛先ホストが見つかりません」というエラーという、2 つの異なる結果で失敗しました。この結果は、異なる論理サブネット上のノードは、ルーターなしでは直接通信できないことを効果的に示し、ルーティングテーブルとインターフェイス構成がネットワーク接続にどのように影響するかを浮き彫りにしました。



