一起学kubernetes系列(2)
本篇文章我们介绍Kubernetes Service的各个类型,各类端口的含义,向外部暴露内部服务的方式。
Service 介绍
Kubernetes中一个应用服务会有一个或多个实例(Pod),每个实例(Pod)的IP地址由网络插件动态随机分配(Pod重启后IP地址会改变)。为屏蔽这些后端实例的动态变化和对多实例的负载均衡,引入了Service这个资源对象,如下所示:
-
apiVersion
:
v1
-
kind
:
Service
-
metadata
:
-
name
:
nginx
-
svc
-
labels
:
-
app
:
nginx
-
spec
:
-
type
:
ClusterIP
-
ports
:
-
-
port
:
80
-
targetPort
:
80
-
selector
:
-
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,实现一层负载均衡。
-
#查询Service与endpoints
-
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汇总
-
containerPort 和 targetPort 放在一起理解,两个不是一个概念,前者容器的port,负责容器间的交流,前者在deploy yaml中设置,后者再在svc yanl 中设置,与kube-proxy进行连接,不强制保持一致!请求先通过targetProt到到达pod,然后再通过containerPort 进入容器!
-
port 和 nodePort 放在一起理解,前者是在集群内访问service 需要的端口,需要结合clusterip ,缺一不可!
-
如果想在集群外访问,则需要将service变成nodePort的类型,需要抛出nodeProt,使用集群任意node ip即可访问!
-
hostPort 是集群外想访问pod 需要抛出的端口,使用pod 所在node 的ip,结合此端口实现!因为pod ip变换莫测,所以应用比较局限,需要自己维护这个变化,比如node打上标签!
-
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。
-
-
PortForward
:通过端口转发访问集群中的应用程序 ,这种类型的连接对于调试很有帮助。配置方法:当前机器必须配置有目标集群的kubectl config:
-
#测试本地机器8099端口转发到目标nginx pod的80端口:
-
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,所以只能用做调试使用。
-
kubectl proxy
--
port
=
8080
-
#通过selfLink即可访问,注意这里的服务名需要指定https
-
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地址。
-
-
LoadBalancer
:只能在Service上定义,LoadBalancer是一些特定公有云提供的负载均衡器,需要特定的云服务商提供,比如:AWS、Azure、OpenStack 和 GCE (Google Container Engine)。
-
Ingress
:与之前的暴露集群Service的方式都不同,Ingress其实不是一种服务。它位于多个服务之前,充当集群中的智能路由器或入口点。类似于Nginx提供的反向代理,其实官方推荐的方式就是Nginx的实现方式。Ingress是自kubernetes1.1版本后引入的资源类型。必须要部署Ingress controller才能创建Ingress资源,Ingress controller是以一种插件的形式提供。使用 Ingress 时一般会有三个组件:
-
反向代理负载均衡器
-
反向代理负载均衡器很简单,类似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内部服务及自动生成证书等功能。