2026年6月4日
2026年6月4日
MetalLBでAuto Scalingと連携する方法|HPA・ノード増減に追従させる設定と注意点
MetalLB自体には台数を増減する機能はありませんが、Podの自動スケール(HPA)やノードの自動追加と組み合わせると、増えたPodやノードへ通信を振り分ける入口として働きます。ポイントは、L2モードでは入口が1台のノードに集中するため、スケールアウトの効果を入口まで広げたい場合はBGPモードを選ぶこと、そして externalTrafficPolicy と広告するノードの範囲を意図して決めることです。この記事では、MetalLBとAuto Scalingの関係、モード別の挙動、設定例、増減時のつまずきと確認方法を説明します。
MetalLBとAuto Scalingの役割分担
オンプレミスや自前のVPSで動かすKubernetesには、クラウドのようなロードバランサーがありません。MetalLBは、type: LoadBalancer のServiceに外部IPアドレスを割り当て、そのアドレスへの通信をクラスタのノードに届ける役割を持ちます。
Auto Scalingに関わる仕組みは、主に次の3つです。
- HPA(Horizontal Pod Autoscaler): CPU使用率などに応じてPodの数を増減する
- ノードの自動増減: Cluster AutoscalerやCluster APIなどでノードを追加・削除する(ベアメタルでは、ノードを自動で用意できる基盤がある場合に限られます)
- MetalLB: Serviceの外部IPを、どのノードから広告するかを管理する
HPAでPodが増えると、ServiceのエンドポイントにそのPodが自動で加わり、kube-proxy(またはCNIの代替実装)が振り分けます。MetalLBの設定を変える必要はありません。ノードが増えた場合も、MetalLBのspeakerはDaemonSetとして動くため、新しいノードにも自動で配置されます。つまり「連携」の多くは自動で起きますが、その結果どこに負荷が集まるかはモードと設定で大きく変わります。
L2モードとBGPモードでの違い
L2モード
L2モードでは、Serviceごとに選ばれた1台のノードが、外部IPへのARP(IPv6ではNDP)に応答します。外部からの通信はすべてそのノードに入り、そこからPodへ転送されます。
Podをいくら増やしても、入口のノードの帯域や処理能力は1台分のままです。小〜中規模のWordPressなど、入口の帯域が問題にならない用途では十分ですが、通信量そのものが増えてスケールしたい場合はボトルネックになります。担当ノードが落ちると別のノードが引き継ぎますが、切り替わるまでの数秒間は通信が途切れることがあります。
BGPモード
BGPモードでは、各ノードのspeakerがルーターとBGPで接続し、外部IPへの経路を広告します。ルーターがECMP(等コストマルチパス)に対応していれば、通信は複数のノードに分散されます。ノードが増えると新しいノードも経路を広告し、入口の数も増えます。
ただし、ノードが追加・削除されるとルーター側のハッシュ計算が変わり、既存の接続が別のノードに振り直されて切れることがあります。長時間の接続(WebSocketや大きなファイルのダウンロード)が多いサービスでは、この影響を考慮します。
externalTrafficPolicyの選び方
Serviceの externalTrafficPolicy は、スケール時の挙動に直接影響します。
Cluster(既定): どのノードに届いた通信も、クラスタ内のいずれかのPodへ転送します。分散は均等になりやすい一方、ノード間の転送が増え、送信元IPがノードのものに置き換わりますLocal: 通信を受けたノード上のPodにだけ転送します。送信元IPが保たれ、余分な転送もありません。MetalLBは、準備ができたPodがあるノードからだけ広告します
Local では、HPAでPodが増えたノードが広告に加わり、Podがいなくなったノードは広告から外れます。Podの配置が偏ると負荷も偏るため、Podをノードに分散させる設定(topologySpreadConstraints など)と組み合わせます。WordPressのログやセキュリティ系のプラグインで閲覧者のIPアドレスを使いたい場合は、Local にするか、前段のIngressコントローラーで実IPを引き継ぐ設定が必要です。
設定例
MetalLB v0.13以降は、設定をカスタムリソース(CRD)で書きます。まずIPアドレスの範囲を定義します。HPAでPodが増えてもServiceの数は変わらないため、アドレスはServiceの数だけあれば足ります。
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: public-pool
namespace: metallb-system
spec:
addresses:
- 192.0.2.240-192.0.2.250
BGPモードでは、ピア(ルーター)と広告の設定を追加します。nodeSelectors を使うと、広告するノードを絞れます。自動で増減するノードに入口を任せたくない場合は、入口専用のラベルを付けたノードだけを指定します。
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
name: upstream-router
namespace: metallb-system
spec:
myASN: 64500
peerASN: 64501
peerAddress: 192.0.2.1
---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
name: public-adv
namespace: metallb-system
spec:
ipAddressPools:
- public-pool
nodeSelectors:
- matchLabels:
node-role.example.com/ingress: "true"
ASN(64500など)とアドレスは例です。ルーター側の設定と合わせて書き換えてください。最後に、ServiceとHPAを用意します。HPAがCPU使用率を見るには、metrics-serverなどのメトリクス基盤と、Podの resources.requests の指定が必要です。
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app: wordpress
ports:
- port: 80
targetPort: 80
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: wordpress
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: wordpress
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
実際の構成では、MetalLBのIPをIngressコントローラーのServiceに割り当て、その背後のWordPressをHPAで増減させる形が一般的です。WordPressを複数Podで動かす場合は、アップロードファイルを共有ストレージやオブジェクトストレージに置き、セッションやキャッシュがPodごとに分かれないようにしておく必要があります。
スケール時につまずきやすい点と確認方法
設定変更は、ステージング用のクラスタで試してから本番に入れます。うまく振り分けられないときは、次の順に確認します。
- 外部IPが割り当てられているか:
kubectl get svcでEXTERNAL-IPが<pending>のままなら、IPアドレスプールが無い・使い切った・Serviceの指定と合っていない、のいずれかです - どのノードが広告しているか:
kubectl describe svc wordpressのイベントに、MetalLBが割り当てやノードの情報を出します。speakerのログも確認します - Podが準備完了になっているか:
Localでは、readinessProbeに合格したPodがあるノードだけが広告します。HPAで増えた直後のPodが準備中だと、そのノードには通信が来ません - ノード削除時の切断: ノードを削除する前に
kubectl drainでPodを退避させると、Podの移動と広告の取り下げが順に進み、切断を減らせます
kubectl get ipaddresspools -n metallb-system
kubectl get pods -n metallb-system -o wide
# speaker のログ(ラベルはインストール方法によって異なります)
kubectl logs -n metallb-system -l component=speaker --tail=50
CRDの apiVersion や設定項目はバージョンで変わることがあるため、使っているMetalLBのバージョンの公式ドキュメントと照らし合わせてください(2026年10月現在)。
まとめ
- MetalLBは台数を増減しないが、HPAで増えたPodや追加されたノードには自動で追従する
- L2モードは入口が1台に集中する。入口ごとスケールさせたいならECMP対応ルーターとBGPモード
externalTrafficPolicy: Localは送信元IPを保てるが、Podの偏りがそのまま負荷の偏りになる- 広告するノードは
nodeSelectorsで意図して決め、ノード削除前はdrainする - WordPressを複数Podにするなら、共有ストレージとキャッシュ・セッションの扱いも合わせて整える