5分でわかる!Kubernetes/CloudNative Topics

入門 Network Service Mesh CloudNativeとNetworkingの交差点〜

こんにちは。サイバーエージェントの杉浦です。

5分でわかる!Kubernetes/CloudNative Topics連載の第4回は、CNCF Sandboxプロジェクトの一つでもあるNetwork Service Meshについて紹介します。

この記事ではNetwork Service Meshとは何か、どういった仕組みで動くのか、そしてNetwork Service Meshのユースケースについて紹介し、最後にkindを使って実際にNetwork Service MeshをKubernetesクラスタで動かした様子について紹介します。

Network Service Meshとは

Network Service Meshとは、サービスメッシュのコンセプトをL2/L3ネットワークに適用するOSSです。

サービスメッシュでは各アプリケーションにプロキシを設置して、アプリケーション間のセキュアな接続性と、アプリケーション間の通信の制御・観測機能を提供します。Istioをはじめとする既存のサービスメッシュを実現するツールは、この機能を主にL7(HTTP/HTTPS)の通信に対して提供しています。これに対して、Network Service Meshはサービスメッシュの機能をL2/L3ネットワークに対して提供します。

Network Service Meshは設計上、Kubernetesクラスタ内の通信だけでなく、Kubernetesクラスタ間の通信に対しても適用できます。またそれだけではなく、各アプリケーションがKubernetesクラスタ・VMクラスタ・ベアメタルサーバクラスタのどのワークロードのネットワークに所属していても使えるように設計されています。

図1 Network Service Mesh概略図
図1

Network Service Meshの仕組み

次はNetwork Service Meshの仕組みについて見ていきましょう。

Network Service MeshはClient・Endpoint・Virtual Wireの3つの要素から成り立っています。

1つ目のClientは文字通り通信を発生させる実体で、KubernetesにおけるPodやVM、物理サーバなどが該当します。 なお個々のClientはアプリケーションの識別子として用いられるSPIFFE IDによって認証されている必要があります。2つ目のEndpointはClientの通信先に該当するもので、Clientと同一あるいは異なるKubernetesクラスタにデプロイされたPodやVM、物理サーバが該当します。3つ目のVirtual Wire(vWire)はVPNにおけるトンネルと同様の役割を果たし、ClientとEndpoint間を接続します。またClientとEndpointはそれぞれ一つ以上のvWireを持つことができます。

Network Service Meshにおける通信経路の確立は、ClientからNetwork Service Meshのコントロールプレーン(Network Service Manager)に対する要求によって行われます。

ClientはNetwork Service Managerに対して、⁠Request」gRPCリクエストを送信し、ClientとEndpointを結ぶvWireを作成します。そして「Close」gRPCリクエストによってvWireは閉じられます。また、このvWireには有効期限があり、時間経過によっても閉じられます。そのためClientはvWireの状態を「MonitorConnection」gRPCストリームによって監視し、定期的に「Request」によってvWireを更新する必要があります。

図2 Network Service Meshの各コンポーネント
図2

ここでKubernetesクラスタにおける、Network Service Meshの利用方法を見てみましょう。KubernetesではNetwork Service Meshのインストール時に追加されるNetworkServiceカスタムリソースを利用します。

NetworkServiceリソースの例はこちらです。この例ではIP通信において、⁠app: sample」ラベルが貼られたClientからの通信を、⁠service: firewall」ラベルが貼られたEndpointへ送信するための設定が記述されています。

---
apiVersion: networkservicemesh.io/v1
kind: NetworkService
metadata:
  name: my-network-service
spec:
  payload: IP
  matches:
    - source_selector:
        app: sample
      routes:
        - destination_selector:
            service: firewall
図3 Network Service Mesh 例
図3

ここでKubernetesクラスタにおける、Network Service Meshの仕組みついてもう少し深く見ます。

まずはじめにClientからNetwork Service Meshにリクエストが送信されます。その後ClientとEndpointのPod内に、新しくネットワークインタフェースが作成されます。この別のネットワークインタフェースを作成する手法は、既存のネットワークインタフェースに対して影響を与えないため、CNIプラグインにより構築される既存のKubernetesクラスタのネットワーク環境に影響を与えません。

図4 Network Service MeshのネットワークとKubernetesのネットワーク
図4

Network Service Meshのユースケース

Network Service Meshのユースケースの一つとしては、複数のワークロードを跨ぐVPNの構築があります。ClientとEndpointをそれぞれ別ワークロードにデプロイされているコンポーネントを指定することで、ユーザはそのコンポーネント間のみにネットワーク疎通性を持たせたVPNを構築できます。

またサービスチェイニングの実現方法の一つとしてのNetwork Service Meshの活用が期待されています。サービスチェイニングとは、ルータやファイアウォールといったネットワークサービスに対して、通信パケットを適切な順番で転送させる機能を指します。

