OpenShift 4.3 でMultus を使って、Pod にNIC を追加してみる

低レイヤーのネットワークエンジアで、SDN周りの技術(OpenFlowやONOS)に関わり、OpenStackも少し味見した経験を持っています。これからはコンテナかなと考えていたので、K8s やOpenShift を試してみようと思い立ちました。コンテナ技術は初心者なので、認識違い等があると思います。間違い等があれば、ご指摘いただければ嬉しいです。

> 環境構築にあたり、Qiitaを始め沢山のネット上の情報を活用しました。今回はそのお礼も込めて、記事してみました。

# 環境作り
k8s でMultus を使って、pod にNIC 追加する検証が終わったので、次はOpenShift で試してみます。
そこで、何も考えず、Redhatさんが公開している[hatenaブログ](https://rheb.hatenablog.com/entry/openshift41-baremetal-upi)を参考にして、ベアメタルでOpenShift環境(4.2)を作ってみました。ベアメタルと言っても、物理サーバが不足しているので、ESXi上に構築、なお、全ゲストOS(今回はCoreOSのみ)にクラスタ用とMultus用のNICを1つずつ持たせただけで、ESXiには特別な設定等々は入れていません（念のため仮想SWを無差別モードにし、フラットなL2セグメントとしました）。
<img width="358" alt="スクリーンショット 2020-05-07 15.08.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/6f340a65-f8be-76b2-247c-97d3e7db1c7a.png">
<img width="316" alt="スクリーンショット 2020-05-07 15.13.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/ae61b4d0-d3a1-929d-830e-b5b7407ee07c.png">
<img width="321" alt="スクリーンショット 2020-05-07 15.09.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/ad2cd1b7-3259-e8c9-fa57-ca6c7b9888a9.png">
<img width="282" alt="スクリーンショット 2020-05-07 15.09.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/fde407dc-f5cb-3de0-2d3e-01260ff3d5f5.png">

> 構成図が抜けていたので、追記しました(2020年5月11日)

## 物理構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/1a0c72f4-14d2-dda2-776f-2ec13113aec0.png)

## 論理構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/1452d0e3-eb45-02c7-3fbb-c38cb000f931.png)


GUIコンソール用のwindows 10やDNS, DHCP, HAProxy を持ったjumpサーバを作り終えた後、boostrap からmaster, worker の順にVMを作っていきます。CoreOSのインストール時の手順は、先のhatenaブログとは少々違っていたので、GUIではなくCLIでパラメータを指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/a3df8898-5ce3-fecd-bfdc-39e88ebddfaa.png)
とても簡単に、master ノードを3台、worker ノードを2台の最小構成で完成。


