ウェブサイト検索

Kubernetesネットワーキングを検査する方法


紹介

Kubernetesは、サーバーノードのクラスター全体でコンテナ化されたアプリケーションを管理できるコンテナオーケストレーションシステムです。クラスター内のすべてのコンテナ間でネットワーク接続を維持するには、いくつかの高度なネットワーキング技術が必要です。この記事では、このネットワーク設定を調査するためのツールと技術を簡単に紹介します。

これらのツールは、接続の問題をデバッグしたり、ネットワークのスループットの問題を調査したり、Kubernetesを探求してその動作を学ぶ際に役立つかもしれません。

Kubernetesについて一般的にもっと学びたい場合は、私たちのガイドKubernetes入門が基本をカバーしています。Kubernetesのネットワーキングに特化した概要については、Kubernetesのネットワーク内部をお読みください。

成長のために構築されたシンプルな管理されたKubernetesサービスをチェックしてみてください。マネージドKubernetesホスティングサービスを探しているなら、ぜひご覧ください。

始めに

このチュートリアルでは、Kubernetesクラスターがあり、kubectlがローカルにインストールされていて、クラスターに接続するように設定されていることを前提とします。

以下のセクションには、Kubernetesノードで実行することを目的とした多くのコマンドが含まれています。それらはこのように見えます:

  1. echo 'this is a node command'

ローカルマシンで実行する必要があるコマンドは、次のようになります。

  1. echo 'this is a local command'

注意: このチュートリアルのほとんどのコマンドは、rootユーザーとして実行する必要があります。もしKubernetesノードでsudo対応のユーザーを使う場合は、必要に応じてコマンドを実行する際にsudoを追加してください。

ポッドのクラスターIPを見つける

KubernetesポッドのクラスターIPアドレスを見つけるには、ローカルマシンでkubectl get podコマンドを使用し、オプション-o wideを付けます。このオプションは、ポッドが存在するノードやポッドのクラスターIPを含む、より多くの情報をリストします。

  1. kubectl get pod -o wide
NAME                           READY     STATUS    RESTARTS   AGE       IP            NODE
hello-world-5b446dd74b-7c7pk   1/1       Running   0          22m       10.244.18.4   node-one
hello-world-5b446dd74b-pxtzt   1/1       Running   0          22m       10.244.3.4    node-two

強調されたIP列には、各ポッドの内部クラスタIPアドレスが含まれます。

探しているポッドが見つからない場合は、正しいネームスペースにいることを確認してください。フラグ--all-namespacesを追加することで、すべてのネームスペースにあるポッドをリストすることができます。

サービスのIPを見つける

kubectlを使ってサービスIPを見つけることもできます。この場合、すべてのネームスペースのすべてのサービスをリストアップします:

  1. kubectl get service --all-namespaces
NAMESPACE     NAME                       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
default       kubernetes                 ClusterIP   10.32.0.1       <none>        443/TCP         6d
kube-system   csi-attacher-doplugin      ClusterIP   10.32.159.128   <none>        12345/TCP       6d
kube-system   csi-provisioner-doplugin   ClusterIP   10.32.61.61     <none>        12345/TCP       6d
kube-system   kube-dns                   ClusterIP   10.32.0.10      <none>        53/UDP,53/TCP   6d
kube-system   kubernetes-dashboard       ClusterIP   10.32.226.209   <none>        443/TCP         6d

サービスIPはCLUSTER-IP列にあります。

ポッドネットワークネームスペースの発見と入場

各Kubernetesポッドには独自のネットワーク名前空間が割り当てられます。ネットワーク名前空間(またはnetns)は、ネットワークデバイス間の隔離を提供するLinuxネットワーキングのプリミティブです。

ポッドのネット名前空間内からコマンドを実行することは、DNS解決や一般的なネットワーク接続を確認するのに役立ちます。そのためには、まずポッド内のコンテナのうちの1つのプロセスIDを調べる必要があります。Dockerの場合、2つのコマンドのシリーズでそれを行うことができます。まず、ノード上で実行されているコンテナをリストします:

  1. docker ps
