【MetalLB】Kubernetes(オンプレ)の負荷分散 BGP+ECMP+BFD設定手順

Kubernetes

前回MetalLBの動作の仕組みについて説明しました。
Kubernetesのオンプレ環境で負荷分散するためにMetalLBを設定します。

概要

今回はKubernetesの外部通信を負荷分散するためにMetalLBBGP+ECMP+BFDの環境を構築します。
ルータはFortigateを利用しています。(ルータではないという突っ込みは無しで…)
構成は下図になります。

環境

NW環境

名前バージョン
Fortigatev7.2.3

Kubernetes環境

名前バージョン
CentOS-Stream-9
kubeletv1.26.2
kubeadmv1.26.2
containerdv1.6.16
calicov3.25
metallbv0.13.9

設定手順

Fortigateの設定

ECMP設定

クラスタが3台構成なのでECMPのMAXパスに3を設定します。

config system settings
    set ecmp-max-paths 3
end

BGP設定

「高度なルーティング」が有効になっていなければGUIで有効化します。

CLIで下記設定を投入します。(ECMPの設定はCLIでのみ設定可能です)

config router bgp
    set as 65000
    set router-id 10.20.30.254
    set keepalive-timer 10
    set holdtime-timer 30
    set ebgp-multipath enable
    config neighbor
        edit "10.20.30.1"
            set bfd enable
            set capability-default-originate enable
            set soft-reconfiguration enable
            set remote-as 65001
        next
        edit "10.20.30.2"
            set bfd enable
            set capability-default-originate enable
            set soft-reconfiguration enable
            set remote-as 65001
        next
        edit "10.20.30.3"
            set bfd enable
            set capability-default-originate enable
            set soft-reconfiguration enable
            set remote-as 65001
        next
    end
    config redistribute "connected"
    end
    config redistribute "rip"
    end
    config redistribute "ospf"
    end
    config redistribute "static"
    end
    config redistribute "isis"
    end
    config redistribute6 "connected"
    end
    config redistribute6 "rip"
    end
    config redistribute6 "ospf"
    end
    config redistribute6 "static"
    end
    config redistribute6 "isis"
    end
end

BFD設定

CLIでBFDの有効化とネイバーを設定します。

config system interface
    edit "dmz"
        set bfd enable
    next
end
config router bfd
    config neighbor
        edit 10.20.30.1
            set interface "dmz"
        next
        edit 10.20.30.2
            set interface "dmz"
        next
        edit 10.20.30.3
            set interface "dmz"
        next
    end
end

ipvsに変更

kube-proxyの設定をiptablesからipvsに変更します。
コマンドで編集モードで入ります。

kubectl edit configmap -n kube-system kube-proxy

ipvsを有効化するのにARPの設定が必要になります。
下記設定を変更しipvsに切り替えます。

apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
 strictARP: true

補足:以下コマンドでdiff取りと設定変更が可能です。

kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
sed -e "s/mode: \"\"/mode: \"ipvs\"/" | \
kubectl diff -f - -n kube-system
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/mode: \"\"/mode: \"ipvs\"/" | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system

kube-proxyのPodを再起動します。

kubectl get pods -A |grep proxy  #Pod名を確認
kubectl delete pod --namespace=kube-system [kube-proxy名]

MetalLB構築

KubernetesにMetalLBを導入していきます。

MetalLBのデプロイ

BFDを使いたいのでMetalLBのFRRモードを利用します。
下記コマンドでMetalLBをデプロイします。

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-frr.yaml

MetalLBの設定

IPアドレスプールやBGP、BFDのマニュフェストを作成して適用します。
metallb-config.yamlで作成します。

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 172.16.200.1-172.16.200.254
  autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: BGPPeer
metadata:
  name: bgp-peer
  namespace: metallb-system
spec:
  myASN: 65001
  peerASN: 65000
  peerAddress: 10.20.30.254
  peerPort: 179
  bfdProfile: bfdprofile
---
apiVersion: metallb.io/v1beta1
kind: BFDProfile
metadata:
  name: bfdprofile
  namespace: metallb-system
spec:
  receiveInterval: 25
  transmitInterval: 25
---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
  name: external
  namespace: metallb-system
spec:
  ipAddressPools:
  - first-pool
  aggregationLength: 24

マニュフェストを適用します。

kubectl apply -f metallb-config.yaml 

