1. 概述

在 Kubernetes 中,使用 LoadBalancer 类型的 Service 是将应用暴露给外部网络的标准方式。当需要为每个服务分配独立 IP 地址时,首选 LoadBalancer 类型。

在公有云平台上,LoadBalancer 服务会自动创建对应的负载均衡器。但在本地开发工具 Minikube 中,该功能是通过模拟实现的,默认情况下,External IP会显示为 <pending>

本文将介绍两种解决 Minikube 中 LoadBalancer 服务 External IP 显示为 pending 的方法。


2. 准备测试环境

为了更好地演示,我们先创建一个测试命名空间和部署一个 Redis Pod。

$ kubectl create ns service-demo
namespace/service-demo created

部署 Redis:

$ kubectl create deploy redis --image=redis:alpine -n service-demo
deployment.apps/redis created

确认 Pod 正常运行:

$ kubectl get pods -n service-demo
NAME                     READY   STATUS    RESTARTS   AGE
redis-8648874d67-d66wz   1/1     Running   0          35s

准备好资源后,我们开始尝试暴露服务并解决 External IP 显示为 pending 的问题。


3. 使用 Minikube Tunnel 暴露服务

3.1 创建 LoadBalancer 类型 Service

使用 kubectl expose 命令创建一个类型为 LoadBalancer 的 Service:

$ kubectl expose deploy redis --port 6379 --type LoadBalancer -n service-demo
service/redis exposed

查看服务状态:

$ kubectl get service -n service-demo
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
redis   LoadBalancer   10.103.33.106   <pending>     6379:31794/TCP   12s

此时 EXTERNAL-IP 显示为 <pending>,这是因为 Minikube 默认不会自动分配外部 IP。

3.2 启动 Minikube Tunnel

在新终端中运行以下命令:

$ minikube tunnel
Status:    
    machine: minikube
    pid: 9325
    route: 10.96.0.0/12 -> 192.168.49.2
    minikube: Running
    services: [redis]
    errors: 
        minikube: no errors
        router: no errors
        loadbalancer emulator: no errors

此时,Minikube 会模拟负载均衡器并分配 IP 地址。

切换回原终端查看服务状态:

$ kubectl get service -n service-demo
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
redis   LoadBalancer   10.103.33.106   10.103.33.106   6379:31794/TCP   53s

✅ External IP 已成功分配。

3.3 验证访问

使用 redis-cli 测试外部访问:

$ redis-cli -h 10.103.33.106 PING
PONG

✅ Redis 成功响应。

3.4 清理资源

回到运行 minikube tunnel 的终端,按下 Ctrl + C 停止隧道。

删除服务:

$ kubectl delete svc redis -n service-demo
service "redis" deleted

4. 使用 MetalLB 暴露服务

4.1 启用 MetalLB 插件

Minikube 支持通过插件启用 MetalLB,这是一个开源的负载均衡实现。

启用插件:

$ minikube addons enable metallb

查看插件状态:

$ minikube addons list

确保 metallb 插件状态为 enabled

4.2 配置 MetalLB IP 地址池

获取 Minikube 节点 IP:

$ minikube ip
192.168.49.2

配置 MetalLB 的 IP 地址池:

$ minikube addons configure metallb
-- Enter Load Balancer Start IP: 192.168.49.10
-- Enter Load Balancer End IP: 192.168.49.20
    ▪ Using image quay.io/metallb/speaker:v0.9.6
    ▪ Using image quay.io/metallb/controller:v0.9.6
✅  metallb was successfully configured

⚠️ 注意:配置的 IP 地址必须和 Minikube 所在子网匹配。

4.3 创建 LoadBalancer 类型 Service

再次创建 Service:

$ kubectl expose deploy redis --port 6379 --type LoadBalancer -n service-demo
service/redis exposed

查看服务状态:

$ kubectl get service -n service-demo
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
redis   LoadBalancer   10.102.24.187   192.168.49.10   6379:31569/TCP   10s

✅ External IP 成功分配为配置的地址池中的 IP。

4.4 验证访问

$ redis-cli -h 192.168.49.10 PING
PONG

✅ Redis 成功响应。


5. 清理环境

删除整个命名空间即可完成清理:

$ kubectl delete ns service-demo
namespace "service-demo" deleted

⚠️ 注意:这种方式适用于测试环境,生产环境中应避免直接删除命名空间,建议逐个删除资源。


6. 总结

本文介绍了两种解决 Minikube 中 LoadBalancer 类型 Service 外部 IP 显示为 pending 的方法:

✅ 方法一:使用 minikube tunnel 命令模拟负载均衡器,自动分配 IP。

✅ 方法二:启用并配置 metallb 插件,手动指定 IP 地址池。

方法 是否需要配置 是否支持多服务 适用场景
minikube tunnel 快速测试单个服务
metallb 多服务、更接近生产环境

选择哪种方式取决于你的使用场景。如果是临时测试,推荐使用 minikube tunnel;如果是构建本地开发环境或 CI 流程,建议配置 metallb


原始标题:Kubernetes Service External IP Showing as Pending in Minikube