Antrea - Yet Another CNI Plug-in for Kubernetes

Antreaとは

2019年11月にSan Diegoで行われたKubeConのタイミングで、Kubernetesのためのネットワークプラグインとして、新たにAntreaというプロジェクトが公開されました。CNI (Container Networking Interface) に準拠したプラグインで、現在はVMwareが中心となって開発をしていますが、オープンソースのプロジェクトですので、今後は徐々にコミュティーからのサポートが得られていくのではないかと思います。GitHubのリポジトリはここにあります。

“Antrea”という名前ですが、実はAntrea Netから来ています。Antreaはフィンランドに近いロシアの街で、世界最古の漁網が見つかった場所として知られており、その網は見つかった場所にちなみんで「Antrea Net」と呼ばれています。Kubernetesという名前は「操舵手」というギリシャ語から付けられたものですが、これに倣ってKubernetes関連のプロジェクトには船や海にちなんだ名前(例えばhelm/tillerなど)がつけられることが多くなっています。一方、CNIのプラグインであるCalicoやFlannelはどちらも繊維(ファブリック)に関係のある名前になっています(「ネットワーク」と「ファブリック」をかけている??)。この「海」と「ファブリック」の二つの要素を兼ね合わせた「漁網」であるAntrea Netに因んでAntreaという名前がつけられました。

Antreaの特徴は以下のような点になります。

  • Open vSwitchによるデータプレーン
  • Network Policyのサポート(iptablesからの脱却)
  • LinuxとWindowsサポート(予定)
  • 幅広いプラットフォームサポート
  • Octantとの連携
  • rspanやIPFIXのサポートなど(予定)

Antreaは仮想スイッチとして広く使われているOpen vSwitch (OVS)をデータパスに使用しているのがもっとも大きな特徴です。OVSをデータパスに使用することでいくつかのメリットが得られます。KubbernetesのNetwork PolicyやServiceのロードバランスを実現するために、他のCNIプラグインの多くはiptablesを使っています。iptablesは古くからある実績豊富な機能ではありますが、性能はあまりよろしくありません。iptabblesはルール数が多くなると、CPUに対する負荷、遅延、設定時間が非常に大きくなることが知られています。複雑なNetwork Policyや多数のServiceを使っているKubernetes環境では、iptablesベースのCNIでは期待した性能が得られないことが予想されます。一方、AntreaはOVSをデータプパスに使っているため、iptablesに起因する性能的問題を回避することができます。

OVSはLinux以外のOS(例えばWindows)もサポートしているので、多様な環境にまたがったKubernetesネットワーク環境を実現することができます。現時点のAntreaはLinuxのみのサポートですが、将来的にはWindowsもサポートする予定です。KubernetesはすでにWindowsをサポートしていますので、AntreaがWindowsをサポートするようになれば、LinuxとWindowsにまたがったネットワークを作って、そこに統一的なNetwork Policyを適用することができるようになります。また、OVSは仮想スイッチの機能だけではなく、他にもさまざまな機能(NetFlow/sFlow/IPFIXやRSPANなど)をサポートしています。将来的にはこれらの機能をAntreaから利用できるようにしていく予定です。

Antreaは幅広いプラットフォームで実行されれることを想定しています。オンプレの仮想環境はもちろん、ベアメタルや各種パブリッククラウドで実行することを想定して作られています。AntreaはKindで作ったKubernetesクラスタもサポートしていますので、簡易的にクラスタを用意してテストをすることもできて便利です。ただし、現在はLinuxの上のKindのみのサポートになります。MacOSのKindはまだサポートされてません。Kindで作ったクラスタでAntreaを動かす場合は、OVSのカーネルモジュールは使われず、OVSのユーザ空間のデータパスが使われます(ブリッジ作成時にdatapath_type=netdevが指定される)。

EncapsulationはデフォルトではVXLANが使われますが、GeneveやGRE、STTを使うこともできます。またこれらのEncapsulationとIPsecを組み合わせて使うこともできます。将来的には、Encapsulationをしないモードもサポートが予定されています。

VMwareはNSX-TのためのCNIプラグインとしてNCPを提供しています。それなのになぜ別のCNIプログインを開発しているのか疑問に思われる方もいるでしょう。NCPはすでに多くのプロダクション環境で使われており、実績面ではAntreaよりもはるかに成熟しています。また、NCPはiptablesに依存しないServiceのロードバランシングを既に実現しているので、スケーラビリティ的にも優れています。一方、Antreaはまだ出来立てのホヤホヤで商用の実績はありません。ただ、Antreaは100%オープンソースで手軽に始めることができるのは魅力です。幅広いプラットフォームやOSで利用できるようになる潜在的能力に魅力を感じる人も多いでしょう。Antreaが機能面、堅牢面においてすぐにNCPのレベルに達するとは考えにくいですが、コミュニティのサポートが得られればかなりのスピードで進化していく可能性を秘めていると思います。現時点でAntreaをプロダクション環境で使うことはお勧めしませんが、将来的には何かしらの形でNSX/NCPとの連携のようなこともできるようになるかもしれません。その頃にはAntreaも十分に成熟しているはずですので、ユーザにとって環境やユースケースによって使い分けられる選択肢が広がることは喜ばしいことでしょう。

アーキテクチャ

Antrea はKubernetesに特化したネットワークプラグインです。例えばCalicoはKubernetesだけでなくOpenStackなど他のオーケストレーションシステムをサポートしていますが、AntreaはKubernetesのみを対象としています。そのぶんAntreaはKubernetesの持つ仕組み(API、Tool、Operator)を最大限に利用するようになっています。

アーキテクチャーは以下通りです。

Antreaはいくつかのコンポーネントによって構成されます。Antrea Conrollerはいわゆるコントローラで、Deploymentとして作成さられます。Kubernetes APIを使って関連するオブジェクトの追加や削除を監視しています。一方、Antrea AgentはDaemonSetとして作られ、各ノードで動作します。Antrea agentはOpenFlowの設定をOVS に対して行います。antrea-cniはKubeletからのCNIコマンドをAntrea Agentに引き渡します。antctlコマンドはAntrea Controllerに対するCLIインターフェースを提供するもので、現在絶賛開発中です。

現時点ではkube-proxyはKubernetes標準のものを使用しています(したがって、Serviceのロードバランシングにはiptablesを使います)が、将来的にはこれはOVSベースのロードバランシングを使ったkube-proxyに置き換えられる予定です。Network Policyは既に完全にOVSベースで、iptablesは使われていません。なお、Antreaの最初のリリース(v0.1.0)では、OVSのOpenFlowテーブルを設定するのにovs-ofctlコマンドを使ってしましたが、現在はlibOpenflowライブラリを使うように変更されています。

OctantはKubernetes Clusterの状況を可視化してくれるダッシュボードです。AntreaはOctant用のプラグインを用意しており、Octantから簡単にAntreaの状況を確認することができます。

インストールと動作確認

今回はオンプレの環境でAntreaを動かしてみます。Kubernetes環境はESXiの上にCluster APIで2つのWorker Nodesを作った素のKubernetes環境を用意することにします。ESXi向けCluster API(CAPV; Cluster API Provider for vSphere) はCentOS 7、Ubuntu 18.04、Photon3用のOVAイメージを提供していますが、今回はUbuntu 18.04を使うことにします。AntreaはKubernetes 1.16以降を要求しますので、v1.16.3のOVAイメージを使用することにします。

標準的な方法でCluster APIでKubernetes環境を作ります。ノードが上がってきたら、各ノードでOVSのカーネルモジュールを入れます。Cluster APIで作られるノードは再構築される可能性があるため、本来ならばCluster APIで使うOVAテンプレートに予めOVSを組み込んでおくべきですが、今回はテストなのでそのステップは省略することにします。各ノードで 以下のコマンド

sudo apt update ; sudo apt -y install openvswitch-switch

を実行して、OVSをインストールします。次にカーネルモジュールが正しく読み込まれたか確認しましょう。

$ lsmod | grep openvswitch
openvswitch           131072  0
nsh                    16384  1 openvswitch
nf_nat_ipv6            16384  1 openvswitch
nf_defrag_ipv6         20480  3 nf_conntrack_ipv6,openvswitch,ip_vs
nf_nat_ipv4            16384  2 openvswitch,iptable_nat
nf_nat                 32768  5 nf_nat_masquerade_ipv4,nf_nat_ipv6,nf_nat_ipv4,xt_nat,openvswitch
nf_conntrack          131072  12 xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_ipv6,nf_conntrack_ipv4,nf_nat,nf_nat_ipv6,ipt_MASQUERADE,nf_nat_ipv4,xt_nat,openvswitch,nf_conntrack_netlink,ip_vs
libcrc32c              16384  4 nf_conntrack,nf_nat,openvswitch,ip_vs

この時点ではKubernetesのノードは以下のような状態になっているはずです。

bash-3.2$ kubectl get nodes
NAME                                       STATUS     ROLES    AGE   VERSION
workload-cluster-1-controlplane-0          NotReady   master   30m   v1.16.3
workload-cluster-1-md-0-78469c8cf9-5r9bv   NotReady   <none>   21m   v1.16.3
workload-cluster-1-md-0-78469c8cf9-tlkn9   NotReady   <none>   21m   v1.16.3

STATUSが “Not Ready” になっていますが、これはCNIプラグインがまだ何もインストールされていないためで、期待された動きです。

Antreaのインストールは非常に簡単です。以下のコマンドを実行するだけで必要なコンポーネントが全てインストールされます。

kubectl apply -f https://raw.githubusercontent.com/vmware-tanzu/antrea/master/build/yamls/antrea.yml

ここではAntreaの最新のものを使うようにしていますが、Antreaの開発のペースは早いので、一時的に最新版ではうまく動作しないケースもあるかもしれません。その場合には、

kubectl apply -f https://github.com/vmware-tanzu/antrea/releases/download/<TAG>/antrea.yml

の部分を適当なものに置き換えてください(現時点で最新のリリース版タグは "v0.2.0" です)。

インストールが無事に終了するとkube-system Namespaceに以下のようなPodができて、全てRunningのSTATUSになっているはずです。

bash-3.2$ kubectl get pods -n kube-system
NAME                                                        READY   STATUS    RESTARTS   AGE
antrea-agent-dvpn2                                          2/2     Running   0          8m50s
antrea-agent-qqhpc                                          2/2     Running   0          8m50s
antrea-agent-tm28v                                          2/2     Running   0          8m50s
antrea-controller-6946cdc7f8-jnbxt                          1/1     Running   0          8m50s
coredns-5644d7b6d9-878x2                                    1/1     Running   0          46m
coredns-5644d7b6d9-pvj2j                                    1/1     Running   0          46m
etcd-workload-cluster-1-controlplane-0                      1/1     Running   0          46m
kube-apiserver-workload-cluster-1-controlplane-0            1/1     Running   0          46m
kube-controller-manager-workload-cluster-1-controlplane-0   1/1     Running   2          46m
kube-proxy-4km5k                                            1/1     Running   0          38m
kube-proxy-cgxcp                                            1/1     Running   0          38m
kube-proxy-h4css                                            1/1     Running   0          46m
kube-scheduler-workload-cluster-1-controlplane-0            1/1     Running   2          46m
vsphere-cloud-controller-manager-gfgbp                      1/1     Running   1          45m
vsphere-csi-controller-0                                    5/5     Running   0          45m
vsphere-csi-node-6mvpt                                      3/3     Running   0          7m4s
vsphere-csi-node-gwr67                                      3/3     Running   0          7m4s
vsphere-csi-node-hb6rk                                      3/3     Running   0          7m4s

DaemonSetも確認してみましょう。

bash-3.2$ kubectl get daemonset -n kube-system
NAME                               DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                     AGE
antrea-agent                       3         3         3       3            3           beta.kubernetes.io/os=linux       9m1s
kube-proxy                         3         3         3       3            3           beta.kubernetes.io/os=linux       47m
vsphere-cloud-controller-manager   1         1         1       1            1           node-role.kubernetes.io/master=   46m
vsphere-csi-node                   3         3         3       3            3           <none>                            46m

antrea-agentがDeamonSetとして実行されているのを確認することができます。

ConfigMapを確認してみましょう。

bash-3.2$ kubectl get configmap -n kube-system
NAME                                 DATA   AGE
antrea-config-tm7bht9mg6             3      10m
coredns                              1      48m
extension-apiserver-authentication   6      48m
kube-proxy                           2      48m
kubeadm-config                       2      48m
kubelet-config-1.16                  1      48m
vsphere-cloud-config                 1      47m
bash-3.2$ kubectl get configmap antrea-config-tm7bht9mg6 -n kube-system -o yaml
apiVersion: v1
data:
  antrea-agent.conf: |
    # Name of the OpenVSwitch bridge antrea-agent will create and use.
    # Make sure it doesn't conflict with your existing OpenVSwitch bridges.
    #ovsBridge: br-int
    # Datapath type to use for the OpenVSwitch bridge created by Antrea. Supported values are:
    # - system
    # - netdev
    # 'system' is the default value and corresponds to the kernel datapath. Use 'netdev' to run
    # OVS in userspace mode. Userspace mode requires the tun device driver to be available.
    #ovsDatapathType: system
    # Name of the interface antrea-agent will create and use for host <--> pod communication.
    # Make sure it doesn't conflict with your existing interfaces.
    #hostGateway: gw0
    # Encapsulation mode for communication between Pods across Nodes, supported values:
    # - vxlan (default)
    # - geneve
    # - gre
    # - stt
    #tunnelType: vxlan
    # Default MTU to use for the host gateway interface and the network interface of each Pod. If
    # omitted, antrea-agent will default this value to 1450 to accomodate for tunnel encapsulate
    # overhead.
    #defaultMTU: 1450
    # Whether or not to enable IPSec encryption of tunnel traffic.
    #enableIPSecTunnel: false
    # CIDR Range for services in cluster. It's required to support egress network policy, should
    # be set to the same value as the one specified by --service-cluster-ip-range for kube-apiserver.
    #serviceCIDR: 10.96.0.0/12
  antrea-cni.conf: |
    {
        "cniVersion":"0.3.0",
        "name": "antrea",
        "type": "antrea",
        "ipam": {
            "type": "host-local"
        }
    }
  antrea-controller.conf: ""
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"antrea-agent.conf":..<snipped>..}}
  creationTimestamp: "2020-01-06T06:57:51Z"
  labels:
    app: antrea
  name: antrea-config-tm7bht9mg6
  namespace: kube-system
  resourceVersion: "4819"
  selfLink: /api/v1/namespaces/kube-system/configmaps/antrea-config-tm7bht9mg6
  uid: e6115864-4179-471d-a382-a1bb4afdeca1

