k8s 之如何从集群外部访问内部服务的三种方法

外部访问集群内部服务的三种方法。

1. k8s集群中三种IP(NodeIP、PodIP、ClusterIP)介绍


1.1 三种 IP 定义


NodeIP:Node 节点的 IP 地址,即物理机(虚拟机)的 IP 地址。
PodIP:Pod 的 IP 地址,即 docker 容器的 IP 地址,此为虚拟 IP 地址。
ClusterIP:k8s 虚拟的 Service 的 IP 地址,此为虚拟 IP 地址。

1.2 三种 IP 的理解


Node IP:
是物理机的IP(或虚拟机IP)。每个Service都会在Node节点上开通一个端口,外部可以通过 http://NodeIP:NodePort 即可访问 Service 里的 Pod 提供的服务。
Pod IP:
是每个 Pod 的 IP 地址,Docker Engine根据 docker 网桥的 IP 地址段进行分配的,通常是一个虚拟的二层网络。
同Service下的pod可以直接根据PodIP相互通信
不同Service下的pod在集群间pod通信要借助于 cluster ip
pod和集群外通信,要借助于node ip
Cluster IP
是 Service 的 IP 地址,此为虚拟 IP 地址,外部网络无法 ping 通,只有kubernetes集群内部访问使用。
Cluster IP仅仅作用于Kubernetes Service这个对象,并由Kubernetes管理和分配P地址 Cluster
IP无法被ping,他没有一个“实体网络对象”来响应 Cluster IP只能结合Service
Port组成一个具体的通信端口,单独的Cluster IP不具备通信的基础,并且他们属于Kubernetes集群这样一个封闭的空间。
在不同Service下的pod节点在集群间相互访问可以通过Cluster IP


1.3 三种 IP 关系图

 

 

①:代表外部通过公有云的 LoadBalancer 负载均衡服务访问集群内部服务流程
②:代表外部用户直接访问集群内部 Service 的 ClusterIP 访问集群内部服务流程
③:代表集群内部不同 Service 之间的 Pod 服务访问流程
④:代表集群内部同一个 Service 中 Pod 服务之间访问流程

2. 客户端如何从外部访问集群内部的服务


那么 Pod 和 Service 都是 k8s 集群内部范围的虚拟概念,所以集群外部客户端无法通过 Pod 的 IP 地址或者 Service 的虚拟 IP 地址和虚机端口号访问他们。
那集群外部客户端如何访问内部服务呢?

第一种方法:
将 Pod 或 Service 的端口号映射到宿主机,以使客户端应用能够通过物理机访问容器应用。

第二种方法:
通过公有云的 LoadBalancer 服务负载均衡,以使客户端从外部访问集群内部容器应用。

第三种方法(推荐):
使用 k8s 自带的 Ingress 负载均衡服务,以使客户端从外部访问集群内部容器应用。

2.1 (第一种方法)将容器应用的端口直接映射到物理机


2.1.1 将 Pod 容器的端口直接映射到宿主机(不推荐)

  • webapp-pod-hostPort.yaml
apiVersion: v1
kind: Pod
metadata:
  name: webapp 
  labels:
    app: webapp 
spec:
  # hostNetwork: true          # 网络模式选择为使用宿主机网络,即容器所有的端口都会自动映射到宿主机上
  containers:
  - name: webapp
    image: tomat
    ports:
    - containerPort: 8080    # 容器的运行端口为 8080
      hostPort: 8081         # 映射到宿主机的端口为 8081,如果上边设置了网络模式,则不需要加 hostPort

 



(不推荐)此种方法比较直接,客户端直接访问指定的容器服务。即客户端通过宿主机的 8081 端口即可访问容器服务, curl <hostIP>:8081 。但是这样的方式只能访问指定单一的容器服务,没有负载均衡,所以不推荐。


2.1.2 将 Service 的端口映射到物理机


webapp-service-nodePort.yaml

apiVersion: v1
kind: Service 
metadata: 
  name: webapp 
spec: 
  type: NodePort        # 设置 Service 类型为 NodePort
  ports: 
  - port: 8080             # 设置 Service 暴露的端口为 8080, 即8080(svc) <-> 80(pod)
    targetPort: 80        # 设置 Pod 的端口为 8080
    nodePort: 30081     # 设置 NodePort 的端口为 30081,即30081(NodePort) <-> 8080(svc) <-> 80(Pod) 
  selector:
    app: webapp 

 

 


Service 包含一组相关的容器,一起来提供服务。
将 Service 的端口映射到物理机的端口上,k8s会在每个工作节点上做端口映射,实现负载均衡服务,访问 curl <NodeIP>:30081,NodeIP 可以是集群中任意一个Node节点。
如果有 Haproxy 负载均衡服务,ClusterIP + Haproxy 为推荐方式


2.2 (第二种方法)通过 LoadBalancer 访问集群内部容器服务

NodePort提供了一种从外部网络访问Kubernetes集群内部Service的方法,但该方法存在下面一些限制,导致这种方式主要适用于程序开发,不适合用于产品部署。

  • Kubernetes cluster host的IP必须是一个well-known IP,即客户端必须知道该IP。但Cluster中的host是被作为资源池看待的,可以增加删除,每个host的IP一般也是动态分配的,因此并不能认为host IP对客户端而言是well-known IP。
  • 客户端访问某一个固定的host IP的方式存在单点故障。假如一台host宕机了,kubernetes cluster会把应用 reload到另一节点上,但客户端就无法通过该host的nodeport访问应用了。
  • 通过一个主机节点作为网络入口,在网络流量较大时存在性能瓶颈。
    为了解决这些问题,Kubernetes提供了LoadBalancer。通过将Service定义为LoadBalancer类型,Kubernetes在主机节点的NodePort前提供了一个四层的负载均衡器。该四层负载均衡器负责将外部网络流量分发到后面的多个节点的NodePort端口上。

下图展示了Kubernetes如何通过LoadBalancer方式对外提供流量入口,图中LoadBalancer后面接入了两个主机节点上的NodePort,后端部署了三个Pod提供服务。根据集群的规模,可以在LoadBalancer后面可以接入更多的主机节点,以进行负荷分担。

 

备注:LoadBalancer类型需要云服务提供商的支持,Service中的定义只是在Kubernetes配置文件中提出了一个要求,即为该Service创建Load Balancer,至于如何创建则是由Google Cloud或Amazon Cloud等云服务商提供的,创建的Load Balancer的过程不在Kubernetes Cluster的管理范围中。

目前WS, Azure, CloudStack, GCE 和 OpenStack 等主流的公有云和私有云提供商都可以为Kubernetes提供Load Balancer。一般来说,公有云提供商还会为Load Balancer提供一个External IP,以提供Internet接入。如果你的产品没有使用云提供商,而是自建Kubernetes Cluster,则需要自己提供LoadBalancer。

 

2.3(第三种方法)通过 Ingress 访问集群内部容器服务

 

 

鸣谢:

https://blog.csdn.net/u010942475/article/details/105205203

https://blog.csdn.net/weixin_44109082/article/details/102619230

posted @ 2022-07-08 13:05  春光牛牛  阅读(6583)  评论(0编辑  收藏  举报