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?

ConoHa VPS の2ノードKubernetesにMetalLBを導入してIngressをLoadBalancer化した話

0
Posted at

はじめに

クラウド管理型のKubernetes(GKEやEKSなど)では type: LoadBalancer のServiceを作成するだけで外部IPが自動的に割り当てられます。しかしConoHa VPSのようなベアメタル環境では、そのままでは EXTERNAL-IP が永遠に <pending> のままになってしまいます。

今回はConoHa VPS上の2ノード構成KubernetesMetalLBを導入し、Nginx Ingressを LoadBalancer タイプで外部公開するまでの手順をまとめます。


環境

ノード IPアドレス 役割
Control Plane 203.0.113.X コントロールプレーン(Pod展開も可能)
Worker Node 203.0.113.Y ワーカー専用
  • Kubernetes v1.28
  • MetalLB v0.14.5
  • Nginx Ingress Controller

MetalLBとは

MetalLBはベアメタル環境向けのロードバランサー実装です。クラウド環境が提供するLB機能をソフトウェアで再現します。

動作モードは2種類あります。

  • L2モード:ARPでIPを宣伝する。シンプルで設定が簡単。VPS環境に向く
  • BGPモード:BGPプロトコルでルーターと通信する。本格的なオンプレ向け

今回はConoHa VPSのネットワーク構成に合わせてL2モードを採用します。


Step 1:MetalLBのインストール

ファイルをローカルに保存するとターミナルの制御文字が混入する場合があるため、URLから直接applyするのが確実です。

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

Podの起動を待ちます。

kubectl wait pod \
  -n metallb-system \
  --for=condition=Ready \
  --timeout=120s \
  -l app=metallb

2ノード構成では speaker が各ノードに1つずつ起動します。

kubectl get pods -n metallb-system -o wide
NAME                          READY   STATUS    NODE
controller-xxx                1/1     Running   control-plane
speaker-aaa                   1/1     Running   control-plane
speaker-bbb                   1/1     Running   worker

Step 2:kube-proxyのstrictARP設定

ipvs モードを使用している場合は strictARP: true が必要です。

kubectl edit configmap -n kube-system kube-proxy
mode: "ipvs"
ipvs:
  strictARP: true   # false → true に変更

iptables モードの場合はこの手順は不要です。


Step 3:IPAddressPoolの作成

両ノードのパブリックIPをプールに登録します。

# ip-pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: conoha-pool
  namespace: metallb-system
spec:
  addresses:
    - 203.0.113.X/32   # Control PlaneのパブリックIP
    - 203.0.113.Y/32   # Worker NodeのパブリックIP
kubectl apply -f ip-pool.yaml

Step 4:L2Advertisementの設定

どのノードがARP宣伝に参加するかを matchLabels で指定します。ここで matchLabels を省略すると unknown field エラーになるので注意が必要です。

# 実際のノード名を確認
kubectl get nodes
# l2-advertisement.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: conoha-l2adv
  namespace: metallb-system
spec:
  ipAddressPools:
    - conoha-pool
  nodeSelectors:
    - matchLabels:
        kubernetes.io/hostname: <control-planeのノード名>
    - matchLabels:
        kubernetes.io/hostname: <workerのノード名>
kubectl apply -f l2-advertisement.yaml

Step 5:Nginx Ingressのインストール

公式のmanifestをベースに spec.typeLoadBalancer に設定してapplyします。

curl -Lo deploy.yaml \
  https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/baremetal/deploy.yaml

取得したファイルを編集する際、よくある落とし穴が2つあります。

落とし穴1:type の大文字小文字

# NG
spec:
  type: loadBalancer

# OK
spec:
  type: LoadBalancer

落とし穴2:loadBalancerIP のフィールド名

# NG(大文字Lになってしまった場合)
spec:
  LoadBalancerIP: 203.0.113.Y

# OK
spec:
  loadBalancerIP: 203.0.113.Y

