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
上記の例では、トラフィックは次のように流れます。
hellok3s.${IP}.sslip.io
が実際のIPに解決されます。続いて、トラフィックが
metallb-speaker
Podによって処理されます。metallb-speaker
がトラフィックをtraefik
コントローラにリダイレクトします。最後に、Traefikが要求を
hello-kubernetes
サービスに転送します。