0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

kube-vipでKubernetes Control PlaneのHAを実現する

Last updated at Posted at 2025-12-23

はじめに

Control Planeを冗長化しHAを実現するKubernetesクラスタを構築することを目的に、kube-vipを利用しました。その際に、kubesprayを用いて構築を行いましたが、その流れをまとめてみたいと思います。

kube-vipとは

概要

kube-vipは、HAなControl PlaneやService LoadBalancerを実現するためのOSSです。
HAProxyやKeepalivedなどの外部コンポーネントに依存せず、ARPやBGPを使ってシンプルに冗長構成を構築することのできる点が特徴です。

仕組み

ARPモード

ARPモードでは、kube-vipが Kubernetesのleader electionの仕組みを用いて複数ノードの中から1台のノードをleaderとして選出します。
leaderとなったノードにのみ、VIP(Virtual IP)がネットワークインターフェースに付与され、VIP宛の通信に対して唯一ARP応答を行います。
leaderノードに障害が発生した場合、leader electionが再実行され、新しいleaderが選出されます。同時に、VIPも新ノードに引き継がれます。

参考:

BGPモード

BGPモードでは、VIPを単一ノードに集約するためのleader electionは行われず、各ノードが外部ルーターに対してVIPをBGPで広告します。
ルーターはBGPの経路選択に基づいて通信先ノードを決定し、選択されたノード上のkube-apiserverがリクエストを処理します。

参考:

アーキテクチャについて

今回構築したKubernetesクラスタのControl Planeの構成を紹介します。

ARPモード

kubesprayの設定により、クライアントからのAPIリクエストはControl PlaneのVIPに送信されます。
VIPはkube-vipによってleaderノードのネットワークインターフェイスに付与され、ARPによりVIP宛通信はleaderノードのMACアドレスへ到達します。
その結果、leaderノード上のkube-apiserverがリクエストを処理します。

処理されたデータは etcdクラスタを通じて各Control Planeノードのetcdに分散して保存され、クラスタ全体で状態が共有されます。
leaderノードに障害が発生した場合はleader選出が行われ、leaderが交代します。

この仕組みにより、Control Planeの可用性が維持されます。

image.png
leaderノードに障害が発生した際の可用性やVIPの移動、及びL2によるブロードキャストについては後ほど実際に確認を行います。

BGPモード

BGPモードで利用する場合、各Master NodeがBGPルーターに対してVIPである192.168.80.10/32宛の通信を自Nodeに送るよう広告を行います。そして、BGPルーターは経路の学習を行い、経路選択で選んだMaster Nodeへ転送します。

image.png

設定

kubesprayによるクラスタ構築

kubesprayは、Ansibleをベースとした、Kubernetesクラスタ構築を行うツールです。

一度設定を作成すれば、クラスタの破棄や再構築、IPアドレスを変更した上での使い回しが容易であり、設定内容をソースコードとして管理できるため便利です。

hosts.yaml
all:
  hosts:
    k8s-master-1:
      ansible_host: 192.168.0.11
      ip: 192.168.0.11
      access_ip: 192.168.0.11

    k8s-master-2:
      ansible_host: 192.168.0.12
      ip: 192.168.0.12
      access_ip: 192.168.0.12

    k8s-master-3:
      ansible_host: 192.168.0.13
      ip: 192.168.0.13
      access_ip: 192.168.0.13

    k8s-worker-1:
      ansible_host: 192.168.0.14
      ip: 192.168.0.14
      access_ip: 192.168.0.14

    k8s-worker-2:
      ansible_host: 192.168.0.15
      ip: 192.168.0.15
      access_ip: 192.168.0.15

    k8s-worker-3:
      ansible_host: 192.168.0.16
      ip: 192.168.0.16
      access_ip: 192.168.0.16

    k8s-worker-4:
      ansible_host: 192.168.0.17
      ip: 192.168.0.17
      access_ip: 192.168.0.17

  vars:
    ansible_user: ryu

  children:
    kube_control_plane:
      hosts:
        k8s-master-1:
        k8s-master-2:
        k8s-master-3:

    etcd:
      hosts:
        k8s-master-1:
        k8s-master-2:
        k8s-master-3:

    kube_node:
      hosts:
        k8s-worker-1:
        k8s-worker-2:
        k8s-worker-3:
        k8s-worker-4:

    k8s_cluster:
      children:
        kube_control_plane:
        kube_node:

