service是k8s中最核心的资源对象之一。
RC的作用是维持pod集群的一系列数量指标,保证service的服务能力和服务质量始终处于预期的标准范围内。
k8s中的service定义了一个服务的访问入口地址,这个地址是提供为集群内的其他service使用的。service提供的cluster ip,只在k8s内部有意义。
每个service背后对应的都是一个pod集群,所以访问一个服务的时候,必定需要一个负载均衡算法来支撑。
k8s中服务通信
运行在node上的kube-proxy进程其实就是一个智能的软件负载均衡器,它负责把本node上对service的请求转发到后端的某个pod上,并在内部实现服务的负载均衡和会话保持机制。与service通信的时候,肯定是不能直接使用ip地址(因为未知),会用服务名来进行通信,因此就需要一种机制来做ip到服务名的映射。显然,dns正好符合要求(环境变量注入的方式也可以提供相同的功能)。
一个典型的service定义文件如下:
1 | apiVersion: v1 |
可以看到,服务tomcat-service的服务端口为8080,拥有tier:frontend标签的pod都属于他。
创建命令:
1 | kubectl create -f tomcat-server.yaml |
服务发现机制
一句话概括,服务发现的过程,就是把服务名替换为ip:port的过程。
环境变量
在pod启动的时候,按照一定规范和约定,在pod 的环境变量中,注入所有的服务的信息。pod要访问某个服务时,就从自己本地的环境变量取出。
考虑到环境变量的方式获取service的ip和port的方式仍然不太方便,不够直观,后来k8s通过Add-on增值包的方式引入了DNS系统,把服务名作为DNS域名,这样以来,程序就可以直接使用服务名来建立通信连接了。
外部系统访问service的问题
三种ip:
Node IP: 实打实的网卡的ip;Pod IP: 根据docker0网桥的ip地址段进行分配的,通常是一个虚拟的二层网络。另外,k8s要求位于不同node上的pod能够彼此直接通信,所以k8s里的pod能够直接访问另外一个pod。Cluster IP:虚拟的IP。属于k8s集群这样一个封闭的空间。如果需要提供外部访问,要做一些额外的工作。
某些服务模块就是用来提供给外部使用的,那么用户如何访问?service定义扩展:
1 | apiVersion: v1 |
这样,服务31002就暴露出来了。NodePort的实现方式是,在k8s集群的每个NOde上为需要外部访问的service开启一个对应的tcp监听端口,外部系统只要用任意一个node的IP地址+具体的NodePort端口号就可以访问该服务。
问题:这种方式仍未解决所有问题,比如负载均衡问题,这是就需要一个集群之外的负载均衡组件来实施负载均衡。