Antrea CNIのFlow ExporterでPod間のフロー情報を可視化する

# Antrea CNIのFlow ExporterでPod間のフロー情報を可視化する

[vExperts Advent Calendar 2020](https://adventar.org/calendars/5343)の12月18日分の投稿です。

## はじめに

Antrea CNIのFlow Exporter機能を利用して、Elastic Stackで構成されるFlowコレクターでPod間のフロー情報を可視化してみます。

- Ubuntu 20.04.1 LTS
- Kubernetes v1.19.4
- Antrea v0.11.1
- Elastic Stack
	- elasticsearch 7.8.0
	- kibana 7.8.0
	- logstash 7.8.0

## AntreaとFlow Exporter

[Antrea](https://antrea.io)はオープンソースのCNI Pluginで、KubernetesでPod間通信を可能にし、Network Policyによる通信制御を可能にします。Antreaは[Open vSwitch(OVS)](https://www.openvswitch.org)を利用しています。

- 参考 : [Antrea – Yet Another CNI Plug-in for Kubernetes](https://blog.shin.do/2020/01/antrea-yet-another-cni-plugin-for-kubernetes/)

Antrea v0.9.0で実装されたFlow Exporter機能はNodeのconntrackを監視し、conntrackが持つフロー情報をIPFIXフローレコードに変換して指定したフローコレクターに送信することが可能です。(IPFIXへの変換は[go-ipfix](https://github.com/vmware/go-ipfix)ライブラリを利用しています。)Flow Exporterの機能はAntrea Agentに実装されており、定期的にconntrackモジュールの状態をポーリングしてIPFIX(Netflow v10)フォーマットでFlowレコードを作成します。

![img](https://antrea.io/docs/master/assets/flow_exporter.svg)

参考 [Network Flow Visibility in Antrea](https://antrea.io/docs/master/network-flow-visibility/)

## Antreaのデプロイ

最新のTanzu Kubernetes GridはCNIとしてAntreaに対応していますが、作成されるKubernetesクラスターはClsuter APIによってAntreaの設定(Configmap)が制御されてしまうため、今回はkubeadmで作成したクラスターを利用しています。

```bash
$ kubectl get node -o wide
NAME     STATUS     ROLES    AGE   VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
master   NotReady   master   2m    v1.19.4   10.44.185.125   <none>        Ubuntu 20.04.1 LTS   5.4.0-56-generic   docker://19.3.14
node1    NotReady   <none>   82s   v1.19.4   10.44.185.126   <none>        Ubuntu 20.04.1 LTS   5.4.0-56-generic   docker://19.3.14
node2    NotReady   <none>   67s   v1.19.4   10.44.185.127   <none>        Ubuntu 20.04.1 LTS   5.4.0-56-generic   docker://19.3.14
```

antrea v0.11.1をデプロイします。

```
$ kubectl apply -f https://github.com/vmware-tanzu/antrea/releases/download/v0.11.1/antrea.yml
```

kube-systemネームスペースでantrea-controller/antrea-agentが起動します。

```bash
$ kubectl get pod -n kube-system
NAME                                READY   STATUS    RESTARTS   AGE
antrea-agent-2vs6n                  2/2     Running   0          81s
antrea-agent-dkf75                  2/2     Running   0          81s
antrea-agent-lfctk                  2/2     Running   0          81s
antrea-controller-db5b84647-vzvm4   1/1     Running   0          81s
coredns-f9fd979d6-7vzgh             1/1     Running   0          13m
coredns-f9fd979d6-dwhdq             1/1     Running   0          13m
etcd-master                         1/1     Running   0          13m
kube-apiserver-master               1/1     Running   0          13m
kube-controller-manager-master      1/1     Running   0          13m
kube-proxy-df8d8                    1/1     Running   0          12m
kube-proxy-kwcfg                    1/1     Running   0          13m
kube-proxy-x7rmx                    1/1     Running   0          13m
kube-scheduler-master               1/1     Running   0          13m
```

CNIが有効になることで、corednsがREADYになりNodeもReady状態になります。

```bash
$ kubectl get node -o wide
NAME     STATUS   ROLES    AGE   VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
master   Ready    master   14m   v1.19.4   10.44.185.125   <none>        Ubuntu 20.04.1 LTS   5.4.0-56-generic   docker://19.3.14
node1    Ready    <none>   14m   v1.19.4   10.44.185.126   <none>        Ubuntu 20.04.1 LTS   5.4.0-56-generic   docker://19.3.14
node2    Ready    <none>   13m   v1.19.4   10.44.185.127   <none>        Ubuntu 20.04.1 LTS   5.4.0-56-generic   docker://19.3.14
```

antrea-controller/antrea-agentの設定はConfigMap(antrea-config-9c7h568bgf)が利用されます。

```bash
$ kubectl get configmap -n kube-system
NAME                                 DATA   AGE
antrea-ca                            1      17m
antrea-config-9c7h568bgf             3      17m
coredns                              1      29m
extension-apiserver-authentication   6      29m
kube-proxy                           2      29m
kubeadm-config                       2      29m
kubelet-config-1.19                  1      29m
```

## Flowコレクターの作成

AntreaのリポジトリにFlowコレクターを構成するための```elk-flow-collector```が提供されています。このマニフェストを利用してelasticsearch/kibana/logstashを作成します。
logstash向けのinput/filter/outputの設定、codecに利用するIPFIXの定義ファイルなどが提供されており、[これら](https://github.com/vmware-tanzu/antrea/tree/master/build/yamls/elk-flow-collector/logstash)のファイルをConfigMaptとしてlogstashコンテナから利用します。

```bash
$ git clone https://github.com/vmware-tanzu/antrea
$ cd antrea/build/yamls
$ kubectl create namespace elk-flow-collector
$ kubectl create configmap logstash-configmap -n elk-flow-collector --from-file=./elk-flow-collector/logstash/
$ kubectl apply -f ./elk-flow-collector/elk-flow-collector.yml -n elk-flow-collector
```

しばらくするとPodがReadyになります。

```bash
$ kubectl get pod -n elk-flow-collector
NAME                        READY   STATUS    RESTARTS   AGE
elasticsearch-0             1/1     Running   0          2m49s
kibana-7ddf7f7c78-vqgxl     1/1     Running   0          2m49s
logstash-6f55bf94f6-kswct   1/1     Running   0          2m49s
```

kibanaは```NodePort```として公開されます。必要に応じて```LoadBalancer```に変更します。

```bash
$ kubectl get svc -n elk-flow-collector
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
elasticsearch   ClusterIP   10.102.54.73     <none>        9200/TCP         3m21s
kibana          NodePort    10.107.159.250   <none>        5601:30007/TCP   3m21s
logstash        ClusterIP   10.104.53.86     <none>        4739/UDP         3m21s
```

elk-flow-collectorで構成されるlogstashは以下のようにInputを設定しおり、上記の通りClusterIP ```10.104.53.86:4739:udp```としてantrea agentからFlowレコードを受信します。

```json
input {
  udp {
    host => "0.0.0.0"
    port => "4739"
    workers => "4"
    queue_size => "2048"
    receive_buffer_bytes => "16777216"
    codec => netflow {
      versions => [10]
      target => "ipfix"
      include_flowset_id => "true"
      cache_ttl => 86400
      ipfix_definitions => "/usr/share/logstash/definitions/ipfix.yml"
    }
    type => "ipfix"
  }
}
```

## Antreaの設定変更

ConfigMapとして構成されている、antrea-agentが起動時に参照する設定ファイル(antrea-agent.conf)を以下のように修正します。

- ```featureGates.FlowExporter```を```true```としてFlowExporter有効化します。
- flowPollIntervalをコメントアウトします。```flowPollInterval: "5s"```
  - flowPollIntervalはFlowExporterがconntrackモジュールからConnection情報を取得する間隔を指定します。
- flowExportFrequencyをコメントアウトします。```flowExportFrequency: 12```
  - FlowレコードをFlow Collectorにエクスポートする頻度としてポーリングサイクルを指定します。
- ```flowCollectorAddr```としてlogstash ServiceがListenしている```10.104.53.86:4739:udp```を指定します。

実際に修正したConfigMapのサンプル : [antrea-configmap.yaml](https://gist.github.com/masanara/ee3f1b233a07651fa010640868f9bbf4)。

各Node上で起動しているantrea-agentを削除して新しいコンフィグで再起動します。

```bash
$ kubectl delete pod -n kube-system `kubectl get pod -n kube-system -l component=antrea-agent -o=jsonpath='{.items[*].metadata.name}'`
```

antrea-agentが再起動してRunningになります。

```bash
$ kubectl get pods -n kube-system -l component=antrea-agent
NAME                 READY   STATUS    RESTARTS   AGE
antrea-agent-fnjbx   2/2     Running   0          41s
antrea-agent-lfhft   2/2     Running   0          35s
antrea-agent-pv2t6   2/2     Running   0          36s
```

## Flowコレクターの確認

antrea-agentがFlowレコードの送信を開始すると、Flowコレクターであるlogstashのログにjson形式のデータが記録され始めます。

```bash
$ kubectl logs -n elk-flow-collector -f logstash-6f55bf94f6-kswct
...

{
          "type" => "ipfix",
         "ipfix" => {
                        "sourcePodName" => "logstash-6f55bf94f6-kswct",
         "egressNetworkPolicyNamespace" => "N/A",
                  "destinationNodeName" => "",
                   "destinationPodName" => "",
                      "octetTotalCount" => 0,
                           "flowset_id" => 256,
               "destinationIPv4Address" => "10.244.2.3",
                       "sourceNodeName" => "node1",
             "ingressNetworkPolicyName" => "N/A",
                              "packets" => 0,
                     "flowStartSeconds" => "2042-07-14T01:04:00.000Z",
                     "packetDeltaCount" => 0,
                       "flowEndSeconds" => "2042-07-14T01:04:00.000Z",
               "reverseOctetDeltaCount" => 0,
                   "protocolIdentifier" => 6,
        "ingressNetworkPolicyNamespace" => "N/A",
                     "packetTotalCount" => 0,
                                "bytes" => 0,
                    "sourceIPv4Address" => "10.244.1.3",
             "destinationTransportPort" => 9200,
                      "octetDeltaCount" => 0,
              "destinationPodNamespace" => "",
              "egressNetworkPolicyName" => "N/A",
                  "sourceTransportPort" => 37872,
              "reversePacketDeltaCount" => 0,
               "destinationClusterIPv4" => "10.102.54.73",
                              "version" => 10,
               "reverseOctetTotalCount" => 0,
           "destinationServicePortName" => "elk-flow-collector/elasticsearch:",
                   "sourcePodNamespace" => "elk-flow-collector",
              "reversePacketTotalCount" => 0
    },
    "@timestamp" => 2020-12-09T09:10:26.000Z,
      "@version" => "1",
          "host" => "10.244.1.1"
}
```

## ダッシュボードの作成

デプロイされたkibanaにアクセスします。elasticsearchがデータを受信できていると以下のように```flow-yyyy-mm-dd```というインデックスが作成され、インデックスパターンを作成することができます。Antreaのリポジトリにある[build/yamls/elk-flow-collector/kibana.ndjson](https://github.com/vmware-tanzu/antrea/blob/master/build/yamls/elk-flow-collector/kibana.ndjson)はIndex Pattern、Visualize、Dashboardが定義されているため、Management > Stack Management > Saved Objects画面でImportを選択してファイルをインポートします。

![Kobito.weFudM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/7fc18cbd-213b-947a-96e6-b4732485be31.png "Kobito.weFudM.png")


上記をインポートすることによりIndex Patternが定義され、以下のダッシュボードが作成されます。

- Antrea: Overview Dashboard
  ![Kobito.TGqaxl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/bf0484e7-dbd0-af0e-c81e-f9280f01a9f6.png "Kobito.TGqaxl.png")
- Antrea: Flow Dashboard
  ![Kobito.busQEg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/c6728009-71cc-13de-34ff-6ca14ed28d8a.png "Kobito.busQEg.png")
- Antrea: Flow Record Dashboard
  ![Kobito.ONwfFS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/6871a21d-8860-3cb1-11f2-2571d8cea3dc.png "Kobito.ONwfFS.png")
- Antrea: Node Thorughput Dashboard
  ![Kobito.1J2gXQ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/31a50c2a-89db-10cd-a887-5522c5bafe12.png "Kobito.1J2gXQ.png")
- Antrea: Network Policy Dashboard
  ![Kobito.6axGvP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/48afa3b8-e497-a935-378f-85631b5c6870.png "Kobito.6axGvP.png")


## まとめ

Antrea CNIのFlowエクスポート機能により生成されるフローレコードをELKスタックを利用して可視化することができました。将来的にはVMwareの[vRealize Network Insight](https://www.vmware.com/jp/products/vrealize-network-insight.html)を利用してNSX-Tや物理デバイスと同じ画面で一元的にフロー情報を確認できるようになるのでしょう。