これをみて分かるように、ConfigMapでは、

  • Integration Bridge名(default: br-int)
  • DataPath タイプ(default: system)
  • ホストと通信するインターフェース名(default: gw0)
  • トンネル(Encapsulation)タイプ(default: vxlan)
  • MTU値(default: 1450)

などを設定することができます。

それでは何かDeploymentを作ってみましょう。今回はお手軽にnginxのDeploymentをreplicas=2で作って、port-forwardでPodにアクセスしてみましょう。

bash-3.2$ cat nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
bash-3.2$ kubectl apply -f nginx.yaml
deployment.apps/nginx-deployment created
bash-3.2$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-54f57cf6bf-fx4mz   1/1     Running   0          44s
nginx-deployment-54f57cf6bf-mg74x   1/1     Running   0          44s
bash-3.2$ kubectl port-forward nginx-deployment-54f57cf6bf-fx4mz 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

無事にnginxにアクセスするすることができました。

次にantrea-agentの内部がどう動いているのか見てみましょう。

bash-3.2$ kubectl exec -ti antrea-agent-dvpn2 -n kube-system /bin/bash
Defaulting container name to antrea-agent.
Use 'kubectl describe pod/antrea-agent-dvpn2 -n kube-system' to see all of the containers in this pod.
root@workload-cluster-1-md-0-78469c8cf9-tlkn9:/# ovs-vsctl show
2fa33701-4b83-4016-a070-08fc90921b2d
    Bridge br-int
        Port "coredns--f4e323"
            Interface "coredns--f4e323"
        Port "tun0"
            Interface "tun0"
                type: vxlan
                options: {key=flow, remote_ip=flow}
        Port "nginx-de-70ebff"
            Interface "nginx-de-70ebff"
        Port "vsphere--7be010"
            Interface "vsphere--7be010"
        Port "gw0"
            Interface "gw0"
                type: internal
    ovs_version: "2.11.1"

Pod用のインターフェースが作成されて、Integrationブリッジ(br-int)に接続されている様子が分かると思います。

最後にOctantとの連携を見てみましょう。

AntreaにはOctant用のプラグインが用意されていて、Octant側からAntreaの状況を確認することができるようになっています。AntreaのOctantプラグインはPodとして動かす方法とプロセスとして動かす方法と2つあります。今回はPodとして動かしてみます。

まず、必要なSecretを作ります。

kubectl create secret generic octant-kubeconfig --from-file=/Users/shindom/work/cluster-api/out/workload-cluster-1/kubeconfig -n kube-system

次にbuild/yamls/antrea-octant.ymlを使用したkubeconfigに合わせてファイル名を書き換えます。

# Change admin.conf to the name of kubeconfig file in your set up.
- name: KUBECONFIG
  value: "/kube/kubeconfig"

Antrea用のOctantプラグインはAntreaのレポジトリにソースがあるので自分でビルドすることもできますが、私のDockerhubにビルド済みのものを置いておきましたので、こちらをお使いいただくのが簡単です。build/yamls/antrea-octant.ymlを以下のように書き換えて、

<del>containers:
 - name: antrea-octant
   image: mshindo/octant-antrea-ubuntu:latest
</del>

(アップデート2020/10/25アップデート:  AntreaのDockerhub Repositoryに適切なバージョンのAntrea用Octantプラグインが置かれるようになりましたので、上記の私のイメージは不要になりました。したがって、私のRepositoryからイメージも削除しいています)。

Podとしてデプロイします。

kubectl apply -f build/yamls/antrea-octant.yml

上記のyamlファイルはNodePortを作るようになっていますので、そこに接続するとOctantのUIにアクセスすることができます。

今後の予定

Windowsの対応、No Encapsulationモードの対応、OVSベースのService Load Balancing、RSPAN/IPFIXなどのDay 2 Operation機能への対応などは既に述べた通りですが、他にも

  • IPv6でのPod Network対応
  • DPDKやAF_XDPなどの高速データパス技術への対応

などがロードマップに上がっています。

本当はAntreaが採用しているデータパスのパイプラインについても説明したかったのですが、力尽きたので今回はここまでで(笑)。

Photo by Manuel Sardo on Unsplash