インフラ

MetalLBとは?ベアメタルKubernetesでLoadBalancerを使う仕組みとL2・BGPの選び方

オンプレミスに立てたKubernetesクラスタで、ServiceのtypeをLoadBalancerにしたままEXTERNAL-IPがpendingから動かない。この詰まりは設定ミスではなく、IPを配る担当者がクラスタに居ないという構造そのものです。MetalLBはその担当者を後から置く実装で、標準的なARPとBGPだけでVIPを外へ知らせます。仕組みと制約、採るべき場面と採るべきでない場面を実装目線で整理します。

まとめ:MetalLBが解決する問題とL2・BGPの選び分け

MetalLBは、クラウドプロバイダー統合を持たないKubernetesクラスタでtype LoadBalancerのServiceへExternal IPを割り当て、そのIPを外部へ知らせるコンポーネントです。IP在庫を管理するcontroller(Deployment)と、経路を広告するspeaker(DaemonSet)の2つで構成されます。

広告方式は2つです。L2モードでは1台のノードがVIPを引き受け、ARPまたはNDPで応答します。追加機材は不要ですが、そのServiceの受信帯域は単一ノードの帯域が上限になります。一方のBGPモードは各ノードがルーターとBGPで話し、ECMPで複数ノードへ分散する方式。帯域は伸びる代わりに、ノード構成が変わるとルーター側のハッシュが揺れて既存接続の大半が切れます。

選び分けの起点は、BGPを話すルーターが手元にあるかどうかです。無ければL2モード一択で、1Serviceあたりの受信トラフィックが単一ノードのNIC帯域に収まるかを先に見積もってください。なお0.16.0(2026年5月20日リリース)でBGPバックエンドの既定がFRR-K8sへ移り、旧FRRモードは非推奨になりました。

MetalLBが必要になる理由|オンプレでExternal IPが割り当たらない仕組み

まず、なぜクラウドでは動くものがオンプレで止まるのかを押さえます。

クラウド統合が無い環境でExternal IPがpendingのまま残る理由

type LoadBalancerというServiceは、それ自体がロードバランサーを作る機能ではありません。「外部のロードバランサーを1台用意してこのServiceへ向けてほしい」という要求を出すだけの仕組みです。実物を作るのはクラウドプロバイダー側のコントローラーで、AWSならNLBやALB、Google CloudやAzureなら各社のロードバランサーが払い出されます。

ベアメタルや自前の仮想基盤にはその受け手が居ません。要求は宙に浮き、Serviceのステータスはpendingで固定されます。エラーではなく、応答者不在の状態が続いているだけです。L4とL7で振り分け方式がどう違うかという前提はロードバランサーの仕組みと種類・振り分け方式の解説で整理しています。

MetalLBはこの受け手の役を引き受け、渡されたIPレンジから未使用の1つを選んでServiceへ書き戻します。専用ハードウェアもクラウドAPIも使わず、ARPとBGPという既存のネットワーク機構だけで完結させる点が設計の芯です。

controller Deploymentとspeaker DaemonSetの分担

controllerはクラスタに1つだけ動くDeploymentで、Serviceの監視とIPの割り当て・回収を担います。どのServiceにどのIPを渡したかという在庫管理がその仕事です。

speakerは全ノードに配られるDaemonSetで、割り当て済みのIPを外部へ広告します。ARPに応答するのも、ルーターとBGPセッションを張るのもこちら。ネットワーク名前空間へ直接触れるため、Kubernetes 1.23以降ではspeakerを動かす名前空間にprivilegedのPod Security設定が要ります。

この分離が切り分けの順序を決めます。IPが割り当たっているのに疎通しないならspeaker側、そもそもEXTERNAL-IPが埋まらないならcontroller側かIPAddressPoolの設定、という順で当たってください。

NodePort・Ingress・MetalLBの守備範囲はどこで分かれるか

NodePortは全ノードの同一ポートを開ける仕組みで、追加コンポーネントなしで外から届きます。ただしポート番号は30000番台に固定され、接続先ノードが落ちたときの切り替えは利用者側の責任。前段に何も置かない構成は検証環境までが現実的な範囲です。

MetalLBが担うのはL4、つまりIPとポートの層です。VIPを1つ払い出し、そのVIPへ来たトラフィックをkube-proxyがPodへ振り分けます。HTTPのホスト名やパスで振り分けたいならL7のIngressコントローラーが要り、そこはMetalLBの担当外。退役したingress-nginxとF5版NGINX Ingress Controllerの違いと移行判断で扱っているコントローラー選定は、MetalLBと競合せず上下に積む関係になります。

