k8s之服务注册与发现
现代的云原生应用由多个独立的微服务协同合作而成。为了便于通力合作,这些微服务
需要能够互相发现和连接。这时候就需要服务发现(Service discovery)功能出场了
关于服务发现有两个主要组件:
- 服务注册(Service registration)
- 服务发现
1、服务注册
所谓服务注册,即把微服务的连接信息注册到服务仓库,以便其他微服务能够发现它并进行连接,如图:

Kubernetes 使用一个内部DNS 服务作为服务注册中心,服务是基于DNS 注册的(而非具体的Pod),每个服务的名称、IP 地址和网络端口都会被注册,Kubernetes 提供了一个“众所周知”的内部DNS 服务,通常被称为“集群DNS”(cluster DNS)。之所以说是“众所周知”,是因为集群里的所有Pod 和容器都知道它的地址。实际上它是运行在kube-system 命名空间中,并被一个名为coredns 的Deployment 管理着的一组Pod。这一组Pod 前面也有一个Service,称为kube-dns。具体实现上,它是基于CoreDNS 的作为Kubernetes 原生应用(Kubernetes-native application)运行的一种DNS技术,查看service信息,如图:

查看具有标签k8s-app=kube-dns的pod,如图:

每一个Kubernetes Service 都会在创建之时被自动注册到集群DNS 中,大致的注册流程如下:
- 用户POST 一个新的Service 部署文件到API Server
- 该请求需通过认证、授权,并遵从准入策略
- Service 会被动态分配一个名为ClusterIP 的虚拟IP 地址
- 创建一个Endpoint 对象来记录所有匹配该Service 的Pod,以便进行流量的负载均衡
- 配置Pod 网络来承载发送至ClusterIP 的流量
- Service 的名称和IP 被注册到集群DNS 中
每个节点上的Kube-proxy进程都会监视API Server 上出现的新的Endpoint 对象,一旦发现,Kube-proxy 就会创建相应的网络规则,将ClusterIP 的流量转发至Pod 的IP,基于Linux 的Kubernetes 集群中要创建这些规则的技术使用的是Linux IP Virtual Server(IP 虚拟服务器,IPVS)。较旧版本的Kubernetes 使用的是iptables。

2、服务发现
服务发现如果要想其发挥作用,每个微服务需要知道如下两点:
- 要连接的远程微服务的名称(Service名称)
- Service名称解析后的IP地址(ClusterIP)
kubernetes会为每个容器注入/etc/resolv.conf文件,其中包含集群DNS服务的IP地址和搜索域,创建一个busybox镜像的pod,进入容器内部查看/etc/resolv.conf文件,如图:

- nameserver:集群DNS地址
- default.svc.cluster.local:优先在当前命名空间下查找Service
- svc.cluster.local:如果当前命名空间没找到就在集群范围内查找,可跨命名空间
- cluster.local:在集群的顶级域名下查找Service
举例:如果pod访问一个my-service的服务,会优先在此pod所在的命名空间查找Service,将此服务解析为my-service.default.svc.cluster,如果没找到就解析为my-service.svc.cluster.local继续查找,如果还没找到就解析为my-service.cluster.local,如果还没有说明不存在此Service
例:在命名空间default创建两个副本的nginx,再创建名称为service-nginx的Service,如图:


此时直接通过ClusterIP:8088是可以访问nginx的,如图:

同样在default创建2个副本的busybox,然后进去pod内部,通过Service名称来访问,如图:

查看输出的out.html文件,已经访问成功,如图:

访问成功说明已经通过集群DNS将service-nginx名称解析其对应的ClusterIP,每个节点都运行着kube-proxy服务,它监视API Server上新创建的Service 和Endpoint 的控制器。当它有新发现时,就回创建一条本地的IPVS 规则,该规则告诉主机节点拦截发往Service的ClusterIP 的流量,并发送至具体的Pod
注意:并不存在直接到达ClusterIP的路由,请求会被发送至容器的默认网关,也就是容器所在的节点,节点也没有到达ClusterIP的路由,节点会将请求发送到节点的默认网关,然后被节点内核处理,并被kube-proxy捕获,根据IPVS规则发送到后面pod

如果是nginx的服务在default命名空间,而busybox的服务在gong命名空间,此时通过busybox来访问nginx的时候就需要指定nginx所在命名空间,Service.Namespace,如图:



