【问题标题】:Kubernetes: how to access service if nodePort is random?Kubernetes:如果 nodePort 是随机的,如何访问服务?
【发布时间】:2020-02-01 12:47:17
【问题描述】:

我是 K8s 的新手,目前正在使用 Minikube 来玩这个平台。如何为服务配置公共(即集群外部)端口?我遵循了nginx example 和 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 服务类型的一些内容,但它们甚至没有指定端口...

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

【问题讨论】:

  • 如果将type字段设置为NodePort,Kubernetes控制平面会从--service-node-port-range flag (default: 30000-32767)指定的范围内分配一个端口。如果您每次都想要一个特定的端口号,您可以在@中指定一个值987654326@ 在您的服务清单文件上创建服务时。
  • 按照文档中的说明设置 nodePort 并不是一个好的解决方案,因为它只控制节点级别的端口。在没有 minikube 的情况下从整个集群外部访问服务时(例如在 GKE 上),nodePort 有什么关系?它必须是负载均衡器级别的东西,但我不知道在哪里。 BTW Ingress 不是一个选项,因为我的流量不是基于 http 的(虽然它是 TCP)
  • 你好,如果它的非http流量,那么我建议你在k8s服务对象中使用exteranlIP。然后您可以使用 externalIP:svcPort 访问非 http 应用程序。 kubernetes.io/docs/tutorials/stateless-application/…
  • Suresh Vishnoi,谢谢,它有效!问题是我必须在单独的 shell 中运行“minikube 隧道”才能获得外部 IP(否则它会永远处于“待处理”状态)。正如您提到的,“端口”配置确实可以在集群外部访问

标签: kubernetes kubernetes-service


【解决方案1】:

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 端口进入。此端口将自动从30000 分配到32767。

您可以按照this manual 更改默认的NodePort 端口范围。

您可以通过查看此answer 来检查创建NodePort 类型的服务对象时究竟发生了什么。

想象一下:

  • 您的节点有 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 响应:

  • 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

您可以使用curl 命令检查访问权限,如下所示:

$ curl http://NODE_IP:NODEPORT


在你提到的例子中:

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

会发生什么:

  • 它将在您的minikube 实例上分配一个从30000 到32767 范围内的随机端口,将进入此端口的流量引导到pod。
  • 此外,它将创建一个ClusterIP,端口为1234

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

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

从minikube 的角度来看,NodePort 将是您的minikube 实例上的一个端口。它的 IP 地址将取决于所使用的管理程序。将其暴露在本地计算机之外将在很大程度上依赖于操作系统。


LoadBalancer

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
  • 您的 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

根据上述示例,您将收到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: LoadBalancer

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

-- Kubernetes.io: Create external LoadBalancer

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

-- Kubernetes.io: Hello minikube

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

命令$ kubectl get services 中的ExternalIP 将处于待处理状态。

要解决没有外部LoadBalancer(2) 的问题,您可以调用$ minikube tunnel,这将创建从主机到minikube 环境的路由,以直接访问ClusterIP 的CIDR。

【讨论】:

  • 在本地环境中,很容易理解固定NodePort 的用例。在云环境中,很容易理解LoadBalancer 的用例。但是随机分配的NodePort 的用例是什么?这对谁有用?它的用途是什么?
【解决方案2】:

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

进入 NodePort 的流量将被直接路由到 Pod 并将 不去 ClusterIP。

但正如 k8s 记录的 here:

NodePort:在每个 Node 的 IP 上的静态端口(即 节点端口)。一个 ClusterIP 服务,NodePort 服务对其 路线,是自动创建的。您将可以联系 NodePort 服务,来自集群外部,通过请求 :.

进入 NodePort 的流量确实流向了 ClusterIP。

【讨论】:

    猜你喜欢
    • 2021-06-27
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 2019-07-26
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    相关资源
    最近更新 更多