L2モードの仕組み|ARP応答でVIPを引き受けるノードの決まり方

追加機材が不要なL2モードから見ていきます。

speakerのリーダー選出がノード名のハッシュだけで決まる仕組み

L2モードでは、あるVIPについて1台のノードだけが「そのIPは自分が持っている」とARP(IPv6ではNDP)で答えます。外から見ると、そのノードのNICに複数のIPが付いているように見える状態です。

誰が名乗るかは投票でもリース取得でもありません。各speakerが「ノード名とVIPの組」のハッシュを計算してソートし、自分が先頭なら名乗り出るだけです。全speakerが同じ入力から同じ順序を導くため、どのIPを誰が持つかを記録する必要がなく、外部の合意ストアなしで動きます。VIPが複数あればノードごとにばらけますが、これはVIP単位の分散であって、1つのVIPへのトラフィックが分散するわけではない点に注意してください。

L2モードの帯域が単一ノードで頭打ちになる構造上の制約と回避策

L2モードで最初に効いてくる制約がこれです。1つのService IP宛のトラフィックはすべて1台のノードに入るため、そのServiceの受信帯域は引き受けノード1台のNIC帯域を超えられません。公式ドキュメントもARPとNDPでトラフィックを誘導する方式の原理的な限界だと明記しています。

Podを何十個に増やしても入口の帯域は変わりません。入った後の分散はkube-proxyのiptablesまたはIPVSが担うためCPU負荷は散りますが、詰まるのは入口のNICです。

回避の手は3つあります。Serviceを分けてVIPを複数に割りノードをばらけさせるか、引き受けノードのNICをボンディングで太らせるか、BGPモードへ移るか。1Gbps環境で数百Mbpsを恒常的に流すなら、設計時点でどれを採るか決めておいてください。

memberlistの死活検知とGARPで数秒に収まるフェイルオーバー

speaker同士はmemberlistプロトコルで互いの死活を見張っており、この通信にはノード間のTCPとUDPの7946番が開いている必要があります。ファイアウォールでこのポートが塞がれていると、平常時は動くのに障害時だけ切り替わらないという厄介な症状につながる点に注意してください。

離脱が検知されると、ハッシュ順で次のノードが名乗り出ます。新しい引き受け手はgratuitous ARP(またはNDPのUnsolicited Neighbor Advertisement)を送り、周囲の機器にMACアドレスの変更を通知する流れです。公式によれば多くのOSはこの通知を正しく扱い、その場合フェイルオーバーは数秒で完了します。

逆に言えば、通知を無視して近隣キャッシュを保持する古い機器が経路上に居ると、キャッシュが切れるまで通信が戻りません。数秒という数字を設計の前提に置くなら、その環境で1台落として実測した値を使ってください。

BGPモードの仕組み|ECMPで複数ノードに分散する構成と接続断のリスク

帯域の頭打ちを外すのがBGPモードですが、別種の制約と引き換えになります。

ホスト単位の経路広告とECMPハッシュ変化で既存接続が切れる理由

BGPモードでは、各ノードのspeakerが外部ルーターとBGPセッションを張り、VIPをホスト単位の経路として広告します。ルーターから見ると同じ宛先への等コスト経路が複数ノード分あるため、ECMPで振り分けられる形です。入口の帯域はノード台数分に伸びます。

問題はECMPの振り分けがハッシュ計算に依るところです。公式ドキュメントは、BGPベースの負荷分散はバックエンド集合の変化に優雅に追随できないと明言しています。ノードが1台増減すると経路数が変わり、ハッシュの割り当て先がまとめてずれてしまう点が厄介です。パケットが落ちるわけではないのに、確立済みのTCP接続の大半が別ノードへ飛んで切断されるという壊れ方をします。

公式が挙げる緩和策は5つです。安定ハッシュを持つECMP実装のルーターを使う、Podの配置をノードに固定する、変更作業を低トラフィック時間帯へ寄せる、クライアント側にリトライを実装する、ステートフルなIngressコントローラーを前段に置いて接続断を吸収させる。5つめは実質的に「MetalLBのVIPはIngress用の1本に絞る」構成で、多くの現場の現実解になります。

0.16.0でFRR-K8sが既定になりFRRモードが非推奨になった経緯