修正後にapplyします。

kubectl apply -f deploy.yaml

EXTERNAL-IPが割り当てられれば成功です。

kubectl get svc -n ingress-nginx ingress-nginx-controller
NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
ingress-nginx-controller   LoadBalancer   10.x.x.x        203.0.113.Y    80:xxxxx/TCP,443:xxxxx/TCP   20m

Step 6:ConoHaファイアウォールの設定

ここが2ノード構成で特に重要なポイントです。

MetalLBがWorker NodeのIPをEXTERNAL-IPとして選択した場合、Worker Node側のセキュリティグループにもポート開放が必要です。ConoHaのコントロールパネルで以下を確認・追加してください。

ノード 開放するポート プロトコル
Worker Node 80 TCP
Worker Node 443 TCP

今回はConoHaの「IPv4v6Web」セキュリティグループをWorker Nodeに適用することで解決しました。


Step 7:動作確認

テスト用アプリをデプロイします。

# test-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: hashicorp/http-echo
        args: ["-text=Hello from Ingress!"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: hello-svc
spec:
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 5678
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: 203.0.113.Y.nip.io   # EXTERNAL-IP(Worker NodeのIP)を使う
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hello-svc
            port:
              number: 80

host には必ずEXTERNAL-IP(MetalLBが割り当てたIP=Worker NodeのIP)を使います。Control PlaneのIPを指定するとルーティングが一致せずアクセスできません。独自ドメインがない場合は nip.io を使うとIPアドレスをそのままドメインとして利用できます。

kubectl apply -f test-app.yaml

# Ingressの状態確認
kubectl get ingress hello-ingress
NAME            CLASS   HOSTS                  ADDRESS        PORTS   AGE
hello-ingress   nginx   203.0.113.Y.nip.io     203.0.113.Y    80      1m
curl http://203.0.113.Y.nip.io/
# Hello from Ingress!

トラブルシューティングまとめ

今回の作業で遭遇したエラーと対処法です。

YAMLに制御文字が混入する

ターミナルからコピペしてYAMLを作成すると、ANSIエスケープシーケンス(^[[O など)が混入することがあります。URLから直接applyするか、curl でダウンロードするのが確実です。

# NG:ブラウザやターミナルからコピペして作成
# OK:curlで直接ダウンロード
curl -Lo manifest.yaml https://...
# または直接apply
kubectl apply -f https://...

spec.type: Unsupported value: "loadBalancer"

LoadBalancerL が小文字になっています。sed で一括修正できます。

sed -i 's/type: loadBalancer/type: LoadBalancer/g' deploy.yaml

unknown field "spec.LoadBalancerIP"

loadBalancerIPl が大文字になっています。前述の sed の副作用で起きがちです。

sed -i 's/LoadBalancerIP/loadBalancerIP/g' deploy.yaml

unknown field "spec.nodeSelectors[1].kubernetes.io/hostname"

nodeSelectors の書き方に matchLabels が抜けています。

# NG
nodeSelectors:
  - kubernetes.io/hostname: worker

# OK
nodeSelectors:
  - matchLabels:
      kubernetes.io/hostname: worker

まとめ

項目 ポイント
MetalLBモード L2モード(VPS環境に最適)
IPAddressPool 両ノードのIPを登録する
L2Advertisement matchLabels を忘れずに
EXTERNAL-IP Worker NodeのIPが割り当てられる
Ingressのhost EXTERNAL-IPに合わせる(Control PlaneのIPではない)
ファイアウォール EXTERNAL-IPのノード(Worker)側も開放が必要

2ノード構成ではどちらのノードがリーダーになるかがポイントです。MetalLBはL2モードでどちらかのノードをリーダーとして選出し、そのノードのIPをEXTERNAL-IPとして使います。リーダーノードがダウンした場合は自動でフェイルオーバーします(数秒の断が発生)。

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?