Network Service MeshではClientとEndpointを指定することで、通信パケットの転送経路をユーザが指定できます。そのため、ネットワークサービスのPodに対して適切にラベルを付与し、Endpointとして指定することで、ユーザは通信パケットを特定の順番で転送できます。

特に昨今では、汎用的なマシン上で仮想マシンにネットワーク機能を持たせるVirtual Network Function(VNF)の手法をコンテナに拡張したContainer Network Function(CNF)と呼ばれる手法が注目されており、そういったCNFにおけるサービスチェイニングの実現にNetwork Service Meshは相性が良いと言えます。

Endpointをラベルを使って指定できる仕組みは、KubernetesにおけるPodのような生成と削除が高頻度で行われ、IPアドレスが一つに定まらない環境においては有効に働くことが期待されています。

Network Service Meshを試してみる

それでは公式で用意されている例を使って、2つのKubernetesクラスタにそれぞれデプロイされたPod間で、実際にNetwork Service Meshを使った通信をさせてみます(図5⁠⁠。

今回使う実験環境を用意するスクリプトも用意しました。使用する際はkindとkubectlがインストールされた環境で以下のようにして実行してください。

$ curl https://raw.githubusercontent.com/chez-shanpu/nsm-demo/main/kind.yaml -O
$ curl https://raw.githubusercontent.com/chez-shanpu/nsm-demo/main/setup.sh -O
$ chmod +x ./setup.sh && sh ./setup.sh
図5 Network Service Meshを使ってクラスタを跨いだ通信を実現する例(networkservicemesh/deployments-k8sより
図5

この例では2つのKubernetesクラスタを用意し、クラスタ1にClient、クラスタ2にEndpointを用意し、このClient・Endpoint間をNetworkServiceリソースを使って接続します。

クラスタ1のClientから発行された、クラスタ2のgreeting Podへのリクエストは、NetworkServiceリソースによって構築されたvWireを経由してクラスタ2のEndpointに到達し、その後クラスタ2のネットワークでリクエストが転送されます。

このときClient・EndpointのPod内のネットワークインタフェースを一覧表示すると、それぞれNetwork Service Mesh用のインタフェースが作成されていることがわかります。

# Client
$ kubectl --kubeconfig cluster1.yaml exec deploy/alpine -- ip a
Defaulted container "alpine" out of: alpine, cmd-nsc, cmd-nsc-init (init)
1: lo: <LOOPBACK,UP,LOWER_UP> …
2: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> …
3: nsm-1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1440 qdisc mq state UNKNOWN qlen 500
    link/[65534]
    inet 172.16.1.3/32 scope global nsm-1
       valid_lft forever preferred_lft forever
    inet6 fe80::8e57:96e:d968:3c63/64 scope link flags 800
       valid_lft forever preferred_lft forever

# Endpoint
$ kubectl --kubeconfig cluster2.yaml exec $(kubectl --kubeconfig cluster2.yaml get po |grep proxy |cut -d ' ' -f 1) -- ip a
1: lo: <LOOPBACK,UP,LOWER_UP> …
2: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> …
3: autoscale--1d96: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1440 qdisc mq state UNKNOWN qlen 500
    link/[65534]
    inet 172.16.1.2/32 scope global autoscale--1d96
       valid_lft forever preferred_lft forever
    inet6 fe80::41d:9636:913b:fc26/64 scope link flags 800
       valid_lft forever preferred_lft forever

実際にクラスタ1にデプロイされたClientから、クラスタ2にデプロイされたアプリケーションにリクエストを送信すると、レスポンスが返ってくることが確認できます。

$ kubectl --kubeconfig cluster1.yaml exec deploy/alpine -c cmd-nsc -- curl -s greeting.default:9080
"hello world from istio"

公式サイトには他にも様々な例が用意されているので、よかったら触ってみてください。

結び

この記事ではNetwork Service MeshというL2/L3レベルでのサービスメッシュを実現するOSSについて紹介しました。

CloudNativeな世界では、イミュータブルインフラストラクチャやマイクロサービスアーキテクチャの手法が普及し、アプリケーション間の通信ネットワークは大規模になるとともに、変化に対して柔軟かつ簡単に操作できることが求められるようになりました。このことに対して、Network Service Meshは各アプリケーションワークロードに紐づけられたメタデータを使うアプローチで、CloudNativeにおけるNetworkingの課題に対する解決策を提供してくれました。

Network Service Meshの開発状況はGrafanaダッシュボードで公開されています。開発開始以来、継続的に開発が進められている様子が見られ、今後の発展に期待したいと思います!

おすすめ記事

記事・ニュース一覧