Cilium BGP Control PlaneとVyOSを活用したおうちKubernetesでのLoadBalancer構築

# はじめに
今までおうちKubernetes上のWebサービスは、MetalLBとIngress-NGINXを組み合わせてアクセスできるようにしていましたが、すべてCiliumの機能で統一したいと思い、Cilium BGP Control Planeの機能を使えるようにしてみました。

BGPについてはまだ理解していないことが多く、試行錯誤しながらの設定になりましたが、実際に動作させることができました。本記事では、その設定手順とポイントを共有します。

CiliumのBGP Control Planeを使用することで、外部のルーターとBGPピアリングを行い、LoadBalancerサービスを自宅ネットワークからアクセス可能にすることができます。今回はVyOSをルーターとして使用し、自宅のBuffaloルーターとも連携してネットワークを構築しました。

それでは、順に説明していきます。

# 目次
1. 環境
1. VyOSの設定
1. Cilium BGP Control Planeの設定
1. 自宅ルーターへの経路情報の追加
1. 動作確認

# 環境
#### ルーター
バッファロー WSR-2533DHP3
192.168.11.1/24

- このルーターは家庭内ネットワークのゲートウェイとして機能しています。
- 後ほど、このルーターに静的ルートを追加して、KubernetesのLoadBalancerサービスへのアクセスを可能にします。

#### Kubernetes
```
$ kubectl get nodes -o wide
NAME      STATUS   ROLES           AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE                         KERNEL-VERSION         CONTAINER-RUNTIME
master1   Ready    control-plane   77d   v1.31.2   192.168.11.101   <none>        Debian GNU/Linux 12 (bookworm)   6.1.0-25-cloud-amd64   cri-o://1.31.2
master2   Ready    control-plane   77d   v1.31.2   192.168.11.102   <none>        Debian GNU/Linux 12 (bookworm)   6.1.0-25-cloud-amd64   cri-o://1.31.2
master3   Ready    control-plane   77d   v1.31.2   192.168.11.103   <none>        Debian GNU/Linux 12 (bookworm)   6.1.0-25-cloud-amd64   cri-o://1.31.2 
worker1   Ready    <none>          77d   v1.31.2   192.168.11.111   <none>        Debian GNU/Linux 12 (bookworm)   6.1.0-25-cloud-amd64   cri-o://1.31.2
worker2   Ready    <none>          77d   v1.31.2   192.168.11.112   <none>        Debian GNU/Linux 12 (bookworm)   6.1.0-25-cloud-amd64   cri-o://1.31.2 
worker3   Ready    <none>          77d   v1.31.2   192.168.11.113   <none>        Debian GNU/Linux 12 (bookworm)   6.1.0-25-cloud-amd64   cri-o://1.31.2
```
- クラスターには3つのコントロールプレーンノード（master1、master2、master3）と3つのワーカーノード（worker1、worker2、worker3）があります。
- 各ノードのINTERNAL-IP（内部IPアドレス）は後ほどBGPの設定で使用します。

#### VyOS
```
vyos@vyos:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 ...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
    inet 192.168.11.251/24 brd 192.168.11.255 scope global eth0
```
- eth0インターフェイスが192.168.11.251/24のIPアドレスを持っています。
- このインターフェイスを通じて、Kubernetesクラスターと通信を行います。

# VyOSの設定
### インターフェースと基本設定
```
set interfaces ethernet eth0 address 192.168.11.251/24
set protocols static route 0.0.0.0/0 next-hop 192.168.11.1
set system name-server 1.1.1.1
set system name-server 1.0.0.1
```
- eth0に192.168.11.251/24のIPアドレスを割り当てます。
- デフォルトルートを192.168.11.1（自宅ルーターのIPアドレス）に設定します。
- DNSサーバーにCloudflareの1.1.1.1と1.0.0.1を指定します。

### BGPの設定
VyOSでBGPを設定し、Kubernetesノードとピアリングを行います。
#### 自身のAS番号とルーターIDの設定
```
set protocols bgp system-as 65100
set protocols bgp 65100 router-id 192.168.11.251
```
- VyOSルーターのAS番号を65100に設定します。
- BGPのルーターIDを自身のIPアドレス192.168.11.251に設定します。

#### 接続されたネットワークの再配布
```
set protocols bgp address-family ipv4-unicast redistribute connected
```
- 直接接続されているネットワークをBGPで再配布します。

#### KubernetesノードとのBGPネイバー設定
各KubernetesノードとのBGPピアを設定します。
```
set protocols bgp neighbor 192.168.11.101 remote-as 65101
set protocols bgp neighbor 192.168.11.102 remote-as 65101
set protocols bgp neighbor 192.168.11.103 remote-as 65101
set protocols bgp neighbor 192.168.11.111 remote-as 65101
set protocols bgp neighbor 192.168.11.112 remote-as 65101
set protocols bgp neighbor 192.168.11.113 remote-as 65101
```
- 各Kubernetesノード（192.168.11.101〜192.168.11.113）をBGPのネイバーとして設定し、リモートAS番号を65101に設定します。

