Contrail CNIとKubernates連携を触ってみる方法:Juniper vLabs

#概要

Kubernetes(以下k8s)の[CNI(Container Network Interface)としてTungsten Fabric(OSS)/Contrail(Juniper社)](https://kubernetes.io/ja/docs/concepts/cluster-administration/networking/#contrail-tungsten-fabric)というものがある。

前回、[AWS上でTungesten FabricとKubernetesを簡単に触る方法](https://qiita.com/hiromiarts/items/1e4ef4c52775ae52f34c)を記載したが、Juniper社がvLABsという無償リモートラボでContrailとk8sを触る環境が用意されているため、そちらを使って、PODを作成してSerivice Load Balancerを利用して外部公開する、基本的なオペレーションを行なう方法を記載する。


1.Juniper vLabsアクセス方法とシナリオ概要
2.初期状態確認
3.サンプルシナリオ – アプリケーションデプロイとLoadBalancer外部接続
 　3-1.POD作成
 　3-2.Service  type LoadBalancer作成
 　3-3.状態確認
4.参考資料
 
#1.Juniper vLabsアクセス方法とContrail & k8s シナリオ概要

vLABサイト 
https://jlabs.juniper.net/vlabs/
 
vLABの利用方法は[こちら](https://qiita.com/lca367/items/99828465d757fb3c913f)も参照

アカウント作成後は、[vLab Sandbox: Contrail Enterprise Multicloud with Kubernetes](https://jlabs.juniper.net/vlabs/portal/contrail-enterprise-multicloud-kubernetes/)
の[Scenario Activity Guide](https://jlabs.juniper.net/vlabs/portal/contrail-enterprise-multicloud-kubernetes/contrail-enterprise-multicloud-kubernetes-using-the-sandbox.page)で用意されている手順が確認できる。

BLUEPRINT: 
[vLAB Official Demo] CEM and Kubernetes 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/5a58d4ff-f773-6205-39f7-bd304381f017.png)
•	Contrail version R1910
•	Kubernetes 1.12
※本ページは上記のバージョンを利用

RESERVEをクリック 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/51f6a25d-6b05-5dff-83e2-d8ecc377963b.png)
 
RESERVEをクリック 
※約10minほどで環境構築完了 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/1f5eabb4-4963-2b0d-29fc-4d2c5443a60c.png)

※vLABでの予約はデフォルトでは3時間の利用。最大6時間。再利用は再度予約する必要がある。
 
**ダイレクトアクセス方法**
COMMANDS->"Add Allowed Network Prefixes"にて自身のGlobalIPを入力し、RUN 。
※これは、パブリックのvLABに接続するアドレスとなる。例として、[こちら](https://www.cman.jp/network/support/go_access.cgi)のサイトで外部接続のアドレスが確認可能。
※設定後、踏み台を経由せず、直接vLABの環境にアクセス可能となる。 
※Add Allowed Network Prefixeを追加すると、各デバイスへのアクセス方法が記載されたメールが通知される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/fcdc3509-76e5-095b-7f5f-6e27e2a9687f.png)
 
 
**通知されたアクセス先にログインできるか確認**
 
[Contrail Command] Private Portが9091のもの 
https://66.129.235.3:40004/ 
※メールで通知されるアドレスとポート番号にアクセス
UserName: admin 
Password: contrail123 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/3a9f3740-88f0-db36-ea77-d4eacabe161a.png)
 ※ログインに時間を要す場合は、クッキーを削除。


[Tungsten Fabric Controller]
https://66.129.235.12:40010/
※メールで通知されるアドレスとポート番号にアクセス。
※Tungesten Fabric GUIはOSSのGUI。こちらをオペレーションすることも可能だが、今回はContrail Command GUIを主に利用する。
UserName: admin 
Password: contrail123 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/b80116aa-9f59-196f-4381-9e3a263e2a85.png)
 
[K8S Master] 
※メールで通知されるアドレスとポート番号にアクセス。

```
$ ssh root@66.129.235.3 -p 40022 
 root@66.129.235.3's password: Juniper!1 
[root@k8smaster ~]# 
```

[K8S Node] 
※メールで通知されるアドレスとポート番号にアクセス。

```
$ ssh root@66.129.235.3 -p 40027
 root@66.129.235.3's password: Juniper!1 
[root@k8snode1 ~]# 
```
 
[vMX] 
※メールで通知されるアドレスとポート番号にアクセス。

```
$ ssh root@66.129.235.3 -p 40041 
Password: Juniper!1 
--- JUNOS 18.3R1.9 Kernel 64-bit  JNPR-11.0-20180816.8630ec5_buil 
root@vMX1-GW:~ # cli 
root@vMX1-GW> 
```
 
