使用 MetalLB 为 Kubernetes 集群服务分配独立 IP
概述
在本地或私有数据中心(On-Premise)部署的 Kubernetes 集群中,暴露服务是一个常见挑战。当将 Service 类型设置为 LoadBalancer 时,其 EXTERNAL-IP 字段会持续显示 <pending> 状态,这是因为自建集群不具备云服务商(AWS、GCP、Azure)提供的自动 IP 分配能力。
MetalLB 是专为裸金属 Kubernetes 集群设计的负载均衡器实现方案。它能够监听 LoadBalancer 类型的 Service,并从预先配置的 IP 地址池中为其分配独立的、可路由的内网 IP 地址。
本文档将详细介绍如何在现有 K8s 集群中部署和配置 MetalLB,并以 Grafana 服务为例,展示如何实现"一个服务一个独立 IP"的目标。
前置条件
在开始之前,需要确保满足以下条件:
- 正在运行的 Kubernetes 集群
- 已配置 kubectl 命令行工具并成功连接到集群
- 已规划好局域网中未被占用的 IP 地址范围(例如:
172.18.130.200-172.18.130.240)
安装 MetalLB
获取安装清单
访问 MetalLB 官方 GitHub 仓库 获取最新的稳定版本号,然后下载部署所需的 YAML 清单文件。
注意:务必将以下命令中的
v0.15.2替换为官方推荐的最新稳定版本。
wget https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml镜像源替换(可选,国内环境推荐)
MetalLB 默认使用的镜像为 quay.io/metallb/controller 和 quay.io/metallb/speaker。在国内网络环境下可能无法直接拉取,可通过以下步骤替换为国内镜像源。
# 检查清单文件中的镜像地址
grep "image:" metallb-native.yaml
# 批量替换镜像仓库地址
# 示例:将 quay.io 替换为国内镜像代理地址
sed -i 's#quay.io#docker.at9.net/quay.io#g' metallb-native.yaml部署 MetalLB
执行以下命令在集群中创建 metallb-system 命名空间并部署相关组件:
kubectl apply -f metallb-native.yaml验证安装
等待所有 Pod 启动完成,检查 metallb-system 命名空间下的 Pod 状态:
kubectl get pods -n metallb-system正常情况下应该看到一个 controller Pod 和多个 speaker Pod(每个节点一个)处于 Running 状态。
配置 IP 地址池
MetalLB 安装完成后,需要配置可管理和分配的 IP 地址范围。
创建配置文件
创建名为 metallb-config.yaml 的配置文件,定义以下两个关键资源:
- IPAddressPool:声明可用的 IP 地址范围
- L2Advertisement:允许 MetalLB 通过 ARP 协议在二层网络上宣告这些 IP 地址,确保局域网内可达
# metallb-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: production-ip-pool
namespace: metallb-system
spec:
addresses:
# 替换为实际规划的 IP 地址段
- 172.18.130.200-172.18.130.240
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default-l2-advertisement
namespace: metallb-system
spec:
# 确保此处名称与 IPAddressPool 名称一致
ipAddressPools:
- production-ip-pool应用配置
kubectl apply -f metallb-config.yaml配置应用后,MetalLB 将自动扫描集群中 type: LoadBalancer 且 EXTERNAL-IP 为 <pending> 的 Service,并从配置的地址池中分配 IP。
验证配置效果
如果集群中存在处于 <pending> 状态的 Service(例如 ingress-nginx-controller),此时应该已经成功获取到 IP 地址。
# 使用 -w 参数实时观察变化
kubectl get svc -n ingress-nginx -w预期输出示例:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.96.2.3 172.18.130.200 80:30691/TCP,443:31601/TCP 46h为 Grafana 服务分配独立 IP
以下步骤演示如何为 Grafana 服务分配独立的内网 IP。
查看当前 Service 状态
首先查看 monitoring 命名空间下的 Service,找到 Grafana 对应的 Service(通常名为 prometheus-grafana):
kubectl get svc -n monitoring修改 Service 类型
使用 kubectl patch 命令将 Service 类型修改为 LoadBalancer:
kubectl patch svc prometheus-grafana -n monitoring -p '{"spec": {"type": "LoadBalancer"}}'此命令执行后将触发 MetalLB 的 IP 分配流程。
验证 IP 分配
稍等片刻,MetalLB Controller 会检测到新的 LoadBalancer Service 请求,并从 IP 池中分配一个未使用的 IP 地址(例如 172.18.130.201)。
再次查看 Service 状态:
kubectl get svc -n monitoring成功后的输出示例:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
prometheus-grafana LoadBalancer 10.96.3.13 172.18.130.201 80:31432/TCP 47h此时可通过浏览器访问 http://172.18.130.201 打开 Grafana 登录页面。
附录:获取 Grafana 初始密码
如果通过 kube-prometheus-stack 或类似方式安装 Grafana,admin 用户的初始密码通常存储在 Secret 中。
使用以下命令获取并解码密码:
kubectl get secret -n monitoring prometheus-grafana -o jsonpath="{.data.admin-password}" | base64 --decode默认用户名为 admin,配合获取到的密码即可登录。
总结
通过部署 MetalLB 并配置 IP 地址池,成功解决了自建 Kubernetes 集群中 LoadBalancer Service 无法分配外部 IP 的问题。这种方案特别适合内网环境,使得每个服务都能拥有独立的、可直接访问的 IP 地址,简化了服务暴露和网络管理的复杂度。