BGPの実装系統は歴史的に3つありました。MetalLB自前のネイティブ実装、FRRoutingを同居させるFRRモード、FRR-K8sという別プロジェクトへBGP制御を委ねるモードです。2026年5月20日リリースの0.16.0で既定のバックエンドがFRR-K8sへ移り、FRRモードは非推奨となりました。当面は動きますが将来的に削除される位置づけです。

FRR系ではネイティブ実装で持てないBFDセッションとの併用やIPv6アドレスの広告が可能になり、BFDを併用するとBGPのタイマーより速く障害を検知できます。

0.16.0には設定に効く変更が他にもあります。ピアごとにAS番号を上書きするlocalASNフィールドが入り、広告リソースにServiceSelectorが追加されました。あわせてkube-rbac-proxyが自前実装へ置き換わり、メトリクスのエンドポイントは自己署名証明書によるHTTPS配信のみになっています。これは破壊的変更で、Prometheusのスクレイプ設定を直さないと上げた瞬間にメトリクスが取れなくなります。事前にscrape_configsのschemeとtls_configを確認してください。

BGPセッションを張れないネットワークでBGPモードを諦める判断

BGPモードは前提が重い方式です。BGPを話せるルーターが1台以上必要で、その設定を変更できる権限も要ります。機器の管理が別部門や外部ベンダーにある環境では、AS番号の採番とピア設定の依頼だけで数週間かかることも珍しくありません。

FRR系バックエンドには構成上の制約もあります。routerIDとmyAsnの値は全BGP広告で揃っている必要があり、多ホップのeBGPピアにはebgp-multihopの明示が要ります。ノードと同一ホスト上のピアリングは非対応。ルーターが論理的に離れた構成では、ここで詰まります。

判断はこう置いてください。BGPの設定変更を自分たちの裁量で回せないなら、BGPモードは選ばない。それでL2の帯域が足りないなら、MetalLBではなく物理ロードバランサーやクラウド移行を含めて構成そのものを見直すほうが早く着地します。

設定リソースの書き方|IPAddressPoolと広告リソースの分離

MetalLBはインストールしただけでは何もしません。設定を投入して初めて動き出します。

IPAddressPoolでIP範囲を、広告リソースで出し方を決める

設定はすべてMetalLB自身と同じ名前空間(既定ではmetallb-system)に置くカスタムリソースで行います。かつてのConfigMapに全設定を詰め込む形式は姿を消しました。古い記事のYAMLをそのまま貼っても通らないので注意してください。

役割は2階建てです。IPAddressPoolが「どのIPを配ってよいか」を、L2AdvertisementまたはBGPAdvertisementが「そのプールをどう外へ知らせるか」を定義します。プールを作っただけでは広告されず、EXTERNAL-IPは埋まっても疎通しません。別リソースに分かれているため、同じプールをL2とBGPで出し分けることもできます。最小構成は次の形です。

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: pool-office
  namespace: metallb-system
spec:
  addresses:
  - 192.168.10.200-192.168.10.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-office
  namespace: metallb-system
spec:
  ipAddressPools:
  - pool-office

IPAddressPool・L2Advertisement・BGPAdvertisementはmetallb.io の v1beta1、BGPPeerだけがv1beta2で、こちらのv1beta1は非推奨です。BGPPeerのマニフェストをコピーしてくる際は、apiVersionの版が古くないかを毎回確かめてください。

0.15と0.16で入ったServiceSelectorとlocalASNの使いどころ

直近2版で入った機能は、複数チームが1クラスタを共有する構成で効きます。

0.16.0の広告リソースに追加されたServiceSelectorは、ラベルでServiceを絞り込み、条件に合うものだけを広告対象にします。同じIPAddressPoolを共有しつつ、あるチームのServiceだけ別のBGPピアへ流す出し分けが1つのプールで書ける形です。同じく0.16.0のlocalASNは、ピアごとにこちら側のAS番号を上書きするフィールドで、データセンターごとにAS番号が違う構成でもピア定義を分けずに済みます。

0.15系では可観測性が伸びました。IPAddressPoolのstatusに割り当て数のカウンタが載り、在庫の残りをkubectlだけで見られます。ServiceBGPStatusは、あるServiceがどのピアへ広告されているかを表す状態リソースです。BGPモードで「このServiceだけ届かない」という切り分けをするとき、ルーター側のshowコマンドを見に行く前にクラスタ内で確認できます。unnumbered BGPとprefer-dual-stackのIPファミリーポリシーも同系で入りました。

新規構築でいきなり全部を使うものではありません。ただしIPAddressPoolのstatusだけは監視に組み込む価値があり、在庫が尽きてServiceがpendingへ戻る事故を先に検知できます。

