概要
Oracle Cloud Infrastructure(OCI)上にてVRRPの検証を行いました
仕組み
オンプレ環境と比較してクラウドはネットワーク冗長化の制約があるため以下のように実現しています
クラウドはOCI, ネットワークデバイスはVYOSを使用しました
- VRRP Hello
- オンプレ:Multicastで実行可能
- OCI:Multicast通信の制限があるのでUnicastを使用
- VRRP切り替え
- オンプレ:BACKUPがMASTERに切り替わり、新MASTERよりGratuitous ARP送出
- OCI:BACKUPがMASTERに切り替わり、以下手順でセカンダリIP(VIP)を移動
- 新MASTERからAPI Gatewayにcurl POST発行
- API GatewayからFunction呼び出し
- 旧MASTERのVNICのセカンダリIP(VIP)を新MASTERのVNICに移動するFunctionsを実行
検証構成図
- ACTIVEルーターをVYOS1, STANDBYルーターをVYOS2
- サブネット
- 10.107.1.0/24 : 外部ルーター接続
- 10.107.2.0/24 : VRRP稼働、サーバーが存在
- 10.107.3.0/24 : API GWおよびFn用
前提
以下を前提としています
- Functionを作成したことがある
- オンプレ~OCI間のVPN構築済
準備
OCI Policy
IPアドレスを操作するためのポリシーは以下を設定します
- FunctionsからIPアドレス更新を実行
Allow dynamic-group [functionsリソースを含むグループ] to use private-ips in compartment [コンパートメント名]
Allow dynamic-group [functionsリソースを含むグループ] to use vnics in compartment [コンパートメント名]
または
Allow dynamic-group [functionsリソースを含むグループ] to use virtual-network-family in compartment [コンパートメント名]
Seconday IP
- OCIコンソールナビゲーションメニューからコンピュート>>インスタンス>>対象のインスタンス(例:VYOS1)を選択
- ResourcesからアタッチされたVNIC>>セカンダリVNIC>>IPv4 アドレスを選択して[セカンダリ・プライベートIPアドレスの割当て]を押下してセカンダリIPを入力して[割当て]を押下(例:10.107.2.100)
- 作成したセカンダリIPの3点リーダー(︙)をクリックしてプライべートIP OCIDのコピーを選択
ルーティング
- OCIコンソールナビゲーションメニューからネットワーキング>>仮想クラウド・ネットワーク>>対象VCN>>ルート表>>対象ルート表を選択して[ルート・ルール]を押下
- 以下を設定して[ルートルールの追加]を押下
- ターゲット・タイプ:プライベートIP
- 宛先タイプ:CIDRブロック
- 宛先CIDRブロック:対向側CIDR
- ターゲット選択:プライべートIP OCID
Functions
- OCIコンソールナビゲーションメニューから開発者サービス>>ファンクションを選択して[アプリケーションの作成]を押下
- 以下を設定して[作成]を押下
- 名前:任意
- サブネット:Functionを実行するサブネット(例:10.107.3.0/24)
- 作成したアプリケーション下でFunctionを設定
func.py
import io
import json
import logging
import oci
def handler(ctx, data: io.BytesIO = None):
try:
body = json.loads(data.getvalue())
private_ip_id = body["private_ip_id"]
vnic_id = body["vnic_id"]
# Resource principal
signer = oci.auth.signers.get_resource_principals_signer()
# Update private ip using resource principal
core_client = oci.core.VirtualNetworkClient(config={},signer=signer,service_endpoint="https://iaas.ap-tokyo-1.oraclecloud.com")
update_private_ip_response = core_client.update_private_ip(
private_ip_id=private_ip_id,
update_private_ip_details=oci.core.models.UpdatePrivateIpDetails(
vnic_id=vnic_id
)
)
except Exception as e:
print('ERROR: bad Event!', flush=True)
raise
func.yaml
schema_version: 20180708
name: updateprivateip
version: 0.0.8
runtime: python
build_image: fnproject/python:3.11-dev
run_image: fnproject/python:3.11
entrypoint: /python/bin/fdk /function/func.py handler
memory: 256
requirements.txt
fdk>=0.1.86
oci
アプリケーションを指定してFunctionsをデプロイ
fn -v deploy --app <App名>
API Gateway
ネットワーク・セキュリティ・グループ(NSG)
NSGを設定してAPI GatewayへのアクセスはVYOSのみに制限します
- OCIコンソールナビゲーションメニューからネットワーキング>>仮想クラウド・ネットワーク>>対象VCN>>リソース ネットワーク・セキュリティ・グループを選択して[ネットワーク・セキュリティ・グループの作成]を押下
- 以下を設定して[作成]を押下
- 名前:任意
- ルール:
- 方向:イングレス
- ソース・タイプ:CIDR
- ソースCIDR:VYOS1 LAN IP(例:10.107.1.98/32)
- IPプロトコル:TCP
- ソース・ポート範囲:All
- 宛先ポート範囲:443
- 別のルール:
- 方向:イングレス
- ソース・タイプ:CIDR
- ソースCIDR:VYOS2 LAN IP(例:10.107.1.99/32)
- IPプロトコル:TCP
- ソース・ポート範囲:All
- 宛先ポート範囲:443
API Gateway
- OCIコンソールナビゲーションメニューから開発者サービス>>API管理>>ゲートウェイから[ゲートウェイの作成]を押下
- 以下を設定して[ゲートウェイの作成]を押下
- 名前:任意
- タイプ:プライベート
- ネットワーク:対象ネットワークを指定(例:10.107.3.0)
- ネットワーク・セキュリティ・グループの有効化にチェックして作成したNSGを選択
- 作成したゲートウェイから呼び出すFunctionsを選択してリソース デプロイメントから[デプロイメントの作成]を押下
- 以下を設定して[作成]を押下
- 名前:任意
- パス接頭辞:任意(例:/icnfnapp)
- 認証:なし
- パス:任意(例:/updateprivateip)
- メソッド:POST
- バックエンド・タイプ:Oracleファンクション
- アプリケーション:作成したアプリケーション
- 関数名:作成したFunction
VYOS
ルーターVYOS1およびVYOS2にVRRPを設定します。
設定のポイントは以下のとおりです。
- StateがMasterになった場合Curl POSTするShellを実行
- VYOS1復旧時にMasterとなるDelay値を60秒にする
VYOS1
- config抜粋
set high-availability vrrp group vrrp01 hello-source-address '10.107.2.98'
set high-availability vrrp group vrrp01 interface 'eth1'
set high-availability vrrp group vrrp01 peer-address '10.107.2.99'
set high-availability vrrp group vrrp01 preempt-delay '60'
set high-availability vrrp group vrrp01 priority '200'
set high-availability vrrp group vrrp01 transition-script master '/config/scripts/updateprivateip_1.sh'
set high-availability vrrp group vrrp01 virtual-address 10.107.2.100/24
set high-availability vrrp group vrrp01 vrid '10'
set interfaces ethernet eth0 address '10.107.1.98/24'
set interfaces ethernet eth1 address '10.107.2.98/24'
set protocols static route 0.0.0.0/0 next-hop 10.107.1.1
- Shell
/config/scripts/updateprivateip_1.sh
#!/bin/bash
curl -k -X POST https://10.107.3.105/icnfnapp/updateprivateip -d '{"private_ip_id":"<Secondary IP OCID>","vnic_id":"<VYOS1 Secondary VNIC OCID>"}'
VYOS2
- config抜粋
set high-availability vrrp group vrrp01 hello-source-address '10.107.2.99'
set high-availability vrrp group vrrp01 interface 'eth1'
set high-availability vrrp group vrrp01 peer-address '10.107.2.98'
set high-availability vrrp group vrrp01 priority '100'
set high-availability vrrp group vrrp01 transition-script master '/config/scripts/updateprivateip_2.sh'
set high-availability vrrp group vrrp01 virtual-address 10.107.2.100/24
set high-availability vrrp group vrrp01 vrid '10'
set interfaces ethernet eth0 address '10.107.1.99/24'
set interfaces ethernet eth1 address '10.107.2.99/24'
set protocols static route 0.0.0.0/0 next-hop 10.107.1.1
- Shell
/config/scripts/updateprivateip_2.sh
#!/bin/bash
curl -k -X POST https://10.107.3.105/icnfnapp/updateprivateip -d '{"private_ip_id":"<Secondary IP OCID>","vnic_id":"<VYOS1 Secondary VNIC OCID>"}'
検証
ACTIVEルーターを落として迂回できることを確認しました。なお、環境の都合上海外サイトを使用しているためレイテンシーが大きいですがテストには支障ありません。
通常時
- VRRP StateをVYOSから確認
user@VYOS1:~$ show vrrp
Name Interface VRID State Priority Last Transition
------ ----------- ------ ------- ---------- -----------------
vrrp01 eth1 10 MASTER 200 2d17h48m29s
user@VYOS2:~$ show vrrp
Name Interface VRID State Priority Last Transition
------ ----------- ------ ------- ---------- -----------------
vrrp01 eth1 10 BACKUP 100 2d17h48m26s
- OCIコンソールからセカンダリIP付与を確認
VYOS1
- オンプレからサーバーにPING
C:\>ping 10.107.2.200 -t
10.107.2.200 に ping を送信しています 32 バイトのデータ:
10.107.2.200 からの応答: バイト数 =32 時間 =382ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =378ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =391ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =371ms TTL=60
VYOS1障害
- VRRP StateをVYOSから確認
user@VYOS1は障害のためログなし
user@VYOS2:~$ show vrrp
Name Interface VRID State Priority Last Transition
------ ----------- ------ ------- ---------- -----------------
vrrp01 eth1 10 MASTER 100 24s
- OCIコンソールからセカンダリIP付与を確認
VYOS1
- オンプレからサーバーにPINGして復旧を確認
C:\>ping 10.107.2.200 -t
10.107.2.200 に ping を送信しています 32 バイトのデータ:
10.107.2.200 からの応答: バイト数 =32 時間 =379ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =432ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =377ms TTL=60
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
10.107.2.200 からの応答: バイト数 =32 時間 =376ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =370ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =367ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =377ms TTL=60
VYOS1復旧
- VRRP StateをVYOSから確認
user@VYOS1:~$ show vrrp
Name Interface VRID State Priority Last Transition
------ ----------- ------ ------- ---------- -----------------
vrrp01 eth1 10 MASTER 200 10s
user@VYOS2:~$ show vrrp
Name Interface VRID State Priority Last Transition
------ ----------- ------ ------- ---------- -----------------
vrrp01 eth1 10 BACKUP 100 14s
- OCIコンソールからセカンダリIP付与を確認
VYOS1
- オンプレからサーバーにPING
C:\>ping 10.107.2.200 -t
10.107.2.200 に ping を送信しています 32 バイトのデータ:
10.107.2.200 からの応答: バイト数 =32 時間 =376ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =383ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =380ms TTL=60
略
10.107.2.200 からの応答: バイト数 =32 時間 =380ms TTL=60
10.107.2.200 からの応答: バイト数 =32 時間 =374ms TTL=60
10.107.2.200 の ping 統計:
パケット数: 送信 = 190、受信 = 190、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
最小 = 354ms、最大 = 723ms、平均 = 383ms