目次にジャンプページナビゲーションにジャンプ: 前のページ[アクセスキーp]/次のページ[アクセスキーn]
documentation.suse.com / SUSE Edgeドキュメント / ハウツーガイド / K3s上のMetalLB (L2を使用)

19 K3s上のMetalLB (L2を使用)

MetalLBは、標準のルーティングプロトコルを使用する、ベアメタルKubernetesクラスタ用のロードバランサの実装です。

このガイドでは、MetalLBをレイヤ2モードでデプロイする方法について説明します。

19.1 この方法を使用する理由

レイヤ2モードでは、1つのノードがローカルネットワークにサービスをアドバタイズする責任を負います。ネットワークの視点からは、マシンのネットワークインタフェースに複数のIPアドレスが割り当てられているように見えます。

レイヤ2モードの主な利点は、その汎用性です。あらゆるEthernetネットワークで動作し、特別なハードウェアも、高価なルータも必要ありません。

19.2 K3s上のMetalLB (L2を使用)

このクイックスタートではL2モードを使用するので、特別なネットワーク機器は必要なく、ネットワーク範囲内の空きIPをいくつか用意するだけで十分です。DHCPプール外のIPであれば割り当てられることがないため理想的です。

この例では、DHCPプールは、192.168.122.0/24のネットワークに対して192.168.122.100-192.168.122.200です(IPは3つです。余分なIPの理由については、「TraefikとMetalLB」 (19.3.3項 「TraefikとMetalLB」)を参照してください)。そのため、この範囲外であれば何でも構いません(ゲートウェイと、すでに実行されている可能性のある他のホストは除きます)。

19.3 前提条件

  • MetalLBがデプロイされるK3sクラスタ。

警告
警告

K3sには、Klipperという名前の独自のサービスロードバランサが付属しています。MetalLBを実行するにはKlipperを無効にする必要があります。Klipperを無効にするには、--disable=servicelbフラグを使用してK3sをインストールする必要があります。

  • Helm

  • ネットワーク範囲内の数個の空きIP (ここでは192.168.122.10-192.168.122.12)

19.3.1 デプロイメント

MetalLBはHelm (および他の方法)を利用するため、次のようになります。

helm repo add metallb https://metallb.github.io/metallb
helm install --create-namespace -n metallb-system metallb metallb/metallb

while ! kubectl wait --for condition=ready -n metallb-system $(kubectl get\
 pods -n metallb-system -l app.kubernetes.io/component=controller -o name)\
 --timeout=10s; do
 sleep 2
done

19.3.2 設定

この時点でインストールは完了しています。次に、サンプル値を使用して設定を行います。

cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: ip-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.122.10/32
  - 192.168.122.11/32
  - 192.168.122.12/32
EOF
cat <<-EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: ip-pool-l2-adv
  namespace: metallb-system
spec:
  ipAddressPools:
  - ip-pool
EOF

これで、MetalLBを使用する準備ができました。L2モードでは、次のようにさまざまな設定をカスタマイズできます。

また、BGPについても、さらに多くのカスタマイズが可能です。

19.3.3 TraefikとMetalLB

Traefikは、デフォルトではK3sとともにデプロイされます(--disable=traefikを使用してK3sを無効にできます)。また、デフォルトでLoadBalancerとして公開されます(Klipperで使用するため)。ただし、Klipperを無効にする必要があるため、Ingress用TraefikサービスはLoadBalancerタイプのままです。そのため、MetalLBをデプロイした時点では、最初のIPは自動的にTraefik Ingressに割り当てられます。

# Before deploying MetalLB
kubectl get svc -n kube-system traefik
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
traefik   LoadBalancer   10.43.44.113   <pending>     80:31093/TCP,443:32095/TCP   28s
# After deploying MetalLB
kubectl get svc -n kube-system traefik
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                      AGE
traefik   LoadBalancer   10.43.44.113   192.168.122.10   80:31093/TCP,443:32095/TCP   3m10s

これは、このプロセスの後半(19.4項 「IngressとMetalLB」)で適用されます。

19.3.4 使用法

デプロイメントの例を作成してみましょう。

