本文主要研究一下使用k8s服务发现的优缺点

spring cloud vs kubernetes


这里有张spring cloud与kubernetes的对比,如果将微服务部署到kubernetes上面,二者有不少功能是重复的,可否精简。
这里主要是讲述一下如果不使用独立的服务发现,而是使用k8s的服务发现的优缺点

k8s服务发现原理

service与pod

service通过selector将标签符合指定条件的pod关联在一起

endpoints

endpoints用来记录一个service对应的pod的访问地址,存储在etcd中

endpoints controller

当用户创建service和对应的pod时,Endpoints Controller会监控pod的状态变化,当pod处于running和就绪状态时,Endpoints Controller会生成Endpoints对象

kube-proxy

运行在每个节点上的kube-proxy会监控service和endpoints的更新,并调用其load balancer模块在主机上刷新路由转发规则。当pod的liveness probe或者readiness probe检测不通过,pod处于非准备就绪状态时,kube-proxy会删除对应的转发规则。kube-proxy的load balancer模块实现有userspace、iptables、IPVS三种方式,iptables的方式在大规模(比如节点大于5000)场景下会有性能问题,一般使用IPVS方式。IPVS模式是基于LVS的负载均衡,即基于netfilter的方式,使用的是NAT模式,默认采用的是round-robin(rr)的负载均衡算法。

ClusterIP

service默认的type为ClusterIP,一旦service和endpoints场景,IPVS模式的kube-proxy会:

  • 确保一块dummp网卡(kube-ipvs0)存在,将service的访问ip绑定在dummy网卡上,让内核认为是本机ip,从而进入netfilter的INPUT链
  • 通过socket调用,创建IPVS的virtual server和real server,分别对应k8s的service和endpoints

示例

# kubectl describe svc nginx-service
    Name: nginx-service    
    Type: ClusterIP    
    IP:            10.102.128.4    
    Port: http    3080/TCP    
    Endpoints:     10.244.0.235:8080,10.244.1.237:8080    
    Session Affinity: None    ...    

# ip addr    
73: kube-ipvs0: <BROADCAST, NOARP> mtu 1500 qdisc noop state DOWN qlen 1000        
    link/ether 1a:ce:f5:5f:c1:4d brd ff:ff:ff:ff:ff:ff        
    inet 10.102.128.4/32 scope global kube-ipvs0          
        valid lft forever preferred lft forever    

...    

# ipvsadm -ln    
IP Virtual Server version 1.2.1 (size=4096)    
Prot LocalAddress:Port Scheduler Flags      
    -> RemoteAddress:Port          Forward Weight ActiveConn InActConn    
    TCP  10.102.128.4:3080 rr      
        -> 10.244.0.235:8080           Masq    1     0         0      
        -> 10.244.1.237:8080           Masq    1     0         0
来源于<<Kubernetes 网络权威指南:基础、原理与实践>>

整体链路

假设serviceA的pod0在node0上,serviceB有3个pod,pod1在node1上,pod2在node2,pod3在node3上,若此时serviceA对serviceB发起请求,其链路如下
pod0 (node0) -> DNS 解析获取 serviceB ClusterIP -> 根据iptables/ipvs规则 -> 路由至 serviceB 后端的pod1或者pod2或者pod3

如图

这里有两个链路:
1是client访问的时候解析到clusterip,走底层网络的IPVS规则路由到server端的某个pod
2是每个node的kube-proxy监听service和endpoints的更新然后更新对应的IPVS路由规则(virtual server和real server)

优缺点

优点

不用自己再部署一套服务发现,直接复用k8s的服务发现,省事

缺点

学习成本大

使用k8s的服务发现其实是将服务发现的中间件下沉到了基础设施(使用了IPVS或者iptables模式),需要有人对此原理比较精通,不然出问题了需要忙活半天

东西流量治理比较困难

k8s的服务发现本质是类似服务端的负载均衡,默认是rr轮询的方式(其他的支持lc最小连接、dh目标地址哈希、sh源地址哈希、sed最短时延),如果需要定制的比如加权,比如根据服务上线时间动态权重等,需要重新定制开发;再比如要进行灰度路由就需要依赖service mesh之类的

追踪困难

由于是服务端的负载均衡,如果没有加上分布式追踪,其实从调用方角度看很难知道最后调用了哪个实例,难度有点大

相关生态缺失或复杂

如果要使用全面的服务治理能力,需要套上service mesh,技术栈的复杂度更大,需要有这方面的人才,如果没有则相当于缺乏了服务治理;相较于nacos这类专业的服务发现的中间件来讲,它会配套ui界面,都是现成的,如果使用k8s的服务发现,相关的生态是缺失的

小结

使用K8S的服务发现看是挺好的,可以少维护一个服务发现的中间件,但是实际使用起来并不是那么美好。

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...