**Topology**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/74d6708e-8a4b-2c42-9f38-7db915f1c42f.png)
  
**アーキテクチャ概要**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/39c5f5eb-388c-dd70-8df0-08c085006c05.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/fd1c58dc-cb6d-be97-e5c6-c96117cf77f1.png)
 
※k8s masterのAPI ServerがContrail Controllerのcontrail-kube-managerにrequest
※各kubernates(以下k8s) NodesにはContrail vRouterが存在し、ネットワーク分割(VRF: Virtual Routing and Forwarding)、セキュリティー・ポリシー、パケットフォワーディング、SNAT等を実施
※k8sNodes間は、オーバーレイ接続 
※vRouterとContrail Controllerはxmppにより情報交換
※vMXは外部接続するゲートウェイ
※設定変更によりgateweyless modeとして直接vRouterからアンダーレイ経由での接続も可能
※vMXとContrail ControllerはBGPにより経路交換
k8sとContrailの概要については、[こちら](https://www.juniper.net/documentation/ja/day-one-books/topics/topic-map/kubernetes-and-contrail-integration.html)も参照

#2.初期状態確認 

Contrail CommandにLoginし、全てのコンポーネントのステータスがグリーンになっていることを確認 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/978a343a-6e02-b40c-a7c1-d055d21b1b3c.png)
 
 
Infrastructure -> ServersにてContrail Controller 1台、K8S Master 1台、K8S Node 2台がデプロイされていることを確認 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/91995347-e6dc-a0f1-1e52-88b610f19a15.png)
 
 
Overlay -> Networksにてk8S-default(GUIの右上にてプロジェクト選択可能)のVirtual Networkが3つ作成済みなことを確認 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/81682a62-5c56-ba8e-3740-3769eb217548.png)
 

 
※k8s-default-pod-network: デフォルトで用意されているPOD用のネットワーク。k8s-pod-ipam(10.32.0.0/12)のIPAMがマッピンされている。
※k8s-default-service-network:デフォルトで用意されているService用のネットワーク。k8s-service-ipam(10.96.0.0/12)のIPAMがマッピンされている。
※External-net: 外部接続用のネットワーク。シナリオ用に事前設定されている状態。”Edit” にてCIDR(ネットワークサブネット10.40.0.0/24)、Floating  Pool Name “External”、Route Targetが設定してあることが確認可能。
*デフォルトで用意されるk8s-default-service-network、k8s-default-pod-networkの説明は[こちら](https://www.juniper.net/documentation/ja/day-one-books/topics/topic-map/kubernetes-and-contrail-integration.html)

Overlay -> IP Address ManagementにてIPAMでそれぞれに払い出すサブネットを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/dd9facad-4724-a6da-d162-e5739eed3f12.png)
 



Overlay -> Floating IPsの初期状態を確認
※10.96.0.1はk8s内部で利用するapiserverのcluster IPとなる。
※# kubectl exec pod-name -- env のKUBERNETES_SERVICE_HOST 環境変数でも確認可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/1944fc1d-5a6e-3ee5-ebf8-b29f5b3dab94.png)

Floating IP Poolsとして仮想ネットワークのExternal-netで指定したExternalが定義されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/75167743-4b9f-76ab-47e7-91474e13df81.png)
 


k8s masterノードにてk8sノード起動、Pod, Serviceの状態を確認

```
[root@k8smaster ~]# kubectl get nodes
NAME        STATUS   ROLES    AGE    VERSION
k8smaster   Ready    master   214d   v1.12.9
k8snode1    Ready    <none>   214d   v1.12.9
k8snode2    Ready    <none>   214d   v1.12.9

root@k8smaster ~]# kubectl get pods 
No resources found. 
 
[root@k8smaster ~]# kubectl get services 
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE 
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   178d 
```



k8s nodesノードにてContrail vRouterの起動状態を確認

```
[root@k8snode1 ~]# contrail-status
Pod      Service   Original Name           State    Id            Status
         rsyslogd                          running  06e2bdaaaad1  Up 5 hours
vrouter  agent     contrail-vrouter-agent  running  b15d1cc7db1b  Up 5 hours
vrouter  nodemgr   contrail-nodemgr        running  39ec47b78802  Up 5 hours

WARNING: container with original name '' have Pod or Service empty. Pod: '' / Service: 'rsyslogd'. Please pass NODE_TYPE with pod name to container's env

vrouter kernel module is PRESENT
== Contrail vrouter ==
nodemgr: active
agent: active
```