#### Next Hopの設定
```
set protocols bgp neighbor 192.168.11.101 address-family ipv4-unicast nexthop-self
set protocols bgp neighbor 192.168.11.102 address-family ipv4-unicast nexthop-self
set protocols bgp neighbor 192.168.11.103 address-family ipv4-unicast nexthop-self
set protocols bgp neighbor 192.168.11.111 address-family ipv4-unicast nexthop-self
set protocols bgp neighbor 192.168.11.112 address-family ipv4-unicast nexthop-self
set protocols bgp neighbor 192.168.11.113 address-family ipv4-unicast nexthop-self
```
- 各ネイバーに対してnexthop-selfを設定し、経路情報のNext HopをVyOS自身に書き換えます。

# Cilium BGP Control Planeの設定
#### Ciliumのインストール
```
cilium install --version 1.16.3 --set bgpControlPlane.enabled=true
```
- BGP Control Planeの機能を使えるようにします。
#### ノードにラベルを付与
BGP設定を適用する対象のノードにラベルを付与します。
```
kubectl label node --all rack=rack0
```
- すべてのノードにrack=rack0というラベルを付与します。

#### BGP設定の適用
bgp.yamlを作成し、以下の内容を記述します。(参考: https://github.com/cilium/cilium/blob/main/contrib/containerlab/bgpv2/service/bgp.yaml)
```
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPClusterConfig
metadata:
  name: cilium-bgp
spec:
  nodeSelector:
    matchLabels:
      rack: rack0
  bgpInstances:
    - name: "65101"
      localASN: 65101
      peers:
        - name: "peer-65100"
          peerASN: 65100
          peerAddress: 192.168.11.251
          peerConfigRef:
            name: "cilium-peer"

---
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  gracefulRestart:
    enabled: true
    restartTimeSeconds: 15
  families:
    - afi: ipv4
      safi: unicast
      advertisements:
        matchLabels:
          advertise: "bgp"

---
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "PodCIDR"
      attributes:
        communities:
          standard: ["65000:99"]
    - advertisementType: "Service"
      service:
        addresses:
          - LoadBalancerIP
      selector:
        matchExpressions:
          - { key: dummy, operator: NotIn, values: ["never-used-value"] }
      attributes:
        communities:
          standard: ["65000:100"]
```
```
kubectl apply -f bgp.yaml
```
- CiliumBGPClusterConfig: BGPのクラスタ設定を定義します。
- CiliumBGPPeerConfig: BGPピアの詳細な設定を定義します。
- CiliumBGPAdvertisement: 広告する経路情報を定義します。

#### LoadBalancer IPプールの設定
ippools.yamlを作成し、以下の内容を記述します。(参考:https://github.com/cilium/cilium/blob/main/contrib/containerlab/bgpv2/service/lb-ip.yaml)
```
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
  name: "ip-pool"
spec:
  blocks:
    - cidr: 10.251.0.0/16
```
```
kubectl apply -f ippools.yaml
```
- 10.251.0.0/16のIPレンジをLoadBalancerサービス用のIPプールとして定義します。

# 自宅ルーターへの経路情報の追加
家庭内ネットワークからLoadBalancerサービスにアクセスできるように、自宅のBuffaloルーターに静的ルートを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733784/87e59995-5876-beb2-5da2-d77a203477f4.png)
- 宛先アドレス: 10.251.0.0（LoadBalancer IPプールのネットワーク）
- サブネットマスク: 255.255.0.0（/16）
- ゲートウェイ: 192.168.11.251（VyOSルーターのIPアドレス）

# 動作確認
#### サンプルアプリケーションのデプロイ
```
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-cilium
  name: nginx-cilium
spec:
  selector:
    matchLabels:
      app: nginx-cilium
  template:
    metadata:
      labels:
        app: nginx-cilium
    spec:
      containers:
        - image: nginx
          name: nginx-cilium
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-cilium
spec:
  selector:
    app: nginx-cilium
  ports:
    - name: http
      port: 80
      targetPort: 80
  type: LoadBalancer
```
デプロイとサービスを適用します。
```
kubectl apply -f sample.yaml
```
```
kubectl get services
NAME           TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
...
nginx-cilium   LoadBalancer   10.97.54.235   10.251.0.7    80:31509/TCP   2m40s
```
- EXTERNAL-IPに10.251.0.7が割り当てられています。
#### 外部からのアクセス確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733784/9d68e9cb-3f0b-ac36-7167-b5412f9cf2ca.png)
無事表示されました。

#### VyOSでの経路確認
```
vyos@vyos:~$ show ip route bgp
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
       f - OpenFabric,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure
...
B>* 10.251.0.7/32 [20/0] via 192.168.11.101, eth0, weight 1, 00:04:55
  *                      via 192.168.11.102, eth0, weight 1, 00:04:55
  *                      via 192.168.11.103, eth0, weight 1, 00:04:55
  *                      via 192.168.11.111, eth0, weight 1, 00:04:55
  *                      via 192.168.11.112, eth0, weight 1, 00:04:55
  *                      via 192.168.11.113, eth0, weight 1, 00:04:55
...
```
- BGPで学習した経路情報が表示されます。

# おわりに
今回は、Cilium BGP Control PlaneとVyOSを活用して、おうちKubernetes環境でLoadBalancerサービスを実現する方法を紹介しました。
皆さんの学習や実践の一助になれば幸いです。