[K 8 S]NATループバック問題解析(LLP)


今日は、前文で紹介したNATループの問題について再紹介します.なぜなら、いくつかの国のIDCやクラウドがNAT返送の問題を解決するためにルータに必要な設定を追加しているにもかかわらず、原因が特定できずにアクティブでない問題が発生しているため、他の解決策を探す必要があるからです.
外部環境に依存せず,我々自身が問題を解決する方法はクラスタ内部で外部IPを使用しないことである.この目的のために、第1のオプションは内部DNSを使用することであり、第2のオプションはeBPF(またはIPTable)を使用して外部IPを通過するすべてのパケットを内部IPに強制的に転送することである(リダイレクト).また、Podから外部IPにアクセスし、ホストネットワークを使用するPodまたはKubeletから外部IPにアクセスすることも考えられる.(この場合、クラスタ内でコンテナレジストリサーバを実行し、Kubeletからコンテナイメージをインポートする場合は、コンテナレジストリサーバの外部ドメインアドレスを使用します.)
一般に、外部IPアクセスにより、NodePortまたはLoadBankサービスタイプのIngressGatewayを使用してクラスタ内部サービスに要求が伝達される.これはクラスタ内部から外部IPにアクセスする場合も同様であり、上記の2つの方法で外部IPを強制的に内部IPに変更するとゲートウェイを介さずにクラスタ内部サービスに直接アクセスするため、ホストネットワークを使用するPodまたはKubeletに問題が発生する.これは、ほかの文章に記載されているスロットベースのロードバランシング機能によって解決することができる.スロットベースのロード・バランシングは、BPFプログラム(各ノードのルートCGROUPからすべてのCGROUPのスロット・システムに呼び出される)によって行われ、ホスト・ネットワークは、次のようにクラスタ内サービスに直接アクセスできます.
$ bpftool cgroup tree
CgroupPath
ID       AttachType      AttachFlags     Name
/sys/fs/cgroup/unified
845      connect4                        sock4_connect
825      connect6                        sock6_connect
853      post_bind4                      sock4_post_bind
833      post_bind6                      sock6_post_bind
857      sendmsg4                        sock4_sendmsg
837      sendmsg6                        sock6_sendmsg
861      recvmsg4                        sock4_recvmsg
841      recvmsg6                        sock6_recvmsg
849      getpeername4                    sock4_getpeerna
829      getpeername6                    sock6_getpeerna
まず、内部DNSを使っている様子を見てみましょう.最も簡単な方法は、すべてのノードの/etc/hostsを使用して外部ドメインアドレスを内部IPに強制的に変更することです.ただし、これはIPを変更するだけなので、外部アクセスのポートが内部アクセスのポートと異なる場合は使用できません.
以下は、Ciliumが提供するLocalRedirectPolicyという機能を使用しています.これは、CitiumにおいてBPFを用いて種々のクーバーネディスサービスを処理する方式と同様に、外部IPに対する要求を内部IPに送信する.次に、特定のIP(10.10.0.10.10)およびポート(8080)に対する要求をクラスタ内のポート(nginx)に転送する設定を示す.
apiVersion: "cilium.io/v2"
kind: CiliumLocalRedirectPolicy
metadata:
  name: nginx-lrp
spec:
  redirectFrontend:
    addressMatcher:
      ip: "10.10.10.10"
      toPorts:
        - port: "8080"
          protocol: TCP
  redirectBackend:
    localEndpointSelector:
      matchLabels:
        run: nginx
    toPorts:
      - port: "80"
        protocol: TCP
対応するCRDをインストールし、Citiumのサービスリストを次のように表示します.
$ kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          7m36s   192.168.0.80   master   <none>           <none>

node0 $ cilium service list
ID   Frontend              Service Type    Backend
1    10.96.0.1:443         ClusterIP       1 => 172.26.50.200:6443
2    10.96.0.10:53         ClusterIP       1 => 192.168.1.96:53
                                           2 => 192.168.1.219:53
3    10.96.0.10:9153       ClusterIP       1 => 192.168.1.96:9153
                                           2 => 192.168.1.219:9153
4    10.108.175.91:80      ClusterIP       1 => 192.168.0.80:80
5    172.26.50.235:80      LoadBalancer    1 => 192.168.0.80:80
6    172.26.50.200:30904   NodePort        1 => 192.168.0.80:80
7    0.0.0.0:30904         NodePort        1 => 192.168.0.80:80
8    10.10.10.10:8080      LocalRedirect   1 => 192.168.0.80:80
上記のサービスリストから、10.10.0.10:8080のリクエストがNGINXエンドポイント192.168.0.80:80のアイテム(8番)に転送されていることがわかります.実際、任意のノードのホストから10.10.0.10:8080に接続すると、次のようにNGINXをインポートするインデックスページが表示されます.
node0 $ curl http://10.10.10.10:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
NATロールバックの問題が発生した場合、SNAT設定は通常、ネットワーク管理者に要求されますが、他の解決策が必要になる場合があります.参照してください.