一起学kubernetes系列(2)‌

本篇文章我们介绍Kubernetes Service的各个类型,各类端口的含义,向外部暴露内部服务的方式。

Service 介绍

Kubernetes中一个应用服务会有一个或多个实例(Pod),每个实例(Pod)的IP地址由网络插件动态随机分配(Pod重启后IP地址会改变)。为屏蔽这些后端实例的动态变化和对多实例的负载均衡,引入了Service这个资源对象,如下所示:

  1. apiVersion : v1
  2. kind : Service
  3. metadata :
  4. name : nginx - svc
  5. labels :
  6. app : nginx
  7. spec :
  8. type : ClusterIP
  9. ports :
  10. - port : 80
  11. targetPort : 80
  12. selector :
  13. app : nginx

Service type

服务可以被外部的客户访问,也可以被内部的客户访问。Service通过创建时指定的标签选择器来决定用户的请求转发到后台的哪些Pods中。根据创建Service的 ​ type ​类型不同,常见的,可分成3种模式 :

  • ClusterIP ​:默认方式 , 通过为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP),实现集群内的访问。为最常见的方式。
  • NodePort ​:除了使用Cluster IP之外,还通过将service的port映射到集群内每个节点的相同一个端口,实现通过nodeIP:nodePort从集群外访问服务。
  • LoadBalancer ​:和nodePort类似,不过除了使用一个Cluster IP和nodePort之外,还会向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的nodePort),实现从集群外通过LB访问服务。

Service与endpoints

  • Endpoints 是组成Service的一组IP地址和端口资源。
  • Kubernetes在创建Service时,根据Service的标签选择器(Label Selector)来查找Pod,据此创建与Service同名的EndPoints对象。当Pod的地址发生变化时,EndPoints也随之变化。Service接收到请求时,就能通过EndPoints找到请求转发的目标地址。
  • kube-proxy根据Service和Endpoint来维护本地的路由规则。当Endpoint发生变化,即Service以及关联的pod发生变化,kube-proxy都会在每个节点上更新iptables,实现一层负载均衡。
  1. #查询Service与endpoints
  2. kubectl get service , endpoints -- all - namespaces

Service的各种Port与IP

PORT

  • port ​​:这是service的端口,通过 ​ ​clusterip​ ​和 ​ ​port​ ​即可访问到service服务,返回为pod tag,注意必须ip和端口缺一不可!
  • nodePort ​​: ​ ​nodePort​ ​的范围是30000-32767,集群内不允许冲突,在service的yaml中设置 , 一旦设置了 ​ ​nodePort​ ​,所有的node主机都会监听这个端口,也就是说使用集群内任意一台 ​ ​nodeIP:nodePort​ ​都可以访问到service服务,同样,在集群内此端口就只能被设置一次。
  • containerPort ​:容器的实际端口,Pod内的容器与外部进行通信的端口,Pod中的所有容器共享一个网络IP,容器间可直接用localhost访问。
  • targetPort ​​:Pod上的端口,从 ​ ​port​ ​和 ​ ​nodePort​ ​上到来的数据最终经过kube-proxy流入到后端pod的 ​ ​targetPort​ ​上进入容器。所以需要在service的yaml中定义,来告诉service。
  • hostPort ​​: ​ ​hostPort​ ​是直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过宿主机的IP加上来访问Pod了。

port汇总

  1. containerPort 和 targetPort 放在一起理解,两个不是一个概念,前者容器的port,负责容器间的交流,前者在deploy yaml中设置,后者再在svc yanl 中设置,与kube-proxy进行连接,不强制保持一致!请求先通过targetProt到到达pod,然后再通过containerPort 进入容器!
  2. port 和 nodePort 放在一起理解,前者是在集群内访问service 需要的端口,需要结合clusterip ,缺一不可!
  3. 如果想在集群外访问,则需要将service变成nodePort的类型,需要抛出nodeProt,使用集群任意node ip即可访问!
  4. hostPort 是集群外想访问pod 需要抛出的端口,使用pod 所在node 的ip,结合此端口实现!因为pod ip变换莫测,所以应用比较局限,需要自己维护这个变化,比如node打上标签!
  5. targetPort 和port 默认是相同的,可以不同!

IP

  • PodIP ​:Pod的IP,每个Pod启动时,会自动创建一个镜像为gcr.io/googlecontainers/pause的容器,Pod内部其他容器的网络模式使用container模式,并指定为pause容器的ID,即:networkmode: "container:pause容器ID",使得Pod内所有容器共享pause容器的网络,与外部的通信经由此容器代理,pause容器的IP也可以称为Pod IP。
  • ClusterIP ​:Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,但clusterIP就不一样了,没有网络设备承载这个地址。它是一个虚拟地址,由kube-proxy使用iptables规则重新定向到其本地端口,再均衡到后端Pod。当kube-proxy发现一个新的service后,它会在本地节点打开一个任意端口,创建相应的iptables规则,重定向服务的clusterIP和port到这个新建的端口,开始接受到达这个服务的连接。
  • 节点IP ​:Node-IP,service对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。指定service的spec.type=NodePort,这个类型的service,系统会给它在集群的各个代理节点上分配一个节点级别的端口,能访问到代理节点的客户端都能访问这个端口,从而访问到服务。

