[Oracle Cloud] ComputeのセカンダリIPのフェールオーバを試してみる

#モチベーション
[OCHaCafe Premium#1：Oracle Cloudで考える高可用性アーキテクチャ](https://ochacafe.connpass.com/event/152768/)で、セカンダリIPをフェールオーバのデモを見て、やってみたくなった

# 結果
IPフェールオーバできた！ 

当初、複数VNICとセカンダリIPをごっちゃにしていたのと、セカンダリIPを作成するoci cliコマンドがなかなかみつからなかったので少々時間かかった。

# 試したこと
インスタンスを2つ作ってセカンダリIPを設定。oci cliを使って、セカンダリIPをフェールオーバする

![vnic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456818/f3e30146-93ae-f72e-afc2-b884bc658c5e.png)


## 1. 同じサブネットに属するComputeインスタンスを2つ作る

## 2.ociユーザのホームディレクトリにoci cliコマンドをインストール

## 3.動的グループの作成
instance#1とinstance#2が所属する動的グループを作成する
以下のルールを設定して試した

```
Any{instance.id='ocid1.instance.oc1.ap-tokyo-1.xxxxxxxxxxxxxxxxxxxxxxxxxx',instance.id='ocid1.instance.oc1.ap-tokyo-1.xxxxxxxxxxxxxxxxxxxxxxxxxx'}
```

## 4.ポリシーの作成
特定コンパートメント内でprivate-ipのmanageと、インスタンス・VCNへのuse権限を付与する
動的グループに対して、以下のポリシーを設定して試した

```
allow dynamic-group <動的グループ名> to manage private-ip in compartment <コンパートメント名>
allow dynamic-group <動的グループ名> to use virtual-network-family in compartment <コンパートメント名>
allow dynamic-group <動的グループ名> to use instance-family in compartment <コンパートメント名>

```

## 5.private-ipを設定するスクリプトを作成
両方のノードに、以下のスクリプトを作成して試した。
private-ipを作成/移動しただけでは、OSレベルでIPが設定されないため、別途ipコマンドで設定してあげる必要がある

```
#!/bin/bash


HOST1=instance1 # instance#1のホスト名
HOST2=instance2 # instnace#2のホスト名
VIP_ADDR=172.16.2.10 # セカンダリIP
VIP_NETMASK=24       # セカンダリIPのネットマスク
DEVNAME=ens3:0       # セカンダリIPのインタフェース名

case $(hostname -s) in
    "${HOST1}")
        # instance#1のVNIC OCID
        VNIC_OCID=ocid1.vnic.oc1.ap-tokyo-1.xxxxxxxxxxxxxxxxxxxxxxx
        ;;
    "${HOST2}")
        # instance#2のVNIC OCID
        VNIC_OCID=ocid1.vnic.oc1.ap-tokyo-1.xxxxxxxxxxxxxxxxxxxxxxx
        ;;
esac

oci --auth instance_principal network vnic assign-private-ip \
    --vnic-id ${VNIC_OCID}\
    --ip-address ${VIP_ADDR}\
    --unassign-if-already-assigned

if [[ ${?} -ne 0 ]]; then
    echo "oci cli command Error"
    exit 1
fi

sudo ip addr add ${VIP_ADDR}/${VIP_NETMASK} dev ${DEVNAME} label ${DEVNAME}
if [[ ${?} -ne 0 ]]; then
    echo "ip command Error"
    exit 1
fi

exit 0
```

## 6.別のホストから付与したprivate ipあてにsshしてホスト名を取得する
※SSHのパススルー認証を設定済み
※hostキーが入れ替わって、ssh接続時にWARNINGがでるため、StrictHostKeyCheckingをnoにし、標準エラーをnullにすててる

```
$ VIP=172.16.2.10 # セカンダリIPを指定
$ while true
  do
  echo -n "$(date '+%Y/%m/%d %H:%M:%S') : "
  ssh -o StrictHostKeyChecking=no -o UpdateHostKeys=yes ${VIP} hostname -s 2>/dev/null
  sleep 1
  done
```

## 7.作成したスクリプトを実行して、プライベートIPを移動させる。

```
2019/12/04 01:51:36 : instance1
2019/12/04 01:51:37 : instance1
2019/12/04 01:51:38 : instance1
2019/12/04 01:51:40 : instance1
★ ここで切り替わる
2019/12/04 01:51:41 : instance2
2019/12/04 01:51:43 : instance2
2019/12/04 01:51:44 : instance2
```

スクリプトを実行すると、private ipはF/Oするが、OSレベルでF/O元にIP設定は残っている。それでも問題なく通信できるのは、仮想ネットワークの制御側でPrivate IPとMACアドレスの対応を切り替えてくれてるからかな。。

→ arpキャッシュとtcpdumpを取ってると、arpキャッシュエントリは変わらず。echo requestの宛先MACとecho replyの送信元MACが異なっているパターンが見られるので、仮想ネットワーク制御側でMACフレームを書き換えているのかもしれない

```
tcpdump

09:00:39.473785 02:00:17:00:75:07 > 02:00:17:00:5e:18, ethertype IPv4 (0x0800), length 98: 172.16.1.2 > 172.16.1.20: ICMP echo request, id 29651, seq 1016, length 64
09:00:39.474351 02:00:17:00:49:b2 > 02:00:17:00:75:07, ethertype IPv4 (0x0800), length 98: 172.16.1.20 > 172.16.1.2: ICMP echo reply, id 29651, seq 1016, length 64
★ F/O
09:00:40.497816 02:00:17:00:75:07 > 02:00:17:00:5e:18, ethertype IPv4 (0x0800), length 98: 172.16.1.2 > 172.16.1.20: ICMP echo request, id 29651, seq 1017, length 64
→ echo requestの宛先MACは02:00:17:00:5e:18 (F/O元)
09:00:40.498566 02:00:17:00:49:b2 > 02:00:17:00:75:07, ethertype IPv4 (0x0800), length 98: 172.16.1.20 > 172.16.1.2: ICMP echo reply, id 29651, seq 1017, length 64
→ echo replyの送信元MACは02:00:17:00:49:b2 (F/O先)
09:00:41.521801 02:00:17:00:75:07 > 02:00:17:00:5e:18, ethertype IPv4 (0x0800), length 98: 172.16.1.2 > 172.16.1.20: ICMP echo request, id 29651, seq 1018, length 64
09:00:41.522357 02:00:17:00:49:b2 > 02:00:17:00:75:07, ethertype IPv4 (0x0800), length 98: 172.16.1.20 > 172.16.1.2: ICMP echo reply, id 29651, seq 1018, length 64
```