Infrastructure-> Cluster->Advanced->BGP Routersにて
vMXに対するBGP設定があることを確認 [設定方法](https://www.juniper.net/documentation/en_US/contrail19/topics/topic-map/config-control-node-with-bgp.html)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/97d35316-b157-891d-734e-29fe2faea66e.png)
 


vMXにてContrail ControllerとBGP Peeringできていることを確認 
※vMXは外部接続ゲートウェイとして動作し、Contrail ControllerとBGPにて経路交換

```
root@vMX1-GW> show bgp summary 
Groups: 1 Peers: 1 Down peers: 0 
Table          Tot Paths  Act Paths Suppressed    History Damp State    Pending 
bgp.rtarget.0 
                       8          8          0          0          0          0 
inet.0 
                       0          0          0          0          0          0 
bgp.l3vpn.0 
                       0          0          0          0          0          0 
bgp.evpn.0 
                       0          0          0          0          0          0 
Peer                     AS      InPkt     OutPkt    OutQ   Flaps Last Up/Dwn State|#Active/Received/Accepted/Damped... 
100.123.18.2          64512       2594       2883       0       0    21:33:04 Establ 
  bgp.rtarget.0: 8/8/8/0 
  bgp.l3vpn.0: 0/0/0/0 
  bgp.evpn.0: 0/0/0/0 
```

 vMXにて保持している経路情報を確認
k8sクラスタ関連のアドレス(10.x.x.x)を保持していないことを確認
※’contrail’という名前のipv4 table(inet.0)を確認 

```
root@vMX1-GW> show route table contrail.inet.0

contrail.inet.0: 3 destinations, 3 routes (3 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

0.0.0.0/0          *[Static/5] 1d 23:29:43
                    > to 172.16.0.1 via lt-0/0/10.1
172.16.0.0/24      *[Direct/0] 1d 23:29:43
                    > via lt-0/0/10.1
172.16.0.100/32    *[Local/0] 1d 23:29:43
                      Local via lt-0/0/10.1
```
 
#3.サンプルシナリオ – アプリケーションデプロイとLoadBalancer外部接続
NGINX PODを2つ作成、LBを経由し外部アクセス  (vLAB英語版記載シナリオ)

3-1.	POD作成(deployment)
3-2.	Service type LoadBalancer作成 
3-3.	状態確認 (外部クライアントからの接続、Contrail Command GUI)

シナリオ確認用に事前に各アプリケーション起動用のマニフェストファイルが用意されていることを確認

```
[root@k8smaster ~]#  cd examples/lab1/
[root@k8smaster lab1]# ls
deployment.yaml  pod1.yaml  pod3.yaml       pod-red.yaml       pol-front-back.yaml
namespace.yaml   pod2.yaml  pod-green.yaml  pol-deny-all.yaml  service.yaml
```

####3-1.  POD作成(deployment)
※k8s PODとは、workloadの最小単位となり、1つ以上のコンテナから構成。POD内は同じIPアドレスが割り当てられる。
※Contrailでは、Virtual Machineとして扱う。
※k8s Deploymentとは、ReplicationSetを管理し、ローリングアップデートやロールバックなどを実現するリソース。

nginxのアプリケーションをデプロイするマニフェストファイルで起動

```
[root@k8smaster ~]# cat examples/lab1/deployment.yaml 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: my-nginx 
spec: 
  selector: 
    matchLabels: 
      run: my-nginx 
  replicas: 2 
  template: 
    metadata: 
      labels: 
        run: my-nginx 
    spec: 
      containers: 
      - name: my-nginx 
        image: nginx 
        ports: 
        - containerPort: 80 
 
[root@k8smaster ~]# kubectl apply -f examples/lab1/deployment.yaml 
deployment.apps/my-nginx created 
```
 
作成されたPodを確認(マニフェストでreplicas:2と指定されているため、nginx Podが2つ作成) 。各PODのアドレスを確認すると、k8s-pod-ipam(10.32.0.0/12)から割り当てられているのがわかる。

```
[root@k8smaster ~]# kubectl get pods 
NAME                        READY   STATUS    RESTARTS   AGE 
my-nginx-756f645cd7-242pp   1/1     Running   0          36s 
my-nginx-756f645cd7-th7cw   1/1     Running   0          36s

[[root@k8smaster lab1]# kubectl get pods --output=wide
my-nginx-756f645cd7-76djb   1/1     Running   0   64s   10.47.255.252   k8snode2   <none>
my-nginx-756f645cd7-x4j5t   1/1     Running   0   64s   10.47.255.248   k8snode1   <none>
```

####3-2. Service type LoadBalancer作成
外部からDeployしたPodにアクセスするためにService(LoadBalancer)のファイルを確認し展開。

※k8s Serviceリソースとは、L4ロードバランシングを提供し、受信したトラフィックを複数のPODに負荷分散する。ClusterIP(クラスタ内部で利用する仮想IP), LoadBalancer(外部接続仮想IP)等の複数のtypeが存在する。
※ContrailではServiceは、ECMP Loadbalanderとして提供する。
※k8s LoadBalancer Serviceとは、クラスタ外の外部疎通性のある仮想IPを払い出す
※外部接続 -> Service -> POD接続となる。


```
[root@k8smaster ~]# cat examples/lab1/service.yaml 
apiVersion: v1 
kind: Service 
metadata: 
  name: my-nginx 
  labels: 
    run: my-nginx 
spec: 
  ports: 
  - port: 80 
    protocol: TCP 
  selector: 
    run: my-nginx 
  type: LoadBalancer 
  
[root@k8smaster ~]# kubectl apply -f examples/lab1/service.yaml 
service/my-nginx created 
```
※上記サンプルは”run=my-ngin”のラベルのPODに対してトラフィックを転送
 
Serviceが作成できているか確認 

*外部アクセス用のFloatingIP(10.40.0.3 – 外部ネットワークのExternal:10.40.0.0/24)がアサイン
*クラスタ内部用のCluster IP(10.96.21.23 – Service用のネットワーク:10.96.0.0/12 )がアサイン
*my-nginxのLoadBalancerのエンドポイントとして各POD(10.47.255.249:80,  10.47.255.252:80)

```
[root@k8smaster lab1]# kubectl get services
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1     <none>        443/TCP        214d
my-nginx     LoadBalancer   10.96.21.23   10.40.0.3     80:30640/TCP   5s

[root@k8smaster lab1]# kubectl get endpoints
NAME         ENDPOINTS                           AGE
kubernetes   10.1.0.67:6443                      214d
my-nginx     10.47.255.248:80,  10.47.255.252:80   22s
```

**補足. 外部接続アドレス:Floating IP**
k8sでは、外部接続をする場合、ServiceリソースとしてL4ロードバランシングや、IngressリソースとしてL7ロードバランシングを利用することで外部接続を行なう。
Contrailの場合は、フローティングIP、Fabric SNAT(アンダー接続)、Logical Routerなど様々な方法で外部接続することが可能。今回は、典型的な方法としてフローティングIPとして外部接続用のアドレスを用意し、クラスタの外部接続を行なう。
フローティングIPを利用することで、外部アドレスと内部アドレスの紐付けを行うことができ、外部からの接続も可能となる。
Contrail k8s環境の場合、Serviceリソース、Ingressリソースに加えて、フローティングIPを利用することで柔軟な接続が可能となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/f1d908bd-1607-0229-503d-4369071dba02.png)

 
図.Floating IPワークフロー概要