对外暴露内部服务

  • hostNetwork:true ​​:在yaml文件中 ​ ​spec​ ​部分指定,如果在POD中使用 ​ ​hostNetwork:true​ ​配置网络,pod中运行的应用程序可以直接看到宿主主机的网络接口,从而使其可以使用宿主主机网络端口。宿主主机所在的局域网上所有网络接口都可以访问到该应用程序。hostNetwork模式不再需要创建一个service yaml。该配置的缺点:应用的网络与宿主机一样,需保证应用需要监听的网络端口在宿主机上没有被占用。并且无法使用容器漂移,动态伸缩特性。
  • HostPort ​​:在yaml文件中 ​ ​spec.containers.ports​ ​部分指定, 通过HostPort设置,您可以请求暴露主机上的任何可用端口。指定HostPort后,在部署pod容器的主机上,该端口会暴露给外部访问。在 ​ ​hostIP:HostPort​ ​上的流量将会被路由到pod容器的专用端口。 ​ ​HostPort​ ​模式不再需要创建一个service yaml。
  • K8S Service基础详解_负载均衡
  • PortForward ​:通过端口转发访问集群中的应用程序 ,这种类型的连接对于调试很有帮助。配置方法:当前机器必须配置有目标集群的kubectl config:
  1. #测试本地机器8099端口转发到目标nginx pod的80端口:
  2. kubectl port - forward - n default nginx 8099 : 80
  • ClusterIP ​​: ​ ​ClusterIP​ ​本身是不会对集群外暴露服务的,但是却单单可以通过K8s Proxy API来访问。Proxy API是一种特殊的API,Kube-APIServer只代理这类API的HTTP请求,然后将请求转发到某个节点上的Kubelet进程监听的端口上,最后有该端口上的REST API响应请求。在集群外部访问,需要借助于kubectl,所以集群外的节点必须配置了经过认证的kubectl,可以参看kubectl的配置章节,这种方式要求访问节点必须具备受认证的kubectl,所以只能用做调试使用。
  1. kubectl proxy -- port = 8080
  2. #通过selfLink即可访问,注意这里的服务名需要指定https
  3. curl http : //localhost:8080/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
  • NodePort ​​:NodePort是基于ClusterIP的方式来暴露服务的,不过不需要kubectl的配置,他是在每一个node上都监听同一个端口,该端口的访问都会被引导到Service的ClusterIP 。 ​ ​NodePort​ ​的默认范围是:30000-32767。从Kubernetes集群外部,进入 ​ ​NodeIP:NodePort​ ​的流量将被定向到工作负载(由kube-proxy组件完成这项工作)。NodeIP可以是Kubernetes集群中任何节点的IP地址。
  • K8S Service基础详解_负载均衡_02
  • LoadBalancer ​:只能在Service上定义,LoadBalancer是一些特定公有云提供的负载均衡器,需要特定的云服务商提供,比如:AWS、Azure、OpenStack 和 GCE (Google Container Engine)。
  • Ingress ​:与之前的暴露集群Service的方式都不同,Ingress其实不是一种服务。它位于多个服务之前,充当集群中的智能路由器或入口点。类似于Nginx提供的反向代理,其实官方推荐的方式就是Nginx的实现方式。Ingress是自kubernetes1.1版本后引入的资源类型。必须要部署Ingress controller才能创建Ingress资源,Ingress controller是以一种插件的形式提供。使用 Ingress 时一般会有三个组件:
  1. 反向代理负载均衡器
  • 反向代理负载均衡器很简单,类似nginx,haproxy;在集群中反向代理负载均衡器可以自由部署,可以使用 Replication Controller、Deployment、DaemonSet 等等,推荐DaemonSet 的方式部署
  • Ingress Controller
  • Ingress Controller 实质上可以理解为是个监视器,Ingress Controller 通过不断地跟 kubernetes API 打交道,实时的感知后端 service、pod 等变化,比如新增和减少 pod,service 增加与减少等;当得到这些变化信息后,Ingress Controller 再结合下文的 Ingress 生成配置,然后更新反向代理负载均衡器,并刷新其配置,达到服务发现的作用。
  • Ingress
  • Ingress简单理解就是个规则定义;比如说某个域名对应某个 service,即当某个域名的请求进来时转发给某个 service;这个规则将与 Ingress Controller 结合,然后 Ingress Controller 将其动态写入到负载均衡器配置中,从而实现整体的服务发现和负载均衡。
  • IngressRoute ​​:Traefik 1.x只能够通过 [Kubernetes Ingress provider] 来支持 Kubernetes,这是严格意义上的 Kubernetes Ingress 控制器。但是,由于社区表达了需要从 Traefik 优秀特性中获益而不需要使用大量的 annotations 注解,最终Traefik 2.x实现了一个名为 IngressRoute 的自定义资源类型,可以提供更好的方式来配置对 Kubernetes 集群的访问。
    我们将会在下面的文章中详细讲解使用Traefik 2.0.2的 ​ ​IngressRoute​ ​来实现各种对外暴露TCP,HTTPS内部服务及自动生成证书等功能。
    K8S Service基础详解_负载均衡_03