導入前に潰す前提条件|strictARP・ServiceLB・メトリクスのHTTPS化

第一に、kube-proxyをIPVSモードで動かしている場合は、Kubernetes v1.14.2以降strictARPをtrueにする必要があります。kube-proxyのConfigMapを編集して有効化してください。kube-routerをサービスプロキシに使っている環境は既定で有効なため作業不要です。

第二に、k3sで構築したクラスタには標準でServiceLB(Klipper)が入っています。type LoadBalancerのServiceを監視してkube-system名前空間にsvc-接頭辞のDaemonSetを作る仕組みで、MetalLBと役割が正面衝突します。全serverノードに --disable=servicelb を渡して無効化してから入れてください。

第三に、0.16.0以降を入れるならメトリクスがHTTPS配信のみになる点を監視担当と先に共有してください。設定を直さないまま上げると監視が静かに止まります。クラスタ内のServiceやPod間通信との噛み合わせはKubernetesネットワーク設計におけるService・Ingress・CNI選定の判断で扱っています。

代替手段との比較|Cilium LB IPAM・kube-vip・ServiceLB

同じ穴を埋める手段はMetalLBだけではありません。

Cilium LB IPAMへ寄せるとコントローラーを1つ減らせる

CNIにCiliumを採っているなら、LB IPAMという機能で同じことができます。CiliumLoadBalancerIPPoolというカスタムリソースにIPレンジを書くと、type LoadBalancerのServiceへIPが割り当てられる仕組みです。広告はCilium BGP Control Planeを使うBGP方式か、L2 Announcements(ベータ扱い)によるローカル広告のどちらかで、Serviceのspec.loadBalancerClassにio.cilium配下の値を指定して切り替えます。

利点は運用対象のコンポーネントが1つ減ることです。CNIとロードバランサー機能が同じデータプレーンに載るため、eBPFのトレーシングで一貫して追えます。eBPFベースのCilium CNIの仕組みとCalico比較で扱っているとおりCilium自体の学習コストは低くありませんが、既に入れているならMetalLBを追加せずLB IPAMを有効化する判断が素直です。

逆にCNIがCalicoやFlannelなら、この選択肢のためにCNIを入れ替える理由にはなりません。CNI移行はクラスタ全体の通信断を伴う作業で、ロードバランサー機能の一本化という動機だけでは釣り合わないためです。

代替4種の比較表|対応モード・前提CNI・IPv6対応と運用主体

判断に効く軸だけで並べます。

手段 広告方式 前提 向く規模
MetalLB L2・BGP CNI非依存 小〜大
Cilium LB IPAM L2(ベータ)・BGP CNIがCilium 中〜大
kube-vip ARP・BGP 制御プレーンVIP兼用 小〜中
k3s ServiceLB ノードIP直結 k3s標準搭載 検証・小規模

kube-vipは制御プレーンのVIP提供が本来の用途で、Service向けの機能も持ちます。すでにkube-vipでAPIサーバーのVIPを組んでいるなら、そこへ寄せるとコンポーネントが増えません。k3s ServiceLBは各ノードのIPをそのまま返す方式で、専用VIPが要らない検証環境では十分に働きます。

CNIを問わずL2とBGPの両方を素直に扱え、情報量も多いという点で、MetalLBは既定の選択肢に置けます。既にCiliumかkube-vipが入っている場合だけ、そちらへ寄せる判断を先に検討してください。

MetalLBを採用してよい条件と、採るべきでない3つの場面の線引き

ここからは条件を示したうえで結論を書きます。

L2モードで足りる条件とBGPモードへ進むべき条件を数値で示す

L2モードで足ります。該当するのは、type LoadBalancerのServiceが概ね10個以内、1つのVIPへの受信トラフィックのピークがノード1台のNIC帯域の3割以下に収まる、ノード障害時の数秒の断が業務上許容できる場合です。この条件ならルーター設定への依頼が発生せず、YAMLを2枚投入すれば当日中に動きます。

BGPモードへ進んでください。該当するのは、1つのVIPへの受信トラフィックが単一ノードのNIC帯域の半分を恒常的に超える、またはBGPを話すルーターと設定権限が自チームの手元にあり入口の可用性をノード台数分に伸ばしたい場合です。この場合はFRR-K8sバックエンドを既定のまま使い、BFD併用まで含めて設計してください。