vMXにLoginし、10.40.0.3がBGPでContrail Controllerから広報されていることを確認。

```
root@vMX1-GW> show route table contrail.inet.0 
  
contrail.inet.0: 4 destinations, 5 routes (4 active, 0 holddown, 0 hidden) 
+ = Active Route, - = Last Active, * = Both 
  
0.0.0.0/0            *[Static/5] 22:03:36 
                               > to 172.16.0.1 via lt-0/0/10.1 
10.40.0.3/32       *[BGP/170] 00:02:48, MED 100, localpref 200, from 100.123.18.2 
                               AS path: ?, validation-state: unverified 
                               > via gr-0/0/10.32771, Push 32 
                               [BGP/170] 00:02:48, MED 100, localpref 200, from 100.123.18.2 
                               AS path: ?, validation-state: unverified 
                                > via gr-0/0/10.32770, Push 32 
172.16.0.0/24      *[Direct/0] 22:03:36 
                                > via lt-0/0/10.1 
172.16.0.100/32    *[Local/0] 22:03:36 
                                Local via lt-0/0/10.1  
```

10.40.0.3経路は2つのオーバーレイのECMPとなり、protocol next-hopとして各k8s nodesがとなっている。

```
root@vMX1-GW> show route table contrail.inet.0 10.40.0.3 detail

contrail.inet.0: 4 destinations, 5 routes (4 active, 0 holddown, 0 hidden)
10.40.0.3/32 (2 entries, 1 announced)
        *BGP    Preference: 170/-201
                Route Distinguisher: 10.1.0.66:3
                Next hop type: Indirect, Next hop index: 0
                Address: 0xce329b0
                Next-hop reference count: 3
                Source: 100.123.18.2
                Next hop type: Router, Next hop index: 631
                Next hop: via gr-0/0/10.32771, selected
                Label operation: Push 39
                Label TTL action: prop-ttl
                Load balance label: Label 39: None;
                Label element ptr: 0xce31f80
                Label parent element ptr: 0x0
                Label element references: 1
                Label element child references: 0
                Label element lsp id: 0
                Session Id: 0x1f9
                Protocol next hop: 10.1.0.66
                Label operation: Push 39
                Label TTL action: prop-ttl
　　　 ---   省略    ---

         BGP    Preference: 170/-201
                Route Distinguisher: 10.1.0.194:4
                Next hop type: Indirect, Next hop index: 0
                Address: 0xce32710
                Next-hop reference count: 2
                Source: 100.123.18.2
                Next hop type: Router, Next hop index: 0
                Next hop: via gr-0/0/10.32770, selected
                Label operation: Push 32
                Label TTL action: prop-ttl
                Load balance label: Label 32: None;
                Label element ptr: 0xce32760
                Label parent element ptr: 0x0
                Label element references: 1
                Label element child references: 0
                Label element lsp id: 0
                Session Id: 0x0
                Protocol next hop: 10.1.0.194
                Label operation: Push 32
                Label TTL action: prop-ttl
　　　 ---   省略    ---
```

