k8s中的service简要介绍

servicek8s中最核心的资源对象之一。

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
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
ports:
- port: 8080
selector:
tier: frontend

可以看到,服务tomcat-service的服务端口为8080,拥有tier:frontend标签的pod都属于他。

创建命令:

1
kubectl create -f tomcat-server.yaml

服务发现机制

一句话概括,服务发现的过程,就是把服务名替换为ip:port的过程。

环境变量

pod启动的时候,按照一定规范和约定,在pod 的环境变量中,注入所有的服务的信息。pod要访问某个服务时,就从自己本地的环境变量取出。

考虑到环境变量的方式获取serviceipport的方式仍然不太方便,不够直观,后来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
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
type: NOdePort
ports:
- port: 8080
nodePort: 31002
selector:
tier: frontend

这样,服务31002就暴露出来了。
NodePort的实现方式是,在k8s集群的每个NOde上为需要外部访问的service开启一个对应的tcp监听端口,外部系统只要用任意一个nodeIP地址+具体的NodePort端口号就可以访问该服务。
问题:这种方式仍未解决所有问题,比如负载均衡问题,这是就需要一个集群之外的负载均衡组件来实施负载均衡。