IBM Cloud: VPC Custom Routesを利用したAZまたぎのHA環境の構成例(VPC内部からのアクセス）

# 1. やりたいこと

```
Tokyo1 Zone: 10.0.0.0/24
Tokyo2 Zone: 10.1.0.0/24
Tokyo3 Zone: 10.2.0.0/24
```

という構成であるとする。ここで、

- Server-A(10.0.0.7)
- Server-B(10.1.0.7)

というサーバーにアクセスする際にIPアドレスレベルでfailoverができるように、普段はVIP(192.168.10.10)でアクセスし、もしSever-Aに障害が発生しても別ZoneのServer-BにこのVIPのままアクセスさせたい。
なお、この192.168.10.10はVPCでprefixレベルで定義していないIPアドレスである。

- Server-A正常時(192.168.10.10宛のアクセスは10.0.0.7に転送）<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/b9754899-0734-294a-c562-d3c98e268a5e.png)

- Server-A障害時(192.168.10.10宛のアクセスは10.1.0.7に転送）<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/edace30a-6826-99c2-1866-6699eb6cf5fa.png)

なお、VPC外部からの切り替えについては、[こちら](https://qiita.com/testnin2/items/956df8a8790a0f3b7208)を参照してください。


# 2 設定方法

## 2-1. Custom Route(Egress)の設定
ドキュメントは、
https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes&locale=en
https://cloud.ibm.com/docs/vpc?topic=vpc-create-vpc-route&locale=en
を参照。

- 初期状態ではEgressタイプのデフォルトのルートテーブルが存在している。このテーブルを編集することにする。<br> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/98c25188-8381-b2cc-5d2d-1685dbfa7757.png)
- `192.168.10.10/32`宛のパケットが`10.0.0.7`に転送されるように構成する。<br><img width="50%" alt="image.png名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/4d2400f5-a4f5-c87f-5137-fce07ceefc55.png">
- 上記の例では、この経路をtokyo1にしか適用していないため、同様にtokyo2, tokyo3に対しても実施する。最終結果は以下の通り。<br> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/6d30de6c-6567-ade5-c4cf-ab7e3daf8b52.png)

（参考）
https://cloud.ibm.com/docs/vpc?topic=vpc-about-custom-routes#limitations-custom-routes
>For egress custom routes, when you add a destination route, you must select a zone. However, the next hop doesn't have to be in the same zone. For ingress custom routes, the next hop must be in the same zone.


この状態で、このVPC内の任意のサーバーから192.168.10.10宛のパケットは、

```txt
アクセス元サーバー -> Implicit Router -> Server-A(10.0.0.7)
```

となる。


```txt:VPC上の任意のサーバーからのping
[root@syasuda-tok1-vpc1 ~]# ping -c 3 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.

--- 192.168.10.10 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1999ms
```
```txt:Server-Aでのtcpdump
[root@server-a ~]# tcpdump -i any icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
17:29:51.382761 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 14185, seq 1, length 64
17:29:52.382690 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 14185, seq 2, length 64
17:29:53.382696 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 14185, seq 3, length 64

```

## 2-2. Server-A/Server-Bに192.168.10.10を付与

今回はipコマンドで暫定的にIPアドレスを付与した。

```txt:Server-A
[root@server-a ~]# ip a list eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:00:04:02:70:58 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.7/24 brd 10.0.0.255 scope global dynamic eth0
       valid_lft 291sec preferred_lft 291sec
    inet6 fe80::4ff:fe02:7058/64 scope link
       valid_lft forever preferred_lft forever
[root@server-a ~]# ip a add 192.168.10.10 dev eth0
[root@server-a ~]# ip a list eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:00:04:02:70:58 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.7/24 brd 10.0.0.255 scope global dynamic eth0
       valid_lft 262sec preferred_lft 262sec
    inet 192.168.10.10/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::4ff:fe02:7058/64 scope link
       valid_lft forever preferred_lft forever
```
```txt:Server-B
[root@server-b ~]# ip a list eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:00:04:02:71:37 brd ff:ff:ff:ff:ff:ff
    inet 10.1.0.7/24 brd 10.1.0.255 scope global dynamic eth0
       valid_lft 270sec preferred_lft 270sec
    inet6 fe80::4ff:fe02:7137/64 scope link
       valid_lft forever preferred_lft forever
[root@server-b ~]# ip a add 192.168.10.10 dev eth0
[root@server-b ~]# ip a list eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:00:04:02:71:37 brd ff:ff:ff:ff:ff:ff
    inet 10.1.0.7/24 brd 10.1.0.255 scope global dynamic eth0
       valid_lft 251sec preferred_lft 251sec
    inet 192.168.10.10/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::4ff:fe02:7137/64 scope link
       valid_lft forever preferred_lft forever
```