上記設定を加えた後、ansible-playbookを実行することでControl Planeが冗長化されたKubernetesクラスタが構築されます。

$ kubectl get nodes
NAME           STATUS   ROLES           AGE     VERSION
k8s-master-1   Ready    control-plane   4h54m   v1.34.2
k8s-master-2   Ready    control-plane   4h53m   v1.34.2
k8s-master-3   Ready    control-plane   4m10s   v1.34.2
k8s-worker-1   Ready    <none>          3m18s   v1.34.2
k8s-worker-2   Ready    <none>          3m18s   v1.34.2
k8s-worker-3   Ready    <none>          3m18s   v1.34.2
k8s-worker-4   Ready    <none>          3m18s   v1.34.2

ARPモードのkube-vip設定

kube_control_plane_vip を指定することで、clientがAPIサーバーへ接続するためのエンドポイントが設定されます。
また、ARPモードでkube-vipを利用する設定を明記しています。

group_vars/k8s_cluster/k8s-cluster.yml
kube_proxy_strict_arp: true
kube_control_plane_vip: "192.168.0.10"
kube_vip_enabled: true
kube_vip_controlplane_enabled: true
kube_vip_arp_enabled: true
kube_vip_interface: "ens18"

参考:

BGPモードのkube-vip設定

BGPモードを有効化した上で、自身のAS番号と接続先のBGPルーターの情報を定義し、ルート情報を広告する経路を確立しています。

group_vars/k8s_cluster/k8s-cluster.yml
kube_control_plane_vip: "192.168.0.10"
kube_vip_address: "192.168.0.10"
kube_vip_enabled: true
kube_vip_controlplane_enabled: true
kube_vip_interface: "ens18"
kube_vip_arp_enabled: false
kube_vip_bgp_enabled: true
kube_vip_local_as: 65000
kube_vip_bgp_peeras: 65001
kube_vip_bgppeers:
  - "192.168.0.9:65001::false" # BGPルーターを指定

BGPルーター側のFRR設定は主に以下のようになります。

  • ルーターの設定
    • ルーター自身のAS番号(65001)と、識別用のID(192.168.0.9)を設定します。
  • ピア登録
    • 3台のMaster Node(AS 65000)を通信相手として登録し、ルート情報を受け取れるようにします。
  • ECMP有効化
    • VIPに対して最大3つまでの経路を同時に使用することを許可し、複数のノードを等価に扱うようにしています。
/etc/frr/frr.conf
frr version 8.4.4
frr defaults traditional
hostname bgp-route
log syslog informational
no ipv6 forwarding
service integrated-vtysh-config
!
router bgp 65001
 bgp router-id 192.168.0.9
 no bgp ebgp-requires-policy
 no bgp hard-administrative-reset
 no bgp graceful-restart notification
 neighbor 192.168.0.11 remote-as 65000
 neighbor 192.168.0.12 remote-as 65000
 neighbor 192.168.0.13 remote-as 65000
 !
 address-family ipv4 unicast
  maximum-paths 3
  bgp bestpath as-path multipath-relax
 exit-address-family
exit

ARPモードでの動作確認

冗長性について

現在、k8s-master-3がleaderとなっていることがわかります。

ryu@k8s-master-3:~$ ip addr show ens18
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether bc:24:11:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    altname enp0s18
    inet 192.168.0.13/24 metric 100 brd 192.168.0.255 scope global dynamic ens18
       valid_lft 106063sec preferred_lft 106063sec
    inet 192.168.0.10/32 scope global ens18
       valid_lft forever preferred_lft forever

ここで、leaderであるk8s-master-3のVMをShutDownしてみます。この時、leaderが死んでいるものの、kubectlは継続することが確認できます。

$ kubectl get nodes
NAME           STATUS     ROLES           AGE   VERSION
k8s-master-1   Ready      control-plane   47h   v1.34.2
k8s-master-2   Ready      control-plane   47h   v1.34.2
k8s-master-3   NotReady   control-plane   42h   v1.34.2
k8s-worker-1   Ready      <none>          42h   v1.34.2
k8s-worker-2   Ready      <none>          42h   v1.34.2
k8s-worker-3   Ready      <none>          42h   v1.34.2
k8s-worker-4   Ready      <none>          42h   v1.34.2