CONTAINER ID        IMAGE                                   COMMAND                  CREATED             STATUS              PORTS               NAMES
173ee46a3926        gcr.io/google-samples/node-hello        "/bin/sh -c 'node se…"   9 days ago          Up 9 days                               k8s_hello-world_hello-world-5b446dd74b-pxtzt_default_386a9073-7e35-11e8-8a3d-bae97d2c1afd_0
11ad51cb72df        k8s.gcr.io/pause-amd64:3.1              "/pause"                 9 days ago          Up 9 days                               k8s_POD_hello-world-5b446dd74b-pxtzt_default_386a9073-7e35-11e8-8a3d-bae97d2c1afd_0
. . .

興味のあるポッド内の任意のコンテナのコンテナIDまたは名前を見つけてください。上記の出力では、2つのコンテナを示しています:

  • 最初のコンテナは、hello-world ポッドで実行されている hello-world アプリです。
  • 2つ目は、hello-worldポッド内で動作するポーズコンテナです。このコンテナは、ポッドのネットワーク名前空間を保持するためだけに存在します。

コンテナのプロセスIDを取得するには、コンテナのIDまたは名前をメモし、それを次のdockerコマンドで使用してください:

  1. docker inspect --format '{{ .State.Pid }}' container-id-or-name
14552

プロセスID(PID)が出力されます。これで、nsenterプログラムを使用して、そのプロセスのネットワークネームスペースでコマンドを実行できます:

  1. nsenter -t your-container-pid -n ip addr

自分のPIDを使用し、ip addrをポッドのネットワーク名前空間内で実行したいコマンドに置き換えてください。

注意: ポッドの名前空間でコマンドを実行するために nsenter を使用する利点の一つは、docker exec のようなものを使う代わりに、ノード上で利用可能なすべてのコマンドにアクセスできることです。それに対して、コンテナには通常制限されたコマンドセットがインストールされています。

ポッドの仮想イーサネットインターフェースの発見

各ポッドのネットワークネームスペースは、仮想イーサネットパイプを介してノードのルートネットワークネームスペースと通信します。ノード側では、このパイプは通常vethで始まり、veth77f2275やveth01のようなユニークな識別子で終わるデバイスとして表示されます。ポッド内では、このパイプはeth0として表示されます。

特定のポッドにペアリングされているvethデバイスを関連付けることは便利です。そのために、ノード上のすべてのネットワークデバイスをリストし、次にポッドのネットワーク名前空間内のデバイスをリストします。その後、2つのリスト間でデバイス番号を比較して接続を確認します。

まず、nsenterを使用してポッドのネットワークネームスペースでip addrを実行します。これを行う方法についての詳細は前のセクションポッドネットワークネームスペースの発見と入出を参照してください:

  1. nsenter -t your-container-pid -n ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
    link/ether 02:42:0a:f4:03:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.244.3.4/24 brd 10.244.3.255 scope global eth0
       valid_lft forever preferred_lft forever

このコマンドはポッドのインターフェースのリストを出力します。出力例のeth0@の後にあるif11の番号に注意してください。これは、このポッドのeth0がノードの11番目のインターフェースにリンクされていることを意味します。次に、ノードのデフォルトの名前空間でip addrを実行して、そのインターフェースのリストを表示します:

  1. ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever

. . .

7: veth77f2275@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master docker0 state UP group default
    link/ether 26:05:99:58:0d:b9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::2405:99ff:fe58:db9/64 scope link
       valid_lft forever preferred_lft forever
9: vethd36cef3@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master docker0 state UP group default
    link/ether ae:05:21:a2:9a:2b brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::ac05:21ff:fea2:9a2b/64 scope link
       valid_lft forever preferred_lft forever
11: veth4f7342d@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master docker0 state UP group default
    link/ether e6:4d:7b:6f:56:4c brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::e44d:7bff:fe6f:564c/64 scope link
       valid_lft forever preferred_lft forever

この例の出力で11番目のインターフェースはveth4f7342dです。これは、私たちが調査しているポッドへの仮想イーサネットパイプです。

Conntrack接続トラッキングの検査

バージョン1.11以前は、Kubernetesはiptables NATとconntrackカーネルモジュールを使用して接続を追跡していました。現在追跡されているすべての接続をリストするには、conntrackコマンドを使用してください:

  1. conntrack -L

新しい接続を継続的に監視するには、-Eフラグを使用します:

  1. conntrack -E

特定の宛先アドレスへのconntrackトラッキングされた接続を一覧表示するには、-dフラグを使用します:

  1. conntrack -L -d 10.32.0.1

