kubernetes服务发现

一、kubernetes架构

 

 

kube-apiserver : Kubernetes API,集群的统一入口,各组件协调者,以RESTful API提供接口服务,所有对象资源的增删改查和监听操作都交给APIServer处理后再提交给Etcd存储

kube-controller-manager:处理集群中常规后台任务,一个资源对应一个控制器,ControllerManager负责管理这些控制器

kube-scheduler:根据调度算法为新创建的Pod选择一个Node节点,可以任意部署, 可以部署在同一个节点上,也可以部署在不同的节点上

Etcd:分布式键值存储系统,用于保存集群状态数据,比如Pod、Service 等对象信息

Kubelet: kubelet是Master在Node节点上的Agent,管理本机运行容器的生命周期,比如创建容器、 Pod挂载数据卷、下载secret、获取容器和节点状态 等工作。kubelet将每个Pod转换成一组容器。

kube-proxy:在Node节点上实现Pod网络代理,维护网络规则和四层负载均衡工作

docker:容器引擎,运行容器

 

二、pod创建以及通信

1、Pod phase状态

 

  • 挂起(Pending):API Server创建了Pod资源对象并已经存入了etcd中,但是并未被调度完成。
  • 运行中(Running):Pod已经被调度到某节点之上,并且所有容器都已经被kubelet创建完成。
  • 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。
  • 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。
  • 未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。

 

2、pod创建

 

3、pod通信

 

一个服务经常会起多个pod,到底访问那个pod的ip呢?

pod经常会因为各种原因被调度,调度后一个pod的ip会发生变化

pod的ip是虚拟的且局域的,在集群内部访问没有问题,但是从k8s集群的外部如何访问

 

4、services服务发现 

 

对Pod资源对象进行打标签,用于Pod的辨识,而Servcie通过标签选择器,关联至同一标签类型的Pod资源对象。这样就实现了从service→pod→container的一个过程。

Type 的取值:

  • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType
  • NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 <NodeIP>:<NodePort>,可以从集群的外部访问一个 NodePort 服务。
  • LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
  • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如,example.com)。 没有任何类型代理被创建,Kubernetes 1.7 或更高版本的 kube-dns支持。

 

Service资源基于标签选择器将一组Pod定义成一个逻辑组合,并通过自己的IP地址和端口调度代理请求到组内的Pod对象,类似于负载均衡器功能,并且是基于TCP/IP 协议栈的四层负载

4.1 Service实现模型

 Kubernetes v1.0 版本,默认 userspace代理模式。

 Kubernetes v1.2 版本,默认 iptables 代理模式

Kubernetes v1.11版本,默认ipvs代理模式

1、userspace代理模式

kube-proxy 组件始终监视着api server中有关service的变动信息,通过watch监视,一旦有service资源相关的变动和创建,kube-proxy就会转换为当前节点上的能够实现资源调度规则

(1)客户端Pod请求内核空间的service iptables,

(2)请求转到给用户空间监听的kube-proxy 的端口,

(3)由kube-proxy将请求转给内核空间的 service ip,

(4)再由service iptalbes根据请求转给各节点中的的service pod。

由此可见这个模式有很大的问题,由客户端请求先进入内核空间的,又进去用户空间访问kube-proxy,由kube-proxy封装完成后再进去内核空间的iptables,再根据iptables的规则分发给各节点的用户空间的pod。这样流量从用户空间进出内核带来的性能损耗是不可接受的

 

2、iptables代理模式

(1)客户端Pod请求内核空间的service iptables

(2)根据iptables的规则直接将请求转发到到各pod上

如果集群中存在上万的Service/Endpoint,那么Node上的iptables rules将会非常庞大,性能会打折扣。

 

3、ipvs代理模式

(1)客户端Pod请求内核空间的ipvs

(2)根据ipvs的规则直接分发到各pod上

kube-proxy会监视Kubernetes Service对象和Endpoints,调用netlink接口创建ipvs规则并定期与Kubernetes Service对象和Endpoints对象同步ipvs规则,访问服务时流量将被重定向到其中一个后端Pod。

ipvs使用哈希表作为底层数据结构并在内核空间中工作,可以更快地重定向流量,并且在同步代理规则时具有更好的性能。

此外,ipvs的负载均衡算法比iptables更多,例如:

  • rr:轮询调度
  • lc:最小连接数
  • dh:目标哈希
  • sh:源哈希
  • sed:最短期望延迟
  • nq:不排队调度

注意: kube-proxy将验证节点上是否安装了IPVS模块,如果未安装,则kube-proxy将回退到iptables代理模式。

 

如果服务后端pod发生变化,增加或者删除,controller-manage会立即反映到apiserver上,而kube-proxy一直watch api server,感知到变化后转为ipvs或者iptables中的规则,这一切都是动态和实时的。

 

同时使用kube-dns可以解决Service的发现问题,k8s将Service的名称当做域名注册到kube-dns中,通过Service的名称就可以访问其提供的服务。

4.2 向外界暴露服务

1、pod漂移问题

Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;

那么如何把这个动态的 Pod IP 暴露出去?借助Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;

这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Pod IP 上

2、端口管理问题

采用 NodePort 方式暴露服务面临问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;

这时,我们可以使用一个Nginx直接对内进行转发,Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间的,当在共享网络名称空间时,Pod上所监听的就是Node上的端口。简单的实现就是使用 DaemonSet 在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了

 

3、域名分配及动态更新问题

当每次有新服务加入又该如何修改 Nginx 配置呢?总不能每次手动改或者Rolling Update 前端 Nginx Pod 吧,此时 Ingress 出现了,Ingress 包含两大组件:Ingress Controller 和 Ingress。

Ingress 简单的理解就是原来需要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象可以用 yaml 创建,每次不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了;

Ingress Controller 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取规则,按照自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,Ingress Controller需要单独部署

yaml配置

 

Ingress 中的spec字段是Ingress资源的核心组成部分:

    rules: 用于定义当前Ingress资源的转发规则列表;由rules定义规则,或没有匹配到规则时,所有的流量会转发到由backend定义的默认后端

    backend: 默认的后端用于服务那些没有匹配到任何规则的请求;定义Ingress资源时,必须要定义backend或rules两者之一,该字段用于让负载均衡器指定一个全局默认的后端。

    backend对象的定义由2个必要的字段组成:serviceName和servicePort,分别用于指定流量转发的后端目标Service资源名称和端口。

 

部署的流程如下:

①下载Ingress-controller相关的YAML文件,并给Ingress-controller创建独立的名称空间;
②部署后端的服务,如rtaas,并通过service进行暴露;
③部署Ingress-controller的service,以实现接入集群外部流量;
④部署Ingress,进行定义规则,使Ingress-controller和后端服务的Pod组进行关联。

 

参考文献:

https://kubernetes.io/zh/docs/concepts/services-networking/

http://docs.kubernetes.org.cn/230.html

https://www.cnblogs.com/yaohong/p/11361784.html#auto-id-6

https://www.cnblogs.com/linuxk/p/10436260.html

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柯·金

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值