K8s对外暴露服务的方式有三种:
一、NodePort
将服务的类型设置成NodePort-每个集群节点都会在节点上打 开 一个端口, 对于NodePort服务, 每个集群节点在节点本身(因此得名叫NodePort)上打开一个端口,并将在该端口上接收到的流量重定向到基础服务。该服务仅在内部集群 IP 和端口上才可访间, 但也可通过所有节点上的专用端口访问。
在k8s上可以给Service设置成NodePort类型,这样的话可以让Kubernetes在其所有节点上开放一个端口给外部访问(所有节点上都使用相同的端口号), 并将传入的连接转发给作为Service服务对象的pod。这样我们的pod就可以被外部请求访问到,但是问题是每个节点都得开端口,一旦服务多了,端口管理会比较麻烦,而且某个节点如果没有运行的service的时候会怎样?
步骤1,创建Service的YAML描述文件
使用kubectl expose命令创建了 一个service的yaml文件,示例:
kubectl expose deployment countgame --port=8082 --target-port=8082 --type=NodePort -o yaml --dry-run > svc.yaml
步骤2,创建Service对象
步骤3,外部请求访问
在浏览器通过Node+端口的来访问我们的这个项目url
可以看到,在我们的master、node01、node02三个服务器的都可以访问,所有节点上都监听同一个端口号,这样就通过NodePort暴露端口给外部访问进来。
总结
简单,但是服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护,所以生产环境不建议这么使用。
二、LoadBalane
LoadBalane是上面通过NodePort暴露外部访问的一个优化,增加了一个负载均衡器,上面的NodePort是所有节点都开放一个端口,直接给外部访问,并没有Node节点的负载均衡。LoadBalane则是在上面的基础上增加了一层,只提供一个公网ip给外部访问,外部访问这个ip再负载均衡分发给Node节点的Pod
总结
最大缺点是每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址和端口,不能做到一个ip地址就可以访问所有服务。
三、Ingress
采用 NodePort 方式暴露服务面临问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;如果采用LoadBalane,每个服务都得开放一个公网IP,也会很庞大。这时候Ingress暴露服务就是一种很合适的方案。可以通过一个Ingress暴露多个服务。
如何实现?我们先想想有没有只开放一个IP就能访问所有服务呢?类似于网关的那种?我们可以能否使用一个Nginx直接对内进行转发呢?众所周知的是,Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间的,也就是说当在共享网络名称空间时,Pod上所监听的就是Node上的端口。那么这又该如何实现呢?简单的实现就是在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了,如下图所示:
即每个Node节点通过NodePort类型的Service绑定80端口,转发请求给我们一个Nginx的Pod,然后在Nginx里面再转发给我们其他的Service的Pod,这样我们就可以只提供一个端口给外部网络,我们的Service都在Nginx里面配置一个转发规则不就可以了吗?
从上面的方法,采用 Nginx-Pod 似乎已经解决了问题,但是其实这里面有一个很大缺陷:当每次有新服务加入又该如何修改 Nginx 配置呢??我们知道使用Nginx可以通过虚拟主机域名进行区分不同的服务,而每个服务通过upstream进行定义不同的负载均衡池,再加上location进行负载均衡的反向代理,在日常使用中只需要修改nginx.conf即可实现,那在K8S中又该如何实现这种方式的调度呢???
此时 Ingress 出现了,如果不算上面的Nginx,Ingress 包含两大组件:Ingress Controller 和 Ingress。
Ingress 简单的理解就是你原来需要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了;那么问题来了:”Nginx 怎么才能动态处理配置?”
Ingress Controller 这东西就是解决 “Nginx 怎么才能动态处理配置” 的程序(可以简单理解成Ngixn程序,实际不一定,实现方案有很多种);Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图:
简单的来说,就是每个Node节点通过NodePort类型的Service绑定80端口,转发请求给我们的Ingress-Controller的Pod(类似于Nginx), Ingress-Controller再根据域名规则转发给我们其他的Service的Pod,Ingress-Controller可以动态感知Ingress对象,读取Ingress对象的规则,生成一段Ngixn的转发规则配置。
总结:
K8S Ingress = 微服务网关, 本质:七层反向代理,微服务集中出入口。
参考
《Kubernetes in Action中文版》
烟雨浮华的《Kubernetes学习之路(十五)之Ingress和Ingress Controller》