Kubernetes服务外部IP挂起。

312

我正在尝试在 Kubernetes 上部署 nginx,Kubernetes 版本为 v1.5.2,我已经使用 3 个副本部署了 nginx,YAML 文件如下:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: deployment-example
spec:
  replicas: 3
  revisionHistoryLimit: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.10
        ports:
        - containerPort: 80

现在我想将其端口80暴露在节点的端口30062上,为此我创建了以下服务:

kind: Service
apiVersion: v1
metadata:
  name: nginx-ils-service
spec:
  ports:
    - name: http
      port: 80
      nodePort: 30062
  selector:
    app: nginx
  type: LoadBalancer

该服务的表现良好,但在Kubernetes仪表板和终端上仍显示为挂起状态。 终端输出仪表板状态

32个回答

299

看起来您正在使用自定义的Kubernetes集群(使用minikubekubeadm或类似工具)。 在这种情况下,不像AWS或Google Cloud一样,没有集成的负载均衡器。 通过此默认设置,您只能使用NodePort或Ingress Controller。

通过Ingress Controller,您可以设置一个域名,该域名映射到您的Pod; 如果您使用Ingress Controller,则不需要将Service设置为LoadBalancer类型。


47
这并没有真正回答问题吧?用户正在使用“LoadBalancer”作为服务类型,这是一种有效的服务类型。“NodePort”和“ingress”是其他解决方法,但并没有真正解决问题,对吧? - Raptor
14
这是一种有效的服务类型,但它不能在非兼容的平台上使用(至少默认情况下不能)。为了使用LoadBalancer,你必须拥有一个能够向pod提供外部IP的平台,这是Google Cloud或AWS等平台所具备的。 - Javier Salmeron
2
我在AWS上使用kubeadm。我还能使用 LoadBalancer 吗? - jiashenC
42
如果您正在使用minikube,请运行"minikube tunnel"。现在检查您的服务,您将获得公共IP地址。这里是更多信息的文档 https://minikube.sigs.k8s.io/docs/tasks/loadbalancer/ - Ravi
3
您可以考虑使用MetalLB,它是通过标准路由协议为裸金属Kubernetes集群提供负载平衡器。 Kubernetes(非服务)与MetalLB非常兼容。 - Thilee
显示剩余4条评论

280

4
我尝试了 minikube tunnel 命令,它解决了 pending 的问题,但新的外部 IP 无法使用:出现了超时错误。 - a.barbieri
@a.barbieri请确保使用隧道IP而不是minikube IP。 "使用IP 10.106.102.98修补ingress-nginx" - Peter Zhou
2
是的,谢谢你Peter。我会尝试的。无论如何,切换到Docker桌面版后,我已经能够通过开箱即用的设置来解决这个问题,直接在本地主机上运行。 - a.barbieri
1
@a.barbieri,您能指出这些选项在哪里以及您需要将它们设置为什么吗?我也想使用Docker桌面版来解决这个问题,但我不知道在哪里以及如何设置。 - user658182
1
这个方法对我有效,但我必须更新我的minikube安装才能使其工作。我已经更新到最新版本,目前是v1.24.0。 - LaloLoop
显示剩余2条评论

103

如果您不使用GCE或EKS(而是使用kubeadm),则可以在您的服务YAML中添加一个externalIPs规范。您可以使用与节点主要接口相关联的IP,例如eth0。然后,您可以使用节点的外部IP从外部访问该服务。

...
spec:
  type: LoadBalancer
  externalIPs:
  - 192.168.0.10

4
可能有一些信息遗漏了:“externalIPs由Kubernetes不管理,而是由集群管理员负责。”(来源:https://kubernetes.io/docs/concepts/services-networking/service/)。我需要安装某种“控制器”吗? - Daniel Alder
1
我正在按照 Kubernetes 教程(https://kubernetes.io/docs/tutorials/stateless-application/guestbook/)进行操作,并且使用 kubeadm 工具运行良好。 - Eduardo
谢谢 - 太棒了,按预期工作。我已将服务暴露给节点eth网络IP,现在可以在集群外访问。 - Vlad Gulin
2
最佳答案,因为它最简单并且实际有效。这解决了EXTERNAL-IP被卡在PENDING状态的实际问题... - Akito
我有一个运行minikube的虚拟机,具有指定的IP地址。将此IP绑定到上面的答案可以正常工作。 - Steven Yip

66

我使用kubeadm创建了一个单节点的k8s集群。当我尝试使用PortForwardkubectl proxy时,它显示外部IP处于挂起状态。

$ kubectl get svc -n argocd argocd-server
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
argocd-server   LoadBalancer   10.107.37.153   <pending>     80:30047/TCP,443:31307/TCP   110s

在我的情况下,我已经像这样修补了该服务:

kubectl patch svc <svc-name> -n <namespace> -p '{"spec": {"type": "LoadBalancer", "externalIPs":["172.31.71.218"]}}'

接着,它开始在公共IP上提供服务。

$ kubectl get svc argo-ui -n argo
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
argo-ui   LoadBalancer   10.103.219.8   172.31.71.218   80:30981/TCP   7m50s

35
或许你应该提到"172.31.71.218"来自哪里? - EuRBamarth
1
@EuRBamarth 我尝试使用我所有节点的IP替换他的172.31.71.218,它们都可以正常工作。 - letthefireflieslive

49

要访问minikube上的服务,您需要运行以下命令:

minikube service [-n NAMESPACE] [--url] NAME

更多信息请查看:Minikube GitHub


11
具体示例:minikube service spark-ui-proxy --url http://192.168.99.100:30621 - Romeo Kienzler
这个有效!这个命令实际上是做什么的? - Aamir Rizwan

32

使用Minikube时,您可以通过运行以下命令获取访问服务的IP和端口:

当使用Minikube时,您可以通过运行以下命令获取访问服务的IP和端口:

minikube service [service name]

例如:

minikube service kubia-http

应该提到,服务可能会保持在“待定”状态,而这个命令无论如何都会给你提供带有端口的IP地址 :) - undefined

17

如果这是您自己的私有k8s集群,那么MetalLB可能更适合。以下是步骤。

步骤1:在您的集群中安装MetalLB

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml
# On first install only
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"

第二步:通过使用configmap进行配置

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 172.42.42.100-172.42.42.105 #Update this with your Nodes IP range 

第三步: 创建您的服务以获取外部IP (但最终是一个私有IP)。

FYR:

在MetalLB安装之前: enter image description here

在MetalLB安装后: enter image description here

enter image description here


4
MetalLB比什么更适合? - vhs
对于原问题描述的场景。 - Thilee
今天我看到了一个使用TapTun在macOS上设置MetalLB的方法。有点像黑客技巧。我相信OP正在使用本地设置。你是在建议使用本地TapTun设置来解决Linux hyperkit网络限制吗? - vhs
有没有获取节点 IP 范围的命令? - Oliver Dixon
1
我现在正在尝试使用MetalLB,并安装了 ingress-nginx。据我所理解,现在应该有一个外部 IP 的 ingress 服务,但它仍然处于 "<pending>" 状态。 - TheAnachronism

8

继@Javier的回答后,我决定选择“修补外部IP”作为我的负载均衡器方案。

 $ kubectl patch service my-loadbalancer-service-name \
-n lb-service-namespace \
-p '{"spec": {"type": "LoadBalancer", "externalIPs":["192.168.39.25"]}}'

这将用一个新的修补过的IP地址来替换那个“挂起”的IP地址,你可以将其用于你的集群。

欲了解更多,请参阅 Kubernetes上使用Minikube支持负载均衡器 上karthik的帖子。

这不是最干净的方法。我需要一个临时解决方案。希望这能帮助到某些人。


完美的答案! - Vijay S B

7

如果在minikube上运行,请注意如果您不使用默认值,则需要提及命名空间。

minikube service <<service_name>> --url --namespace=<<namespace_name>>


不仅在minikube中... - undefined

7

如果您正在使用 minikube,则可以从终端运行以下命令:

$ minikube ip
$ 172.17.0.2 // then 
$ curl http://172.17.0.2:31245
or simply
$ curl http://$(minikube ip):31245

我正在使用minikube,只需使用nodeport并获取minikube IP即可解决问题。 - Diego Lins de Freitas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接