逆に見送るべき組み合わせもあります。帯域は足りているのに冗長性のためだけにBGPモードを選ぶ構成は勧めません。ECMPハッシュの揺れで既存接続が切れる副作用のほうが、L2の数秒フェイルオーバーより体感の劣化が大きくなるためです。冗長性が目的なら、L2モードのままIngressコントローラーを前段に置き、その配下でPodを冗長化するほうが効きます。

MetalLBを採るべきでない3つの場面と、代わりに置く手段の選び方

採らないほうがよい場面は3つです。1つめは、クラウドのマネージドKubernetesで動かしている場合。EKSやGKE、AKSにはクラウド側のロードバランサー統合が既にあり、MetalLBを重ねる理由がありません。ハイブリッド構成でオンプレ側クラスタにだけ入れる形が正解です。

2つめは、CNIにCiliumを採っている場合。前述のLB IPAMで同じことができ、運用対象を増やさずに済みます。3つめは、そのクラスタが単一ノードか検証専用の場合。NodePortかk3s標準のServiceLBで足り、VIPを配る意味がありません。

加えて、配るIPレンジをネットワーク管理部門と合意できていない状態での導入も避けてください。既存のDHCPスコープや静的割り当てと重なったMetalLBのIPは、同じIPを別の機器も主張する状態を生み、断続的にしか繋がらないという最も追いにくい障害になります。レンジの確保が先で、インストールは後です。

オンプレKubernetes基盤の構築を委託するとき確認すべき5点

社内に手が空かず外部へ出す場合、見積書で確認すべき項目は決まっています。払い出すIPレンジの確保を誰がネットワーク側と調整するか。L2とBGPのどちらを前提にした金額か(BGPならルーター設定作業が含まれるか)。ノード障害時のフェイルオーバー時間を実測して報告するか。IPAddressPoolの在庫枯渇を監視項目に含めるか。そしてMetalLBの版上げ方針、とりわけ0.16.0のメトリクスHTTPS化のような破壊的変更を誰が追跡するか。

この5点が曖昧なまま総額だけ提示された見積もりは、ネットワーク調整と監視設定が「追加作業」として後から積み上がりがちです。オンプレとクラウドをまたぐKubernetes基盤の設計から構築・監視までを相談したい場合は、AWS・Google Cloud・Azureのインフラ構築支援で現行構成の棚卸しから対応しています。

よくある質問

MetalLBの仕組みと採用判断について、検索で頻出する質問に答えます。

MetalLBはベータ版と書かれていますが本番で使えますか?

公式サイトはプロジェクトとAPIがベータ扱いであると断ったうえで、MetalLBは安定して信頼できることが知られていると記しています。実運用の採用例も多く、ベータという表記だけを理由に外す判断にはなりません。ただしBGPPeerがv1beta1からv1beta2へ移ったようにAPIの版は動いており、版上げの際はapiVersionを確認する運用が要ります。

L2モードとBGPモードは同じクラスタで併用できますか?

できます。IPAddressPoolと広告リソースが分離されているため、プールAをL2Advertisementで、プールBをBGPAdvertisementで出す構成が書けます。管理用の小さなServiceはL2で、トラフィックの大きい入口はBGPでという使い分けが可能です。ただしBGPを使う時点でルーター設定の前提は発生します。

MetalLBを入れるとNodePortは使えなくなりますか?

使えます。MetalLBはtype LoadBalancerのServiceにExternal IPを配るだけで、NodePortの仕組みには手を触れません。type LoadBalancerのServiceにもNodePortは内部的に割り当てられ続けます。既存のNodePort運用を残したまま段階的にLoadBalancerへ移す進め方が取れます。

MetalLBのVIPへ疎通しないとき何から見ればよいですか?

順序があります。まずServiceのEXTERNAL-IPが埋まっているかを見て、pendingならcontroller側かIPAddressPoolの範囲不足です。埋まっているなら次にL2AdvertisementまたはBGPAdvertisementの有無を確認します。両方あるのに届かない場合はspeaker側で、L2モードならノード間のTCP・UDP 7946番の開放とIPVS利用時のstrictARP設定、BGPモードならピアの確立状態を順に見ます。

MetalLBとIngressコントローラーはどちらも必要ですか?

役割が別なので、HTTPをホスト名やパスで振り分けるなら両方が要ります。MetalLBはL4でVIPを1つ払い出し、IngressコントローラーはそのVIPで受けたHTTPをL7で振り分ける関係です。実際にはIngressコントローラーのServiceをtype LoadBalancerにしてVIPを1つだけ受け取る構成が定番で、MetalLBが配るIPは1個で済みます。

関連記事

資料請求

RELATED POSTS 関連記事