また、VIPがk8s-master-2に移動しleaderが交代したことがわかります。

ryu@k8s-master-2:~$ ip addr show ens18
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether bc:24:11:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    altname enp0s18
    inet 192.168.0.12/24 metric 100 brd 192.168.0.255 scope global dynamic ens18
       valid_lft 208844sec preferred_lft 208844sec
    inet 192.168.0.10/32 scope global ens18
       valid_lft forever preferred_lft forever

また、k8s-master-1にはVIPが割り当てられていません。

ryu@k8s-master-1:~$ ip addr show ens18
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether bc:24:11:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    altname enp0s18
    inet 192.168.0.11/24 metric 100 brd 192.168.0.255 scope global dynamic ens18
       valid_lft 258729sec preferred_lft 258729sec

このことから、Control Plane冗長化により、apiserverが1台死んでもleaderが交代し新たにVIPを割り当て直すことで動作を継続できていることが確認できました。

L2ブロードキャスト

leaderであるk8s-master-2についてVIPが付与されていることを確認します。

ryu@k8s-master-2:~$ ip addr show ens18
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether bc:24:11:10:ab:cd brd ff:ff:ff:ff:ff:ff
    altname enp0s18
    inet 192.168.0.12/24 metric 100 brd 192.168.0.255 scope global dynamic ens18
       valid_lft 207619sec preferred_lft 207619sec
    inet 192.168.0.10/32 scope global ens18
       valid_lft forever preferred_lft forever

leaderであるk8s-master-2のノードがVIP(192.168.0.10)を保持しており、そのMACアドレスであるbc:24:11:10:ab:cdであることを、自ノードから送信されているARP Request/ReplyによりL2でブロードキャストしていることがわかります。

これにより、同一L2ネットワークの各ノードが、VIP宛の通信をleaderのk8s-master-2のMACアドレスに流せば良いという判断ができるようになります。

ryu@k8s-master-1:~$ sudo tcpdump -i ens18 -nne arp
08:06:04.451726 bc:24:11:10:ab:cd > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: Request who-has 192.168.0.10 (ff:ff:ff:ff:ff:ff) tell 192.168.0.10, length 46
08:06:07.472682 bc:24:11:10:ab:cd > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: Reply 192.168.0.10 is-at bc:24:11:10:ab:cd, length 46

BGPモードでの確認

学習経路の確認

Master Nodeが落ちた際に動作を継続できる点についてはARPモードと同様なので、割愛します。ここではBGPルーターが各Master Nodeから広告された経路情報を学習できている点を確認したいと思います。

BGPルーターのルートテーブルを確認すると、経路の学習を行なっていることがわかります。nexthopが3つ並んでおり、通信が1台に偏らず、3台のMaster Nodeに分散されることが確認できます。1台のMaster Nodeが故障したとしても残りの2台で処理を継続することができ、高可用性が維持されます。

ryu@bgp-router:~$ ip route show 192.168.0.10
192.168.80.10 nhid 20 proto bgp metric 20 
	nexthop via 192.168.0.11 dev ens18 weight 1 
	nexthop via 192.168.0.12 dev ens18 weight 1 
	nexthop via 192.168.0.13 dev ens18 weight 1 

また、全Master NodeとBGPルーター間でBGPセッションが確立され、VIPの広告が正常に受信できていることが確認できます。

ryu@bgp-router:~$ sudo vtysh -c "show ip bgp summary"

IPv4 Unicast Summary (VRF default):
BGP router identifier 192.168.80.16, local AS number 65001 vrf-id 0
BGP table version 2
RIB entries 1, using 192 bytes of memory
Peers 3, using 2172 KiB of memory

Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
192.168.0.11   4      65000        34        35        0    0    0 00:05:18            1        1 N/A
192.168.0.12   4      65000        33        34        0    0    0 00:05:02            1        1 N/A
192.168.0.13   4      65000        32        32        0    0    0 00:04:53            1        1 N/A

まとめ

今回はkube-vipのARPモード及びBGPモードを用いたHA Control PlaneなKubernetesクラスタをkubesprayを用いて構築し、実際の動作について確認を行いました。
この記事が参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?