ノードがサービスへの信頼できる接続を確立できない場合、接続トラッキングテーブルが満杯で新しい接続が破棄されている可能性があります。その場合、システムログに次のようなメッセージが表示されることがあります:

Jul 12 15:32:11 worker-528 kernel: nf_conntrack: table full, dropping packet.

接続を追跡するための最大数を設定するためのsysctl設定があります。次のコマンドを使用して現在の値をリストアップできます:

  1. sysctl net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_max = 131072

新しい値を設定するには、-wフラグを使用します:

  1. sysctl -w net.netfilter.nf_conntrack_max=198000

この設定を永続的にするには、sysctl.confファイルに追加してください:

. . .
net.ipv4.netfilter.ip_conntrack_max = 198000

iptablesルールの検査

バージョン1.11以前のKubernetesは、Service IPの仮想IP変換と負荷分散を実装するためにiptables NATを使用していました。

ノード上のすべてのiptablesルールをダンプするには、iptables-saveコマンドを使用します:

  1. iptables-save

出力が長くなる可能性があるため、ファイルに出力をパイプすることをお勧めします(iptables-save > output.txt)や、ページャーを使用すること(iptables-save | less)でルールをより簡単に確認できます。

KubernetesサービスNATルールのみを一覧表示するには、iptablesコマンドと-Lフラグを使用して正しいチェーンを指定します:

  1. iptables -t nat -L KUBE-SERVICES
Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  anywhere             10.32.0.10           /* kube-system/kube-dns:dns cluster IP */ udp dpt:domain
KUBE-SVC-ERIFXISQEP7F7OF4  tcp  --  anywhere             10.32.0.10           /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:domain
KUBE-SVC-XGLOHA7QRQ3V22RZ  tcp  --  anywhere             10.32.226.209        /* kube-system/kubernetes-dashboard: cluster IP */ tcp dpt:https
. . .

クラスタDNSをクエリする

クラスタのDNS解決をデバッグする一つの方法は、必要なすべてのツールを備えたデバッグコンテナをデプロイし、次にkubectlを使用してそのコンテナ内でnslookupを実行することです。これは公式のKubernetesドキュメントに記載されています。

クラスタDNSにクエリを送る別の方法は、ノードからdigとnsenterを使用することです。digがインストールされていない場合、DebianベースのLinuxディストリビューションではaptを使用してインストールできます:

  1. apt install dnsutils

まず、kube-dnsサービスのクラスターIPを見つけます:

  1. kubectl get service -n kube-system kube-dns
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.32.0.10   <none>        53/UDP,53/TCP   15d

クラスタIPは上に強調表示されています。次に、nsenterを使用して、コンテナの名前空間内でdigを実行します。詳細については、ポッドネットワーク名前空間の発見と使用のセクションを参照してください。

  1. nsenter -t 14346 -n dig kubernetes.default.svc.cluster.local @10.32.0.10

このdigコマンドは、service-name.namespace.svc.cluster.localのサービスの完全なドメイン名を検索し、クラスタDNSサービスIPのIP(@10.32.0.10)を指定します。

IPVSの詳細を見る

Kubernetes 1.11 以降、kube-proxy は IPVS を設定して、仮想サービス IP をポッド IP に変換することができます。ipvsadm を使用して IP の変換テーブルを一覧表示できます。

  1. ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  100.64.0.1:443 rr
  -> 178.128.226.86:443           Masq    1      0          0
TCP  100.64.0.10:53 rr
  -> 100.96.1.3:53                Masq    1      0          0
  -> 100.96.1.4:53                Masq    1      0          0
UDP  100.64.0.10:53 rr
  -> 100.96.1.3:53                Masq    1      0          0
  -> 100.96.1.4:53                Masq    1      0          0

単一のサービスIPを表示するには、-tオプションを使用し、希望するIPを指定します:

  1. ipvsadm -Ln -t 100.64.0.10:53
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  100.64.0.10:53 rr
  -> 100.96.1.3:53                Masq    1      0          0
  -> 100.96.1.4:53                Masq    1      0          0

結論

この記事では、Kubernetesクラスターのネットワーキングの詳細を探求し、調査するためのコマンドとテクニックをいくつかレビューしました。Kubernetesに関する詳細情報については、Kubernetesチュートリアルのタグや公式のKubernetesドキュメントをご覧ください。

関連記事: