Kubernetes:如果nodePort是随机的,如何访问服务?

8

我刚接触K8s,目前正在使用Minikube玩转这个平台。如何为服务配置一个公共(即集群外部)端口?我按照nginx示例和K8s服务教程操作。在我的情况下,我创建了以下的服务:

kubectl expose deployment/mysrv --type=NodePort --port=1234

如果从集群内部访问服务,则端口为1234。Minikube教程指出,我需要通过它的随机nodePort直接访问服务,这对于手动测试来说是有效的。

kubectl describe service mysrv | grep NodePort
...
NodePort:                 <unset>  32387/TCP
# curl "http://`minikube ip`:32387/"

但我不明白在一个真正的集群中,服务如何能有一个固定的全球可访问的端口。 nginx示例中描述了使用LoadBalancer服务类型的一些内容,但它们甚至没有在那里指定端口......

有任何想法如何为整个服务修复外部端口?


1
如果您将类型字段设置为NodePort,则Kubernetes控制平面将从由“--service-node-port-range”标志(默认值:30000-32767)指定的范围中分配端口。如果您想要每次使用特定的端口号,可以在服务清单文件上创建服务时在nodePort字段中指定一个值。 - DT.
在文档中所解释的设置nodePort并不是一个好的解决方案,因为它只控制节点级别的端口。当在没有minikube(例如在GKE上)的整个集群外部访问服务时,nodePort又有什么关联呢?它必须是负载均衡器级别的东西,但我不知道在哪里。顺便说一下,Ingress不是一个选项,因为我的流量不是基于http的(虽然是TCP)。 - Sagi Mann
2
嗨,如果是非HTTP流量,我建议您在k8s服务对象中使用externalIP。然后,您可以使用externalIP:svcPort访问非HTTP应用程序。https://kubernetes.io/docs/tutorials/stateless-application/expose-external-ip-address/ - Suresh Vishnoi
1
Suresh Vishnoi,谢谢,它起作用了!问题是我必须在单独的shell中运行'minikube tunnel'才能获得外部IP(否则它将永远保持“挂起”状态)。正如您所提到的,“端口”配置确实可以在集群外访问。 - Sagi Mann
2个回答

18
“minikube教程中提到,我需要直接访问服务的随机nodePort,这对于手动测试是有效的。当您使用kubectl expose命令创建类型为NodePort的服务对象时,无法选择NodePort端口。要选择NodePort端口,您需要创建一个YAML定义文件。以下示例演示了如何在类型为Nodeport的服务对象中手动指定端口。”
apiVersion: v1
kind: Service
metadata:
  name: example-nodeport
spec:
  type: NodePort
  selector:
    app: hello # selector for deployment
  ports:
  - name: example-port
    protocol: TCP
    port: 1234 # CLUSTERIP PORT
    targetPort: 50001 # POD PORT WHICH APPLICATION IS RUNNING ON 
    nodePort: 32222 # HERE!

您可以通过以下命令应用上述YAML定义: $ kubectl apply -f FILE_NAME.yaml 只有当nodePort端口可用时,才会创建上述服务对象。
“但是我不明白,在实际集群中,服务如何没有一个固定的全球可访问端口。”
在由云提供商管理的集群(例如GKE)中,您可以使用类型为LoadBalancer的服务对象,该对象将具有固定的外部IP和固定端口。
具有公共IP的节点的集群可以使用类型为NodePort的服务对象将流量引导到集群中。
minikube环境中,您可以使用类型为LoadBalancer的服务对象,但是它将具有最后一段描述的一些警告。
一点解释: NodePort Nodeport在每个节点IP上以静态端口公开服务。 它允许外部流量通过NodePort端口进入。此端口将自动分配从3000032767的范围内。
您可以按照此手册更改默认的NodePort端口范围。
当创建一个类型为NodePort的服务对象时,您可以通过查看此answer来了解发生了什么。
想象一下:
  • 您的节点具有IP地址:
    • 192.168.0.100
    • 192.168.0.101
    • 192.168.0.102
  • 您的Pod在端口50001上响应hello,并且它们具有IP地址:
    • 10.244.1.10
    • 10.244.1.11
    • 10.244.1.12
  • 您的服务是:
    • NodePort(端口32222),其中包括:
      • ClusterIP
        • IP:10.96.0.100
        • port:7654
        • targetPort:50001
关于targetPort的说明。这是一个定义在pod上的端口,例如Web服务器。
根据上面的例子,您将得到带有hello响应的:
  • 节点IP:节点端口 (所有的POD都可以回应 hello):
    • 192.168.0.100:32222
    • 192.168.0.101:32222
    • 192.168.0.102:32222
  • 集群IP:端口 (所有的POD都可以回应 hello):
    • 10.0.96.100:7654
  • POD IP:目标端口 (只有接收请求的POD可以回应 hello)
    • 10.244.1.10:50001
    • 10.244.1.11:50001
    • 10.244.1.12:50001

您可以使用以下命令检查访问:

$ curl http://节点IP:节点端口


在你提到的例子中:

$ kubectl expose deployment/mysrv --type=NodePort --port=1234

会发生什么:

  • 它将在您的minikube实例上分配一个随机端口,范围从3000032767,将进入此端口的流量指向pod。
  • 此外,它将创建一个端口为1234ClusterIP

在上面的示例中,没有参数targetPort。如果未提供targetPort,则与命令中的port相同。

进入NodePort的流量将直接路由到pod,而不会进入ClusterIP

minikube的角度来看,NodePort将是您的minikube实例上的端口。其IP地址将取决于所使用的虚拟化程序。将其暴露在本地计算机之外将严重依赖于操作系统。


负载均衡器

类型为LoadBalancer(1)的服务对象与外部LoadBalancer(2)之间存在区别:

  • LoadBalancer(1)类型的服务对象允许使用云服务提供商的LoadBalancer(2)将服务暴露在外部。它是Kubernetes环境中的一个服务,通过服务控制器可以调度创建外部LoadBalancer(2)。
  • 外部LoadBalancer(2)是云服务提供商提供的负载均衡器,它将在第4层操作。

LoadBalancer(1)类型服务的示例定义:

apiVersion: v1
kind: Service
metadata:
  name: example-loadbalancer
spec:
  type: LoadBalancer
  selector:
    app: hello
  ports:
    - port: 1234 # LOADBALANCER PORT 
      targetPort: 50001  # POD PORT WHICH APPLICATION IS RUNNING ON 
      nodePort: 32222 # PORT ON THE NODE 

应用上述YAML将创建一个类型为LoadBalancer的服务(1)

具体看:

  ports:
    - port: 1234 # LOADBALANCER PORT 

这个定义将同时:

  • 将外部LoadBalancer(2)的port指定为1234
  • ClusterIPport指定为1234

想象一下:

  • 您的外部LoadBalancer(2)有:
    • ExternalIP: 34.88.255.5
    • port:7654
  • 您的节点具有以下IP:
    • 192.168.0.100
    • 192.168.0.101
    • 192.168.0.102
  • 您的Pods使用端口50001响应hello,它们的IP地址为:
    • 10.244.1.10
    • 10.244.1.11
    • 10.244.1.12
  • 您的服务是:
    • NodePort(端口32222)具有:
      • ClusterIP
        • IP:10.96.0.100
        • port:7654
        • targetPort:50001

根据上述示例,您将获得以下响应:hello

  • ExternalIP:port (所有的Pod都可以回应 hello):
    • 34.88.255.5:7654
  • NodeIP:NodePort (所有的Pod都可以回应 hello):
    • 192.168.0.100:32222
    • 192.168.0.101:32222
    • 192.168.0.102:32222
  • ClusterIP:port (所有的Pod都可以回应 hello):
    • 10.0.96.100:7654
  • PodIP:targetPort (只有接收请求的Pod能够回应 hello)
    • 10.244.1.10:50001
    • 10.244.1.11:50001
    • 10.244.1.12:50001

ExternalIP 可以通过命令 $ kubectl get services 进行检查

流量传输方式: 客户端 -> LoadBalancer:port(2) -> NodeIP:NodePort -> Pod:targetPort

Minikube: 负载均衡器

注意:此功能仅适用于支持外部负载均衡器的云提供商或环境。

-- Kubernetes.io: 创建外部负载均衡器

在支持负载均衡器的云提供商上,将会提供一个外部IP地址以访问服务。在Minikube上,LoadBalancer类型通过minikube service命令使服务可访问。

-- Kubernetes.io: Hello minikube

Minikube可以创建LoadBalancer类型的服务对象(1),但不会创建外部LoadBalancer(2)。

在命令$ kubectl get services中,ExternalIP状态为等待中。

为了解决没有外部LoadBalancer(2)的问题,可以调用$ minikube tunnel,它将在主机和minikube环境之间创建一条路由,以直接访问ClusterIPCIDR


在本地环境中,固定NodePort的用例很容易理解。在云环境中,LoadBalancer的用例也很容易理解。但是随机分配的NodePort有什么用途呢?它对谁有帮助,应该如何使用? - shawnz

0

Dawid Kruk 的回答有一个小错误,

进入 NodePort 的流量将直接路由到 pod,而不会进入 ClusterIP。

但是根据 k8s 文档 这里,

NodePort:在每个节点的 IP 上公开服务,使用静态端口(NodePort)。自动创建 ClusterIP 服务,NodePort 服务路由到此服务。您将能够通过请求 <NodeIP>:<NodePort> 从集群外部联系 NodePort 服务。

进入 NodePort 的流量确实会进入 ClusterIP。


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