MetalLB動作確認

MetalLBの状態確認

kubectl get pods –namespace=metallb-system -o wideでControllerとSpeakerがRunningになっていることを確認します。

[user001@k8s-mas01~]#  kubectl get pods --namespace=metallb-system -o wide
NAMESPACE          NAME                                       READY   STATUS    RESTARTS         AGE     IP               NODE         NOMINATED NODE   READINESS GATES
metallb-system     controller-7dd7f6785b-nbv9w                1/1     Running   25 (159d ago)    90d     10.240.235.205   k8s-mas01   <none>           <none>
metallb-system     speaker-5pbzn                              4/4     Running   124 (159d ago)   97d     10.20.30.1     k8s-mas01   <none>           <none>
metallb-system     speaker-6bnz7                              4/4     Running   116 (159d ago)   97d     10.20.30.2     k8s-nod01   <none>           <none>
metallb-system     speaker-blfm8                              4/4     Running   108 (159d ago)   97d     10.20.30.3     k8s-nod02   <none>           <none>

Fortigateの状態確認

get router info bgp networkでピアからルートを受信してマルチホップで見えることを確認できます。

FortiGate # get router info bgp network
VRF 0 BGP table version is 280, local router ID is 10.20.30.254
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
              S Stale
Origin codes: i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric     LocPrf Weight RouteTag Path
*  172.16.200.0/24  10.20.30.3    0                      0        0 65001 i <-/->
*                   10.20.30.1    0                      0        0 65001 i <-/->
*>                  10.20.30.2    0                      0        0 65001 i <-/1>

Total number of prefixes 1

get router info bfd neighborでBFDステータスがアップしていることを確認できます。

FortiGate # get router info bfd neighbor

OurAddress      NeighAddress    State       Interface       LDesc/RDesc
10.20.30.254  10.20.30.1    UP          dmz             3/124
10.20.30.254  10.20.30.2    UP          dmz             2/254
10.20.30.254  10.20.30.3    UP          dmz             1/111

テスト用Podを起動

Nginxデプロイ

テスト用にNginxを6つ稼働させます。
nginx-test.yamlで作成します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  labels:
    app: nginx
spec:
  replicas: 6
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    app: nginx
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  ports:
  - port: 80
  selector:
    app: nginx

マニュフェストを適用します。

kubectl apply -f nginx-test.yaml

Nginx状態確認

kubectl get pods –output=wideでPod状態一覧を表示して確認してみます。
6つ全てがRunningになっていることを確認できます。

[user001@k8s-mas01~]# kubectl get pods --output=wide
NAME                                 READY   STATUS    RESTARTS       AGE     IP               NODE         NOMINATED NODE   READINESS GATES
my-nginx-6b7f675859-896df            1/1     Running   0              2m35s   10.240.235.198   k8s-mas01   <none>           <none>
my-nginx-6b7f675859-fvxnh            1/1     Running   0              2m35s   10.240.58.219    k8s-nod02   <none>           <none>
my-nginx-6b7f675859-gcdh8            1/1     Running   0              2m35s   10.240.85.212    k8s-nod01   <none>           <none>
my-nginx-6b7f675859-m8xgx            1/1     Running   0              2m35s   10.240.235.245   k8s-mas01   <none>           <none>
my-nginx-6b7f675859-mms4c            1/1     Running   0              2m35s   10.240.85.209    k8s-nod01   <none>           <none>
my-nginx-6b7f675859-tq6hg            1/1     Running   0              2m35s   10.240.58.213    k8s-nod02   <none>           <none>

kubectl get svcでサービス状態を確認します。
LoadBalancerタイプでExternal-IPが割り振られていることが確認できます。

[user001@k8s-mas01~]# kubectl get svc
NAME                TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)        AGE
my-nginx-svc        LoadBalancer   10.105.165.234   172.16.200.1   80:31890/TCP   101s

外部端末からブラウザでアクセスできることを確認できます。

テスト用Pod削除

下記のコマンドでPod設定を削除します。

kubectl delete -f nginx-test.yaml

最後に

最後までお読みいただきありがとうございます。
Kubernetesは仕組みが複雑で詰まるところも多いので、毎日試行錯誤する日々です。
ただ、KubernetesだけでなくISPやNW機器周りで書きたいことが溜まっているので出来るだけそちら方面も記事に起こしていこうと思います。

参考サイト