# Multus を使うために
再度、Redhat さんが公開している[hatenaブログ](https://rheb.hatenablog.com/entry/multus_openshift43_ipi_aws)を参考にして、構築したOpenShift4.2 環境内にMultusを追加。しかし、上手くいかない。。。
Redhatの知人に聞いてみると、Multus は4.3 からサポートとのこと。じゃ、4.3 に上げてみるか！と安易に考え、OpenShift のGUI をいじったり、ググってみると、簡単にupdate できることが判明。しかし、当時(３月頃？) 4.2 からstable-4.3 へのupdate できないようで、fast-4.3 を選択し、無事4.2.26 から4.3.10 にupdate完了。
![名称未設定1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/78e0d3e7-9e9a-06ce-2d8f-f9f0be98116d.png)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100356/c6c67a73-114a-beb6-1023-59deb507c4d7.png" width=50%>

> プロプントはrhel8-jump となっていますが、途中jump-0 に変更しました。

再度、[hatenaブログ](https://rheb.hatenablog.com/entry/multus_openshift43_ipi_aws)を参考にして、macvlanのCNO用とPod用のYAMLを作り、無事Multus が出来上がった。疎通も確認できた。と思ったら、、、

# ある日突然
4.3.13 が出たよとGUI上に通知があり、何も考えず、update、ここから大変。まずGUIにアクセスできない。CLIで確認すると、clusteroperators のconsole がfalse に。
今回は、環境構築感とMultus の動作感を知りたいだけで、プロダクション用ではないので、最新の4.3.13で再構築を試みた。しかし、次は、clusteroperators のauthentication がunknown に。。。。なぜだ。。。。始めは証明書問題かと思ったが、切り分けできず。

何度も環境を作り直したけど、完成出来るときもあれば、出来ないときもある。あと、単純にopenshift-installer を持ってきて、ign ファイルを作ってもだめで、利用したいバージョンのインストーラーを使用せよのこと(Redhat の知人情報)。

頭を冷やすために、ちょっと時間をあけることに。そこで、気づいたのが、HAproxy とdnsmasq の設定と状態。確認できたのは、
1. dnsmasq でIPアドレスを配っていないと、HAproxy は当該のホストがないためfailし、プロセスが立ち上がらない。具体的には、/var/lib/dnsmasq/dnsmasq.leases にホストが登録されていないと、ダメっぽい
2. OpenShift4.2 からmaster ノードもworker ノードにスケジュールされるため、HAproxy 設定内のbackend httpとhttps にmaster ノードを追加する必要がある
知っている人には当たり前のことかもしれないけど、dnsmasq を初めて使うし、HAproxy は慣れていないので、結構戸惑った。HAproxy の設定ファイルの抜粋は

```
(抜粋)
backend http-80
    mode tcp
    balance     roundrobin
    server  master-0 master-0.test.example.local:80 check
    server  master-1 master-1.test.example.local:80 check
    server  master-2 master-2.test.example.local:80 check
    server  worker-0 worker-0.test.example.local:80 check
    server  worker-1 worker-1.test.example.local:80 check

backend https-443
    mode tcp
    balance     roundrobin
    option      ssl-hello-chk
    server  master-0 master-0.test.example.local:443 check
    server  master-1 master-1.test.example.local:443 check
    server  master-2 master-2.test.example.local:443 check
    server  worker-0 worker-0.test.example.local:443 check
    server  worker-1 worker-1.test.example.local:443 check
```

HAproxy とdnsmasq を適切に設定し、無事OpenShift4.3.10 環境が出来上がりました。ひよって最新の4.3.13 にしていません。。。
> その他、hosts をいじると、dnsmasq プロセスを再起動。当たり前と言えば、当たり前ですが。。。

# Multusの追加、アゲイン
ようやく環境できたので、Multus を入れてみる。しかし、先に成功していたCNO の設定が通らない。openshift-network-operator でエラー。
## openshift-network-operator のエラー

```
[root@jump-0 openshift]# oc -n openshift-network-operator logs -f network-operator-xxxxx
(snip)
2020/04/** 01:53:51 httpProxy, httpsProxy and noProxy not defined for proxy 'cluster'; validation will be skipped
2020/04/** 01:53:51 Starting render phase
E0507 01:53:51.040613       1 runtime.go:78] Observed a panic: "invalid memory address or nil pointer dereference" (runtime error: invalid memory address or nil pointer dereference)
```


## CNOの見直し
色々試してみる。まずはCNOを見直し。公開されているOpenshiftのマニュアルを見る、でもよく理解できない。。。
- https://docs.openshift.com/container-platform/4.3/networking/multiple_networks/configuring-macvlan.html
- https://docs.openshift.com/container-platform/4.3/networking/multiple_networks/attaching-pod.html#attaching-pod
この2つのページを参照して作成したCNO設定を、「oc edit networks.operator.openshift.io cluster」 で追記。

```
spec:
  additionalNetworks:
  - name: network-macvlan
    type: Raw
    rawCNIConfig: '{
      "cniVersion": "0.3.1",
      "type": "macvlan",
      "capabilities": {"ips": true},
      "master": "ens224",
      "ipam": {
        "type": "static"
      }
    }'
```

エラーは出ず、CNOも確認できたので、Pod 作成に取りかかる。

```
[root@jump-0 openshift]# oc get network-attachment-definitions
NAME              AGE
network-macvlan   164m
[root@jump-0 openshift]#
```

## Pod用のYAML

```
apiVersion: v1
kind: Pod
metadata:
  name: macvlan-1
  labels:
    app: multus-macvlan
  annotations:
    k8s.v1.cni.cncf.io/networks: '[
    {
      "name": "network-macvlan",
      "ips": [ "10.0.201.29/24" ]
    }
    ]'
spec:
  containers:
  - name: centos-tools
    image: docker.io/centos/tools:latest
    command:
    - /sbin/init
    securityContext:
      privileged: true
  nodeSelector:
    kubernetes.io/hostname: worker-0
```


## PodにNICを追加できた

```
[root@jump-0 openshift]# oc get pod/macvlan-1 -oyaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    k8s.v1.cni.cncf.io/networks: '[ { "name": "network-macvlan", "ips": [ "10.0.201.29/24"
      ] } ]'
    k8s.v1.cni.cncf.io/networks-status: |-
      [{
          "name": "openshift-sdn",
          "interface": "eth0",
          "ips": [
              "10.128.2.16"
          ],
          "dns": {},
          "default-route": [
              "10.128.2.1"
          ]
      },{
          "name": "network-macvlan",
          "interface": "net1",
          "ips": [
              "10.0.201.29"
          ],
          "mac": "6a:1b:1b:a1:15:ef",
          "dns": {}
      }]
(snip)
```

## Podを2つ作成→状態を確認→疎通もOK

Multusで使うIPアドレスを変えて、同じようなyaml ファイルを作成後、create。その後、状態確認し、疎通も確認

```
[root@jump-0 openshift]# oc rsh macvlan-1 ip -d a s dev net1
4: net1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 6a:1b:1b:a1:15:ef brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0
    macvlan mode bridge numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.0.201.29/24 brd 10.0.201.255 scope global net1
       valid_lft forever preferred_lft forever
    inet6 fe80::681b:1bff:fea1:15ef/64 scope link
       valid_lft forever preferred_lft forever
[root@jump-0 openshift]#
[root@jump-0 openshift]# oc rsh macvlan-2 ip -d a s dev net1
4: net1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:ed:f7:26:87:7b brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0
    macvlan mode bridge numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.0.201.30/24 brd 10.0.201.255 scope global net1
       valid_lft forever preferred_lft forever
    inet6 fe80::ed:f7ff:fe26:877b/64 scope link
       valid_lft forever preferred_lft forever

[root@jump-0 openshift]#
[root@jump-0 openshift]# oc rsh macvlan-1 ping -c 3 10.0.201.30
PING 10.0.201.30 (10.0.201.30) 56(84) bytes of data.
64 bytes from 10.0.201.30: icmp_seq=1 ttl=64 time=0.175 ms
64 bytes from 10.0.201.30: icmp_seq=2 ttl=64 time=0.205 ms
64 bytes from 10.0.201.30: icmp_seq=3 ttl=64 time=0.341 ms

--- 10.0.201.30 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2046ms
rtt min/avg/max/mdev = 0.175/0.240/0.341/0.073 ms
[root@jump-0 openshift]#
[root@jump-0 openshift]# oc rsh macvlan-2 ping -c 3 10.0.201.29
PING 10.0.201.29 (10.0.201.29) 56(84) bytes of data.
64 bytes from 10.0.201.29: icmp_seq=1 ttl=64 time=0.231 ms
64 bytes from 10.0.201.29: icmp_seq=2 ttl=64 time=0.237 ms
64 bytes from 10.0.201.29: icmp_seq=3 ttl=64 time=0.215 ms

--- 10.0.201.29 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2087ms
rtt min/avg/max/mdev = 0.215/0.227/0.237/0.019 ms
[root@jump-0 openshift]#

```

# 結果
本来の目的を達成しようと、試したい技術を評価してみるものの、その技術の周辺で問題が発生し、想定通りに動作しない状況を過去何度か経験してきました。個人的にはインフラあるあるとしていますが、今回も正しく発動しました。まだまだスキルが不足し、視野が狭いと実感したここ1ヶ月でした。これからも腕を磨き、視野を広げる活動を続けていこうと思います。

# （追伸） 可用性が高いK8s 環境
etcdをmaster ノードから切り離し、3台のetcd と2台のHAproxy を使って、可用性を高めた構成を2020年の初めに作りました。この環境に、Juniper vMX とCalico を使って、外部からの接続をBGPで負荷分散する機能も追加済み。機会があれば、記事にしようかと思います。