## 2-3. IP spoofingの有効化

Server-AやServer-Bからの戻りのパケットは本来自身が所有していない192.168.10.10がsourceとなるパケットになるため、IP Spoofingを有効化する。
IP Spoofingの有効化方法については、[こちら](https://qiita.com/testnin2/items/eef96d180583b6a87fda#4-ip-spoofing%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96)も参照。

- Server-A<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/6e494dd4-8a56-c967-60fe-edc929c79ffe.png)
- Server-B<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/16c30a89-68ee-ddb0-f84b-c273546b3e74.png)

## 2-4. Security Group/Network ACLで通信を許可する。

（省略）

# 3. テスト

##3-1. Server-A正常時のアクセス
デフォルトの状態では、このVPC内の任意のサーバーから192.168.10.10宛のパケットは、

```txt
アクセス元サーバー -> Implicit Router -> Server-A(10.0.0.7)
```
となる。

```
#送信元
[root@client ~]# ping -c 3 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
64 bytes from 192.168.10.10: icmp_seq=1 ttl=64 time=5.23 ms
64 bytes from 192.168.10.10: icmp_seq=2 ttl=64 time=0.281 ms
64 bytes from 192.168.10.10: icmp_seq=3 ttl=64 time=0.404 ms

--- 192.168.10.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.281/1.974/5.237/2.307 ms

#Server-A
[root@server-a ~]# tcpdump -i any icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
17:39:53.722252 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 14890, seq 1, length 64
17:39:53.722341 IP 192.168.10.10 > 10.0.0.12: ICMP echo reply, id 14890, seq 1, length 64
17:39:54.723566 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 14890, seq 2, length 64
17:39:54.723593 IP 192.168.10.10 > 10.0.0.12: ICMP echo reply, id 14890, seq 2, length 64
17:39:55.723697 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 14890, seq 3, length 64
17:39:55.723730 IP 192.168.10.10 > 10.0.0.12: ICMP echo reply, id 14890, seq 3, length 64


#Server-B
[root@server-b ~]# tcpdump -i any icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
```

## 3-2. Server-A障害時のアクセス（Server-Bへの切り替えテスト）

Server-A障害によって経路をAPIなどを使って以下のように変更することを想定。
自動スクリプトのサンプルは[IBM Cloud: VPC Custom Routesの切り替えスクリプト・サンプル](https://qiita.com/testnin2/items/2ebea2524e4c59e19f5b)を参照。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/54f1b508-89bf-1d73-fc2d-76b17b4b5dbb.png)

これにより、このVPC内の任意のサーバーから192.168.10.10宛のパケットは、

```txt
アクセス元サーバー -> Implicit Router -> Server-A(10.1.0.7)
```
となる。

```
#送信元
[root@client ~]# ping -c 3 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
64 bytes from 192.168.10.10: icmp_seq=1 ttl=57 time=1.82 ms
64 bytes from 192.168.10.10: icmp_seq=2 ttl=57 time=1.64 ms
64 bytes from 192.168.10.10: icmp_seq=3 ttl=57 time=1.67 ms

--- 192.168.10.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 1.640/1.713/1.823/0.079 ms

#Server-A
[root@server-a ~]# tcpdump -i any icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes


#Server-B
[root@server-b ~]# tcpdump -i any icmp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
17:47:08.063999 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 15512, seq 1, length 64
17:47:08.064091 IP 192.168.10.10 > 10.0.0.12: ICMP echo reply, id 15512, seq 1, length 64
17:47:09.065852 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 15512, seq 2, length 64
17:47:09.065877 IP 192.168.10.10 > 10.0.0.12: ICMP echo reply, id 15512, seq 2, length 64
17:47:10.067421 IP 10.0.0.12 > 192.168.10.10: ICMP echo request, id 15512, seq 3, length 64
17:47:10.067455 IP 192.168.10.10 > 10.0.0.12: ICMP echo reply, id 15512, seq 3, length 64
```