Kubernetesネットワークプリミティブの検査とデバッグ方法



導入
Kubernetesはコンテナノードのクラスタ間でコンテナ化されたアプリケーションを管理できるコンテナオーケストレーションシステムです.クラスタ内のすべてのコンテナ間のネットワーク接続を維持するには、いくつかの高度なネットワーク技術が必要です.本稿では、このネットワークセットアップを検査するためのツールとテクニックを簡単に説明します.
これらのツールは、接続の問題をデバッグしたり、ネットワークのスループット問題を調査したり、それがどのように動作するかを知るためにKubernetesを探索している場合に便利です.
場合は、一般的にKubernetesについての詳細を知りたい場合は、DigitalOceanAn Introduction to Kubernetes . Kubernetesのネットワーク特定の概要については、読んでくださいKubernetes Networking Under the Hood .

始める
このチュートリアルでは、既にKubernetesクラスタを持っていることを前提としていますkubectl あなたのローカルコンピュータにインストールされ、クラスタに接続するように構成されています.任意kubectl 示されるコマンドは、あなたのローカルマシンで実行されることを目的とします.
他のすべてのコマンドはrootユーザとしてKubernetesノードで実行されます.あなたのKubernetesノードでsudoを有効にしないrootユーザを使用するならば、使用してくださいsudo 必要に応じてコマンドを実行します.

のポッドクラスタを見つける
Kubernetes podのクラスタIPアドレスを見つけるにはkubectl get pod オプションを指定してローカルマシンでコマンドを実行する-o wide . このオプションは、PODが存在するノード、PODのクラスタIPを含む詳細な情報を一覧表示します.
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列には、各PODの内部クラスタIPアドレスが含まれます.
あなたが探しているポッドを見ないならば、あなたが正しい名前空間にいることを確認してください.フラグを追加することで、すべての名前空間のすべてのポッドを一覧表示できます--all-namespaces .

サービスのIPを見つける
使用するサービスIPを見つけることができますkubectl 同様に.この場合、すべての名前空間のすべてのサービスを一覧表示します
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はクラスタ- IPカラムで見つけることができます.

PODネットワーク名前空間の検索と入力
各Kubernetes podは独自のネットワーク名前空間を割り当てます.ネットワーク名前空間(またはnetns)は、ネットワークデバイス間の分離を提供するLinuxネットワークプリミティブです.
これは、DNSの解像度や一般的なネットワーク接続をチェックするためにpodのnetns内からコマンドを実行するのに便利です.そのためには、まずコンテナの一つのプロセスIDをpodで調べなければなりません.Dockerでは、2つのコマンドの一連の操作を行うことができます.まず、ノードを実行しているコンテナを一覧表示します.
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または名前を見つけてください.上記の出力では二つのコンテナを示しています.
  • 最初の容器はhello-world アプリケーションの実行hello-world ポッド
  • 番目は、中で動いている休止容器ですhello-world ポッド.このコンテナは、podのネットワーク名前空間にのみ保持されます
  • いずれかのコンテナのプロセスIDを取得するには、コンテナIDまたは名前をメモし、次のように使用しますdocker コマンド
    docker inspect --format '{{ .State.Pid }}' your_container_id_or_name
    
    出力:
    14552
    
    プロセスID (またはPID )が出力されます.今、我々はnsenter そのプロセスのネットワーク名前空間でコマンドを実行するプログラム
    nsenter -t your_container_pid -n ip addr
    
    あなた自身のPIDを使用してくださいip addr コマンドでPODのネットワーク名前空間内で実行します.

    Note: One advantage of using nsenter to run commands in a pod's namespace – versus using something like docker exec – is that you have access to all of the commands available on the node, instead of the typically limited set of commands installed in containers.



    ポッドの仮想イーサネットインタフェースを見つける
    各々のPODのネットワーク名前空間は、仮想イーサネットパイプを通してノードのルートNETNSと通信します.ノード側では、このパイプはveth などのユニークな識別子で終了するveth77f2275 or veth01 . ポッドの内側にはこのパイプが見えるeth0 .
    これはどのように相関することができますveth デバイスは、特定のpodと対になっています.そうするために、我々はノードの上にすべてのネットワーク装置をリストして、次に、podのネットワーク名前空間で装置をリストします.次に、2つのリスティング間のデバイス番号を関連づけて接続を行うことができます.
    ファーストランip addr PODのネットワーク名前空間でnsenter . この方法の詳細については、前のセクションの検索とPODネットワーク名前空間を参照してください.
    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
    
    コマンドはpodのインターフェースのリストを出力します.注意if11eth0@ 出力例では.これは、このポッドのeth0 ノードの第11インターフェイスにリンクされます.今すぐ実行ip addr ノードのデフォルトの名前空間でインターフェイスを一覧表示します.
    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 コマンド
    conntrack -L
    
    新しい接続のために連続的に見て、使用する-E フラグ:
    conntrack -E
    
    特定の宛先アドレスへのConntrack追跡接続を一覧表示するには、-d フラグ:
    conntrack -L -d your_destination_address
    
    ノードがサービスに信頼性の高い接続を行う問題がある場合は、接続の追跡テーブルがいっぱいであり、新しい接続が削除されている可能性があります.その場合、システムログに次のようなメッセージが表示されます.
    Jul 12 15:32:11 worker-528 kernel: nf_conntrack: table full, dropping packet.
    
    sysctlには、接続する最大接続数を設定します.現在の値を次のコマンドで一覧表示できます.
    sysctl net.netfilter.nf_conntrack_max
    
    出力:
    net.netfilter.nf_conntrack_max = 131072
    
    新しい値を設定するには-w フラグ:
    sysctl -w net.netfilter.nf_conntrack_max=198000
    
    この設定を永続化するには、sysctl.conf ファイル
    net.ipv4.netfilter.ip_conntrack_max = 198000
    

    iptables規則の検査
    バージョン1.11の前に、KubernetesはIPIP NATを使用して、サービスIPのための仮想IP翻訳とロードバランシングを実装しました.
    ノード上のすべてのiptables規則をダンプするにはiptables-save コマンド
    iptables-save
    
    出力を長くすることができるので、ファイルをパイプにしたいかもしれません(iptables-save > output.txt ) またはページャiptables-save | less ) より簡単にルールを確認する.
    KubernetesサービスのNAT規則を列挙するには、iptables コマンドと-L 正しいチェーンを指定するフラグ
    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解決をデバッグする1つの方法は、必要なすべてのツールを使用してデバッグコンテナを展開することですkubectl 実行するnslookup その上にこれはthe official Kubernetes documentation .
    クラスタDNSを問い合わせるもう一つの方法はdig and nsenter ノードから.If dig がインストールされていない場合、apt DebianベースのLinuxディストリビューションについて:
    apt install dnsutils
    
    まず、Kube DNSサービスのクラスタIPを探します.
    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 コンテナの名前空間.セクションを見てくださいFinding and Entering Pod Network Namespaces この詳細については
    nsenter -t 14346 -n dig kubernetes.default.svc.cluster.local @10.32.0.10
    
    このdig サービスはサービス名のサービスの完全なドメイン名を見ます.名前空間.SVCクラスタ.ローカルおよび特定のクラスタDNSサービスIPのIP@10.32.0.10 ).

    IPVS詳細を見ること
    Kubernetes 1.11現在kube-proxy 仮想サービスIPの変換をpod ipsに処理するためにipvを設定できます.IPSの翻訳表を一覧表示できますipvsadm :
    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を指定します.
    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の詳細については、見てくださいDigitalOcean's Kubernetes tutorials and the official Kubernetes documentation .