1 基础概念
1.1 containerPort、port、nodePort、targetPort的区别与联系
- containerPort:Container容器暴露的端口。containerPort是在pod控制器中定义的、pod中的容器需要暴露的端口。
- port:service暴露在集群中的端口,仅限集群内部访问。port是暴露在cluster (集群网络)上的端口,提供了集群内部客户端访问service的入口,即clusterIP:port。mysql容器暴露了3306端口(参考DockerFile),集群内其他容器通过33306端口访问mysql服务,但是外部流量不能访问mysql服务,因为mysql服务没有配置NodePort。
- nodePort:集群节点Node暴露在外网中的端口。nodePort提供了集群外部客户端访问service的一种方式,即nodeIP:nodePort提供了外部网络访问k8s集群中service的入口。
- targetPort:Pod暴露的端口。targetPort是pod上的端口,从port/nodePort下来的数据,经过kube-proxy流入到后端pod的targetPort上,最后进入容器,因此targetPort与容器的containerPort必须一致。
2. Service网络:ClusterIp
在Kubernetes中,Pod是非持久性的资源,可以按照需要创建和销毁。当使用Deployment来运行应用时,可以根据需要动态地创建或销毁Pod,实现水平扩缩容。
当引入Deployment,并为Pod设置多个副本时,那么某一个服务就会有多个pod及多个podIp,此时即使知道了这些Pod的IP,那访问起来也并不方便。此外,Pod的IP地址是动态分配的,可能发生变化,所以在实际通信中,直接使用Pod的IP地址进行通信会有一些问题。为了解决这个问题,Kubernetes引入了Service的概念。
所以,这里需要有一个统一入口,其它Pod通过这个统一入口去请求该服务(Nginx)对应的所有Pod。这时就有了Service这个资源对象,它主要作用就是用来提供统一入口,也就是说只需要一个IP就能访问所有的Pod,而这个入口IP就是ClusterIP,也就是Service的IP。
Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,但Cluster IP是一个完全虚拟的IP,没有网络设备与其对应。
- Cluster IP仅仅作用于Kubernetes Service这个对象,并由Kubernetes管理和分配P地址
- Cluster IP无法被ping,他没有一个“实体网络对象”来响应
- Cluster IP只能结合Service Port组成一个具体的通信端口,单独的Cluster IP不具备通信的基础,并且他们属于Kubernetes集群这样一个封闭的空间。
- 虚拟 ip 是固定的,这也是service可以解决pod动态ip的原因
Service是一种持久性资源,它可以提供一个或多个端点(Endpoint),并通过标签选择器选择指向集群中的一组Pod。Service使用ClusterIP来提供内部集群的网络连接,ClusterIP是固定的虚拟ip,这样就可以通过Service来访问Pod,而不需要直接使用Pod的动态IP地址。当创建一个Deployment并运行应用时,通常会创建一个或多个Service来提供访问Pod的接口。这样,即使Pod的IP地址发生变化,通过Service的端点仍然可以访问到Pod,以确保集群内的可靠通信,并避免因Pod的动态变化而引起的问题。
K8s通过在引入一层Service抽象,还能解决以下问题:
- 服务发现:Service提供统一的ClusterIP来解决服务发现问题,Client只需通过ClusterIP就可以访问App的Pod集群,不需要关心集群中的具体Pod数量和PodIP,即使是PodIP发生变化也会被ClusterIP所屏蔽。注意,这里的ClusterIP实际是个虚拟IP,也称Virtual IP(VIP)。
- 负载均衡:Service抽象层具有负载均衡的能力,支持以不同策略去访问App集群中的不同Pod实例,以实现负载分摊和HA高可用。K8s中默认的负载均衡策略是RoundRobin,也可以定制其它复杂策略。
Service在上述K8s集群中被画成一个独立组件,实际是没有独立Service这样一个组件的,只是一个抽象概念。
2.1 服务发现
K8s通过一个ServiceName+ClusterIP统一屏蔽服务发现和负载均衡,底层技术是在DNS+Service Registry基础上发展演进出来。K8s的服务发现和负载均衡是在客户端通过Kube-Proxy + iptables转发实现,它对应用无侵入,且不穿透Proxy,没有额外性能损耗。K8s服务发现机制,可以认为是现代微服务发现机制和传统Linux内核机制的优雅结合。
3. 外部访问集群网络
3.1 NodePort
K8s的Service网络ClusterIp只是一个集群内部网络,集群外部是无法直接访问的。如果我们要将K8s内部的一个服务通过NodePort方式暴露出去,使用Service的NodePort类型,将Service的ClusterIP对应的Port映射到每一个Node的IP上,映射出去的Port范围为30000~32767。
Service NodePort服务发布以后,K8s在每个Worker节点上都会开启nodePort这个端口。这个端口的背后是Kube-Proxy,当K8s外部有Client要访问K8s集群内的某个服务,它通过这个服务的NodePort端口发起调用,这个调用通过Kube-Proxy转发到内部的Servcie抽象层,然后再转发到目标Pod上。
3.2 LoadBalancer云负载均衡器
在NodePort的基础上增加了云服务商提供的负载均衡器Load-Balancer,使用该均衡器后进行访问时不需要再带着nodePort30055,可以将流量自动分配到集群的不同节点上。
3.3 Nginx Service反向代理、域名
Nodeport只支持四层的数据包转发,所以不支持基于域名的做分流,基于uri做匹配。因此我们考虑在Nodeport上添加一层Nginx Service进行反向代理。
使用 Nginx 作为反向代理服务器是一种常见的做法,它可以为多个服务提供负载均衡和路由功能。在这种情况下,Nginx 通常被部署在一个单独的 Pod 中,并且该 Pod 会被 Service 暴露给外部网络。当外部请求到达 Nginx Service 时,它会被路由到 Nginx Pod。然后,Nginx Pod 根据配置将请求转发到相应的 APP Service。
上图为抓包模拟客户端访问的情况,通过抓包我们可以发现在使用Nginx进行反向代理时访问pod中的服务需要进行大量包的传输,在实验时访问一个静态页面需要请求59个包,这带来了巨大的资源损失,因此引出了Ingress。
4.4 Ingress 代理服务
Ingress算是Service上面的一层代理,通常在 Service前使用Ingress来提供HTTP路由配置。它让我们可以设置外部 URL、基于域名的虚拟主机、SSL 和负载均衡。
ingress相当于一个7层的负载均衡器,是k8s对反向代理的一个抽象。大概的工作原理也确实类似于Nginx,可以理解成在 Ingress 里建立一个个映射规则 , ingress Controller 通过监听 Ingress这个api对象里的配置规则并转化成 Nginx 的配置(kubernetes声明式API和控制循环) , 然后对外部提供服务。ingress包括:ingress controller和ingress resources
- ingress controller:核心是一个deployment,实现方式有很多,比如nginx, Contour, Haproxy, trafik, Istio,需要编写的yaml有:Deployment, Service, ConfigMap, ServiceAccount(Auth),其中service的类型可以是NodePort或者LoadBalancer。
- ingress resources:这个就是一个类型为Ingress的k8s api对象了,这部分则是面向开发人员。
如上图所示,为使用Ingress之后的抓包流程,可以看到此时eth0与docker网桥并没有通过Kube-Proxy进行通信,而是直接通过Ingress Controller进行通信,再次抓包访问一个静态网页需要35个包。
原文链接:https://blog.csdn.net/qq_45808700/article/details/132714651