自分のPodのネットワークを読む
目標
ネットワークを図で学んでも、あまり身につきません。今みなさんが使っているこのPodのネットワークを、自分で読んでみます。
教材用に作った例ではなく、実際の本番クラスターなので、教科書に出てこないものが、そのまま出てきます。/32のアドレス、インターフェースと異なるパスMTU、searchドメインです。
見る場所
ip -4 addr show eth0 # 내 주소
ip route # 어디로 나가나
ip route get 1.1.1.1 # 이 목적지로는 어떻게 가나
cat /sys/class/net/eth0/mtu # 인터페이스 MTU
cat /etc/resolv.conf # 이름을 어떻게 푸나
ss -tan # 지금 연결 상태
実験用サーバー
python3 -m http.server 8080 --bind 127.0.0.1 &
ステップ
- アドレスとネットマスク →
01-addr.txt - ルーティング →
02-route.txt - MTU →
03-mtu.txt - DNS →
04-dns.txt - ポートの衝突 →
05-port.txt - 手で打ったHTTP →
06-http.txt - 接続の状態 →
07-states.txt - まとめ →
08-notes.md
参考
このPodは、外のインターネットには出られません。DNSの照会だけが開いています。そのため、実験はすべて、このPodの中のサーバーで行います。学ぶべきことは、すべて学べます。
自分のアドレスとネットマスク
このPodのIPとネットマスクを確認して01-addr.txtに残し、そのネットマスクがどういう意味かを1行書いてください。
ip -4 addr show eth0を使います。/32が出るはずです。
/32は、このネットワークに自分1人だけという意味です。普通は/24のように、同じアドレス帯にネイバーがいるのですが、ここにはいません。それなら、外へどう出るのかが、次のステップです。
では、どうやって外へ出るのか
ルーティングテーブルを取り出して02-route.txtに残し、/32なのにゲートウェイに届く理由を書いてください。
ip routeを使います。2行が見えるはずです。default via <게이트웨이>と<게이트웨이> dev eth0 scope linkです(プレースホルダーはゲートウェイのアドレスです)。
2行目が答えです。そのアドレスは、ルーティングなしで直接届く(on-link)とカーネルに知らせるものです。ネットマスクの上では同じアドレス帯ではありませんが、この経路があるおかげで、ゲートウェイに届きます。
インターフェースとパスのMTUが違う
eth0のMTUとデフォルト経路のMTUを、それぞれ確認して03-mtu.txtに残してください。違うなら、なぜ違うのかも書いてください。
インターフェースはcat /sys/class/net/eth0/mtu、経路はip route get 1.1.1.1で確認します。
インターフェースは1500なのに、経路はもっと小さいはずです。トンネルがヘッダーを付け足すからです。このクラスターは、ノード間を暗号化トンネルでつないでおり、その分だけ載せられるサイズが減ります。
MTUを誤って設定すると、小さなリクエストは通るのに、大きなレスポンスだけが止まる症状が出ます。原因を探すのが最も難しい種類です。
短い名前がどう解決されるのか
/etc/resolv.confを見て、短い名前を1つ実際に照会して、04-dns.txtに残してください。
cat /etc/resolv.confにnameserverとsearchがあります。getent hosts kubernetes.defaultのように、短い名前を照会してみてください。
searchに書かれたドメインが、順番に付け足されて試されます。kubernetes.default → kubernetes.default.<네임스페이스>.svc.cluster.local → …という具合です。そのため、短く書いても見つかります(プレースホルダーはネームスペースです)。
ポート1つにプログラム1つ
ポート8080にサーバーを起動した後、同じポートにもう1つ起動してみて、そのときに出るエラーを05-port.txtに残してください。
python3 -m http.server 8080 --bind 127.0.0.1 &で1つ起動し、Pythonで同じアドレスにbindを試してください。
[Errno 98] Address already in useが出ます。アドレス+ポートの組み合わせは、1つのプログラムだけが持てます。「ポートがすでに使用中」というエラーの正体です。
HTTPを手で打つ
ライブラリなしで、TCP接続に直接HTTPリクエストの文字列を書いてレスポンスを受け取り、06-http.txtに残してください。
bashだけでできます。
exec 3<>/dev/tcp/127.0.0.1/8080
printf 'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' >&3
timeout 3 head -8 <&3
行末は必ず\r\nにします。ヘッダーの最後に、空行がもう1つ必要です。HTTPは、単にTCPの上で、約束された文字をやり取りしているだけです。
接続には状態がある
接続を作って閉じながら、ssで状態がどう変わるかを見て、07-states.txtに残してください。TIME-WAITが見える必要があります。
ss -tanで見ます。接続中はESTAB、閉じた後はTIME-WAITがしばらく残ります。
TIME-WAITはバグではありません。遅れて届いたパケットが次の接続に混ざらないように、しばらく場所を確保しておくものです。短い接続を大量に作るサーバーで、これが溜まるとポートが枯渇します。そのため、接続を再利用(keep-alive)します。
3つのことをまとめる
08-notes.mdに3行以上書きます。/32なのに通信できる理由、MTUがずれたときに出る症状、TIME-WAITがある理由を書いてください。
本文に경로、MTU、TIME-WAITが含まれている必要があります(韓国語の語は「経路」を意味します)。