Service 中的端口
- Xunzhuo
- Kubernetes networking
- December 15, 2022
端口映射
在 Kubernetes 中,Service 是定义一组访问 Pod 的规则,它决定了如何暴露这些 Pod。不同类型的 Service 主要是为了满足不同的网络访问需求。让我们来看看这三种类型的 Service 和它们的网络原理:
- ClusterIP:
- 这是默认的 Service 类型。
- 它为 Service 在内部 Kubernetes 集群的网络中分配一个内部 IP 地址,只能从集群内部访问。
- ClusterIP Service 不需要端口映射,因为它不需要与集群外部的网络通信。它仅仅是在集群内部的虚拟网络中提供一个稳定的 IP 地址,以便其他 Pod 可以通过它访问后端的 Pod。
- 当一个请求发送到 ClusterIP 时,Kubernetes 会使用内部的负载均衡机制将请求转发到后端的 Pod。
- NodePort:
- 这种类型的 Service 除了包含 ClusterIP 的功能外,还为 Service 在每个节点的 IP 上打开一个端口(NodePort),使得可以从集群外部访问 Service。
- 当外部流量发送到任何节点的 NodePort 时,Kubernetes 会将该流量路由到相应的 Service,然后再转发到后端的 Pod。
- 这里需要端口映射是因为你需要将外部流量从节点的某个端口(通常是一个高端口,范围在30000-32767之间)转发到内部 Pod 的端口。这样做可以让外部客户端不需要知道 Pod 的内部结构或 IP 地址,只需要知道节点的 IP 和 NodePort。
- LoadBalancer:
- 这种类型的 Service 通常由云服务提供商提供,它在 NodePort 和 ClusterIP 的基础上,还会请求云提供商创建一个外部负载均衡器。
- 外部负载均衡器将流量从外部网络路由到集群中的 Service(通过 NodePort),然后再转发到后端的 Pod。
- 这里的端口映射是因为负载均衡器需要将接收到的流量从特定的端口转发到集群内部的 Service 端口上。这样可以实现更加智能的流量分发和管理,同时也允许使用标准端口(如 HTTP 的 80 或 HTTPS 的 443)来访问服务。
总的来说,ClusterIP 不需要端口映射因为它是内部通信,而 NodePort 和 LoadBalancer 需要端口映射来处理从集群外部到集群内部的流量。这些机制使得 Kubernetes 能够灵活地在不同的环境和需求下提供服务发现和负载均衡。
端口分配
在 Kubernetes 中,节点上的端口分配取决于 Service 的类型:
- 对于 NodePort 类型的 Service:
- 当你创建一个 NodePort 类型的 Service 时,你可以选择指定一个端口号,或者让 Kubernetes 自动为你选择一个端口。
- 如果你没有指定端口号,Kubernetes 将为该 Service 分配一个从配置的 NodePort 范围内(默认是 30000-32767)的随机端口。
- 这个端口号是在 Kubernetes 集群的所有节点上被分配的,这意味着你可以用任何节点的 IP 地址加上这个端口号来访问 Service。
- 对于 LoadBalancer 类型的 Service:
- 当你创建一个 LoadBalancer 类型的 Service 时,它通常会自动创建一个 NodePort Service。
- 同样,如果你没有指定 NodePort,Kubernetes 会自动为你分配一个。
- 云提供商的负载均衡器将会监听外部的端口(通常是标准的端口,比如 80 或 443),然后将流量转发到这个自动分配或者你指定的 NodePort 上。
- 对于 ClusterIP 类型的 Service:
- ClusterIP 类型的 Service 只在集群内部使用,因此不涉及节点级别的端口分配。它只会分配一个虚拟的 IP 地址,供集群内部的其他组件使用。
在 Kubernetes 集群中,端口分配的管理是由 kube-controller-manager 组件中的一个子组件(Service 控制器)来处理的。当 Service 被创建或更新时,这个控制器会确保端口的分配符合用户的请求和集群的配置。如果端口冲突或者分配失败,Service 的状态会反映相应的错误信息。
几种 Port
在 Kubernetes Service 配置中,port
、targetPort
和 nodePort
有着不同的作用:
- port:
- 这是 Service 对外暴露的端口号。
- 当其他 Pod 或者集群外部的服务想要访问这个 Service 时,它们会使用这个端口号。
- 在 ClusterIP 类型的 Service 中,这是集群内部通信会使用的端口。
- 在 NodePort 类型的 Service 中,这个端口是集群内部通信使用的,而外部通信会使用
nodePort
。
- targetPort:
- 这是 Pod 上容器监听的端口号。
- 当 Service 接收到请求后,它需要将请求转发到后端 Pod 上的某个端口,这个端口就是
targetPort
。 targetPort
可以是一个端口号,也可以是一个引用 Pod 上容器端口的名称。- 如果
targetPort
不被指定,它默认与port
字段的值相同。
- nodePort(仅适用于 NodePort 和 LoadBalancer 类型的 Service):
- 这是集群中每个节点上用于访问 Service 的端口号。
- 无论请求是发送到哪个节点的这个端口,Kubernetes 都会将请求路由到相应的 Service,然后再转发到后端的 Pod。
nodePort
通常在 30000-32767 范围内自动分配,但也可以手动指定,如你的示例中的 32108。
所以在你的示例中:
- 外部系统可以通过
<NodeIP>:32108
访问 Service(因为这是 NodePort)。 - Service 内部在 Kubernetes 集群中通过 ClusterIP 和端口 9080 提供服务(这是
port
)。 - Service 接收到请求后,会将请求转发到后端 Pod 的 9080 端口(这是
targetPort
)。
这样的配置允许 Service 在不同层次上抽象和转发网络流量,从而实现灵活的服务发现和负载均衡。
所以,如果你有一个 Service 配置文件,它可能看起来像这样:
kind: Service
apiVersion: v1
metadata:
name: backend
spec:
type: NodePort
selector:
app: your-backend-app
ports:
- protocol: TCP
port: 3000
targetPort: 3000
nodePort: 31263
在这个例子中,port
设置为 3000,nodePort
明确设置为 31263。如果 targetPort
被省略了,Kubernetes 就会假设它与 port
相同,也就是 3000。这意味着 Service 会将到达任何节点上的 31263 端口的流量转发到后端 Pod 的 3000 端口。