cat <<- EOF | kubectl apply -f -
---
apiVersion: v1
kind: Namespace
metadata:
  name: hello-kubernetes
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: hello-kubernetes
  template:
    metadata:
      labels:
        app.kubernetes.io/name: hello-kubernetes
    spec:
      serviceAccountName: hello-kubernetes
      containers:
        - name: hello-kubernetes
          image: "paulbouwer/hello-kubernetes:1.10"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          env:
          - name: HANDLER_PATH_PREFIX
            value: ""
          - name: RENDER_PATH_PREFIX
            value: ""
          - name: KUBERNETES_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: KUBERNETES_POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: KUBERNETES_NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
          - name: CONTAINER_IMAGE
            value: "paulbouwer/hello-kubernetes:1.10"
EOF

最終的にサービスは次のようになります。

cat <<- EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes
  namespace: hello-kubernetes
  labels:
    app.kubernetes.io/name: hello-kubernetes
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: hello-kubernetes
EOF

実際の動作を見てみましょう。

kubectl get svc -n hello-kubernetes
NAME               TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
hello-kubernetes   LoadBalancer   10.43.127.75   192.168.122.11   80:31461/TCP   8s

curl http://192.168.122.11
<!DOCTYPE html>
<html>
<head>
    <title>Hello Kubernetes!</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>

  <div class="main">
    <img src="/images/kubernetes.png"/>
    <div class="content">
      <div id="message">
  Hello world!
</div>
<div id="info">
  <table>
    <tr>
      <th>namespace:</th>
      <td>hello-kubernetes</td>
    </tr>
    <tr>
      <th>pod:</th>
      <td>hello-kubernetes-7c8575c848-2c6ps</td>
    </tr>
    <tr>
      <th>node:</th>
      <td>allinone (Linux 5.14.21-150400.24.46-default)</td>
    </tr>
  </table>
</div>
<div id="footer">
  paulbouwer/hello-kubernetes:1.10 (linux/amd64)
</div>
    </div>
  </div>

</body>
</html>

19.4 IngressとMetalLB

TraefikはすでにIngressコントローラとして機能しているため、次のようなIngressオブジェクトを介してHTTP/HTTPSトラフィックを公開できます。

IP=$(kubectl get svc -n kube-system traefik -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
cat <<- EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  namespace: hello-kubernetes
spec:
  rules:
  - host: hellok3s.${IP}.sslip.io
    http:
      paths:
        - path: "/"
          pathType: Prefix
          backend:
            service:
              name: hello-kubernetes
              port:
                name: http
EOF

これにより、次のような結果が返されます。

curl http://hellok3s.${IP}.sslip.io
<!DOCTYPE html>
<html>
<head>
    <title>Hello Kubernetes!</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:300" >
</head>
<body>

  <div class="main">
    <img src="/images/kubernetes.png"/>
    <div class="content">
      <div id="message">
  Hello world!
</div>
<div id="info">
  <table>
    <tr>
      <th>namespace:</th>
      <td>hello-kubernetes</td>
    </tr>
    <tr>
      <th>pod:</th>
      <td>hello-kubernetes-7c8575c848-fvqm2</td>
    </tr>
    <tr>
      <th>node:</th>
      <td>allinone (Linux 5.14.21-150400.24.46-default)</td>
    </tr>
  </table>
</div>
<div id="footer">
  paulbouwer/hello-kubernetes:1.10 (linux/amd64)
</div>
    </div>
  </div>

</body>
</html>

また、MetalLB が正しく動作していることを確認するため、arpingを次のように使用できます:

arping hellok3s.${IP}.sslip.io

予期される結果は次のとおりです。

ARPING 192.168.64.210
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=0 time=1.169 msec
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=1 time=2.992 msec
60 bytes from 92:12:36:00:d3:58 (192.168.64.210): index=2 time=2.884 msec

上記の例では、トラフィックは次のように流れます。

  1. hellok3s.${IP}.sslip.ioが実際のIPに解決されます。

  2. 続いて、トラフィックがmetallb-speaker Podによって処理されます。

  3. metallb-speakerがトラフィックをtraefikコントローラにリダイレクトします。

  4. 最後に、Traefikが要求をhello-kubernetesサービスに転送します。