MetalLB, bare metal load-balancer for Kubernetes

自宅の検証環境におうちk8sを導入しています。

AWSやGCPなどのクラウドプロバイダーの場合、KubernetesのServiceをType: LoadBalancerにしていると、自動的にグローバルIPアドレスを取得してくれます。

オンプレ環境のKubernetesで同様のことをするとPendingになってしましますが、Metallbを使うとこでType: LoadBalancerと設定したServiceに、プライベートIPアドレスを振り分ける事ができます。

今回は、クラスター間のネットワークにflannelを使っているので、L2ネットワークでIPアドレスを設定します。

目次

事前準備

kube-proxyにIPVS modeを使用している且つKubernetes v1.14.2以降のバージョンの場合は、strictARPを有効にする必要があります。(今回はIPVS modeを使用していないため、割愛します。)

strictARPが有効になっているかは、以下のコマンドで確認できます。

kubectl get configmap kube-proxy -n kube-system -o yaml | \\
sed -e "s/strictARP: false/strictARP: true/" | \\
kubectl diff -f - -n kube-system

diffが出力されるので、以下の出力が含まれていた場合にはstrictARPが有効になっていない事が分かります。

-      strictARP: false
+      strictARP: true

以下のコマンドでstrictARPを有効にします。

kubectl get configmap kube-proxy -n kube-system -o yaml | \\
sed -e "s/strictARP: false/strictARP: true/" | \\
kubectl apply -f - -n kube-system
Warning: resource configmaps/kube-proxy is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.

MetalLBのインストール

Manifestでインストールする場合は、以下の2つをapplyします。

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.2/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.2/manifests/metallb.yaml

これでインストール自体は完了したので、以降は実際にアサインするIPアドレスを設定します。

Config設定

Flannel Networkのため、L2 ConfigurationのConfigMapを作成します。

address-pools は自分の環境(cluster のアドレスレンジの未使用 IP アドレス)に修正しております。

ちなみに、このaddress-poolsはflannel networkで使用しているものではなく、Nodeが持つIPのものになっています。

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.100.240-192.168.100.250
EOF

以上で設定は完了です。

Create Pod&Service

テスト用のnginxを作ります。

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: ngnix
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: ngnix
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
EOF

動作確認します。

root@k8s-master1:~# kubectl get pod,svc
NAME                                  READY   STATUS    RESTARTS   AGE
pod/ngnix-84784697bb-8mhhr            1/1     Running   0          55s
pod/ngnix-84784697bb-9x6ft            1/1     Running   0          55s

NAME                     TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)        AGE
service/nginx            LoadBalancer   10.105.252.24   192.168.100.240   80:30324/TCP   55s

root@k8s-master1:~# curl 192.168.100.240
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="<http://nginx.org/>">nginx.org</a>.<br/>
Commercial support is available at
<a href="<http://nginx.com/>">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@k8s-master1:~#

192.168.100.240のExternal-IPを持って動いていることが確認できました。defaultではaddress poolから若番のIPアドレスが払い出されるようです。

loadBalancerIPをaddress pool内の値に設定することで、IPアドレスを指定することも可能でした。(当たり前ですが、pool外のIPアドレスを指定するとpendingとなりIPアドレスが付与されません。)

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
  loadBalancerIP: 192.168.100.250
EOF
root@k8s-master1:~# kubectl get svc
NAME             TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)        AGE
nginx            LoadBalancer   10.105.59.75    192.168.100.250   80:31629/TCP   3m5s

最後に

今回はL2でのmetallbを試してみましたが、次はBGP Configuration(L3)を試してみます。

Reference