####3-3.  状態確認 (外部クライアントからの接続、Contrail Command GUI)

Cluster外部のクライアント (JumpHost)にLoginし、podにアクセスできるか確認。 
※メールで通知されるアドレスとポート番号にアクセス。
※PODで起動しているnginxにcurlでアクセス。

```
[root@csg ~]# curl 10.40.0.3 
<!DOCTYPE html> 
<html> 
<head> 
<title>Welcome to nginx!</title> 
<style> 
--snip-- 
<p><em>Thank you for using nginx.</em></p> 
</body> 
</html> 
```
 
Contrail Command確認(Pod、FIP 、Service)
Overlay -> VirtualNetworksにて、k8s-default-pod-networkのVNにPodが２つ接続されていることがわかる。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/084e5e8f-acb7-3e0d-99ab-01417bde144e.png)
 
Contrail CommandでもExternalのPoolからFloating IP(10.40.0.3)が割り当てられたのがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/94fcc320-ae94-cc6b-724f-01a79b1f3980.png)

Services -> LoadBalancersにて、default__my-nginxというLoadBalancerが作成されており、FloatingIP(10.40.0.3)がアサインされている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/321b7198-baf2-e355-5561-4315f49217de.png)
※default_my-nginxをクリックするlister portやPool Membersを確認可能。
※ ただし、vLab環境の場合、Pool MembersのMonitorは動作負荷。

OVERLAY -> Virtual Portsでも各Floating IPとFixes IPのマッピングが確認可能。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138304/d26658f8-5c93-d2d4-0256-6b5e5274fee7.png)
 
今後、[namespaceの分割](https://qiita.com/hiromiarts/items/26137b8500fd9de6442c)、ingress、Network Policy、Contrail Security、Service Chaining(cSRX)などのシナリオの基本オペレーションも記載予定。

#4.参考ドキュメント
[DAY ONE: BUILDING CONTAINERS WITH KUBERNETES AND CONTRAIL](https://www.juniper.net/documentation/en_US/day-one-books/day-one-containers-kubernetes-contrail.pdf)
[DAY ONE : KubernetesとContrailを使用したコンテナの構築](https://www.juniper.net/documentation/ja/day-one-books/information-products/pathway-pages/day-one-building-containers-using-kubernetes-and-contrail.html) (DAY ONEの日本語翻訳)
[Contrail Networking Architecture Guide]
(https://www.juniper.net/documentation/en_US/release-independent/solutions/information-products/pathway-pages/sg-010-contrail-networking-arch-guide.pdf)
[contrail-controller/wiki/Kubernetes](https://github.com/Juniper/contrail-controller/wiki/Kubernetes)
[Single click installation of RedHat OpenShift with Contrail SDN (on AWS)]
(https://github.com/Juniper/openshift-ansible/wiki/Single-click-installation-of-RedHat-OpenShift-with-Contrail-SDN-(on-AWS))
https://github.com/Juniper/contrail-controller/tree/master/src/container/cni
https://github.com/Juniper/contrail-controller/tree/master/src/container/kube-manager
[Contrail Networking Installation and Upgrade Guide](https://www.juniper.net/documentation/en_US/contrail19/information-products/pathway-pages/contrail-install-and-upgrade-guide.html)



以上