service是一组逻辑pod的抽象,为一组pod提供统一接入服务,用户只需与service打交道,service提供DNS解析名称,负责追踪pod动态变化并更新转发表,通过负载均衡算法最终将流量转发到后端pod

Service原理

假设已经通过Deployment副本控制器创建了3个pod,每个pod包含"app=test-app"标签,每个pod暴露端口9376。只所以假设已经有3个pod实例是为了方便说明service工作原理,推荐的做法是先创建service后创建pod。

## 启动命令 kubectl create -f test-service.yaml
kind: Service
apiVersion: v1
metadata:
  name: test-service
spec:
  selector:
    app: test-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
    
## 启动后查询如下:
[root@xxx ~]# kubectl get svc
NAME      TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
test-app  ClusterIP   172.24.1.1      <none>       80/TCP            11d

工作流程如下:

  • 为实例分配置集群虚拟IP。如果在声明时明确指定集群虚拟IP,则分配指定IP,如未指定则自动分配。
  • 根据实例名称、分配的集群虚拟IP、端口号创建DNS条目。
  • 根据标签选择器聚合符合条件的节点pod,并创建相应endpoint,endpoint包含所有符合条件pod的ip地址与端口号。如果没有符合条件的pod,或者pod在集群外,则需要手动创建endpoint
  • kube-proxy运行在集群中每一个节点上,并持续监控集群中service、endpoint变更,根据监控结果设置转发规则,将一个集群虚拟IP、端口与一个或者多个pod的IP、端口映射起来。
  • 当在集群内部通过服务名称访问创建的service时,首先由DNS将服务名称转换成集群虚拟IP与端口号,kube-proxy根据转发规则对service的流量计算负载均衡、转发到位于后端的pod。

集群虚拟IP与kube-proxy

什么是虚拟IP?一般情况下,一个IP地址都会被分配给一个二层网络设备,网络设备可以是物理的、也可以是虚拟的,但总有设备对IP地址对应。而kubernetes中的集群IP,只是三层网络上的一个地址,没有设备与其对应,因此集群IP又是虚拟IP。

kube-proxy是kubernetes核心组件,运行在集群中每一个节点上,负责监控集群中service、endpoint变更,维护各个节点上的转发规则,是实现servcie功能的核心部件。在1.8及以后的版本中,kube-proxy有以下三种工作模式,但不同版本kubernetes能支持的工作模式不同,注意查证。

  • 用户空间模式
  • iptables 跟用户空间模式的区别就是客户端是否经过kube-proxy
  • ipvs 工作在内核态,有更好的性能,支持多种负载均衡算法

服务发现

  • 环境变量
  • DNS service_name.namespace_anme.svc.cluster.local

Service类型

本文以上示例都以默认服务类型为前提,实际上kubernetes暴露服务IP的类型有四种,分别如下:

  • ClusterIP:默认类型,为服务分配集群虚拟IP,此时集群内部的pod可以通过服务名称寻址到服务的集群虚拟IP地址,集群外无效。
  • NodePort:在每个节点上为服务分配静态端口号,注意此端口号占用的是节点网络,此时如果在集群外部访问任何一个节点的IP地址加指定的端口号,kube-proxy会将流量转发到服务的集群虚拟IP,再由虚拟IP寻址到POD。
  • LoadBalancer:通过云服务供应商提供的load balancer向外部暴露服务,由指定的load balancer负责对NodePort与ClusterIP服务的路由。
  • ExternalName:比较特殊,只是简单的将服务名称映射成指定名称,如foo.bar.example.com,kube-dns1.7有以后版本支持此特性。

参考

k8s service

k8s service 介绍