# Metallb - 贫苦 K8S 用户的负载均衡支持

## 简介

在私有网络上运行 Kubernetes，和御三家相比，对 `LoadBalancer` 类型的服务的支持应该是众多表面差异中最醒目的一个了。类型为 `LoadBalancer` 的服务在 Kubernetes 中并没有直接支持，NodePort 和 ExternalIP 方案让很多私有云用户成为了 K8S 世界中的二等公民。接下来介绍的 [`Metallb`](https://metallb.universe.tf/)，就给私有 Kubernetes 用户带来了一个方便、可用（而且不太成熟）的软件解决方案。

> 该项目发布于 2017 年底，当前处于 Beta 阶段。

Metallb 会在 Kubernetes 内运行，监控服务对象的变化，一旦察觉有新的 `LoadBalancer` 服务运行，并且没有可申请的负载均衡器之后，就会完成两部分的工作：

### 地址分配

用户需要在配置中提供一个地址池，Metallb 将会在其中选取地址分配给服务。

### 地址广播

根据不同配置，Metallb 会以二层（ARP/NDP）或者 BGP 的方式进行地址的广播。

## 支持范围

> 不支持 IPVS

|网络插件|兼容性|
|---|---|
|Calico|部分支持（有附加文档）|
|Flannel|支持|
|Kube-router|不支持（正在跟进）|
|Romana|支持（有附加文档）|
|Weave Net|支持|

## 一个小测试

### 安装

Metallb 支持 Helm 和 YAML 两种安装方法，这里我们使用第二种：

`kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.1/manifests/metallb.yaml`

很简单，Metallb 就会开始安装，会生成自己的命名空间以及 RBAC 配置。

~~~shell
$ kubectl get pods -n metallb-system
NAME                         READY     STATUS    RESTARTS   AGE
controller-b7896bf94-g449l   1/1       Running   0          51m
speaker-mt6kd                1/1       Running   0          51m
speaker-sqbn4                1/1       Running   0          51m
~~~

### 配置

接下来我们要生成一个 Configmap 文件，为 Metallb 设置网址范围以及协议相关的选择和配置，这里以一个简单的二层配置为例：

~~~yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: my-ip-space
      protocol: layer2
      addresses:
      - 10.211.55.240/28
~~~

> 注意：这里的 IP 地址范围需要跟集群实际情况相对应。

使用 `kubectl apply` 命令应用之后，使用 `kubectl logs -f [metallb-controller-pod]` 会看到配置更新过程。

### 测试

创建一个 Nginx 的服务，服务类型为 `LoadBalancer`：

~~~yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1
        ports:
        - name: http
          containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
~~~

服务创建运行之后，可以列出服务信息：

~~~shell
kubectl get svc
NAME       TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)         AGE
kube-dns   ClusterIP      10.96.0.10      <none>          53/UDP,53/TCP   7d
nginx      LoadBalancer   10.96.245.212   10.211.55.240   80:32207/TCP    54m
~~~

这里就发现，LoadBalancer 类型的服务，分配到了我们地址池中的第一个 IP。

用 `curl http://10.211.55.240` 验证，就会发现返回了 Nginx 的欢迎信息。

## 补充

除了这里提到的一点点简单配置之外，Metallb 的配置能力还是比较强大的，这点可以参考官网，其中谈及了不少较为务实的案例，另外还提到了部分 Issue 供用户参考。
