Kubernetes的service

Kopei article

https://kubernetes.io/docs/concepts/services-networking/service/

Service定义

简单来说,service是一组pods和访问这些pods规则的逻辑抽象, 它的作用就是代理pods和端口映射(具体的实现似乎是通过复杂的iptable路由NAT)。Service是一个REST对象,这个对象将所有通过某个node端口进来TCP或者UDP包转发给下游pod, 默认上游的端口直接映射到下游pod,比如80—>80,
但是也可以指定下游端口为字符串(将pod端口取个名称), 这样下游不同的pod端口可以对应同一个端口名,大大提供了便利性。service定义代码如下,通过对apiserver post这组定义,可以产生一个新的service。(对于原生k8s服务,还会生成一个同名的Endpoints用来更新pod的地址)。每个node里有一个进程kube-proxy会分配的虚拟IP(cluster ip)。kube-proxy是一个守护进程, 管理着每个节点的service的虚拟IP. service既可以管理kubernetes原生的服务(通过更新EndpointsAPI),也可以抽象非k8s服务.(通过提供VIP)
k8s的Serivce支持TCP和UDP两种协议,默认是TCP.下面这个例子执行kubectl create -f my-service.yml后,将会生产一个叫my-service Service对象和一个
叫my-service的Endpoints对象(其实就是一组pods的ip),Service负责将流量导入到某组pods,Endpoints负责具体分配给某个pod。

1
2
3
4
5
6
7
8
9
10
11
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80 #service port
targetPort: 9376 # pod port

抽象外部服务

上面的例子使用label selector找到pods, 但是也有可能服务不是kubernetes管理的,这时候可以使用non selector service + endpoints抽象一个外部服务。

1
2
3
4
5
6
7
8
9
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376

没有selector的Service是不会生成Endpoint的,需要手动把对应的非k8s服务Endpoint映射到service.

1
2
3
4
5
6
7
8
9
kind: Endpoints
apiVersion: v1
metadata:
name: my-service
subsets:
- addresses:
- ip: 1.2.3.4
ports:
- port: 9376

如果在云上使用类似RDS之类的服务,没有IP,可以使用externalName来定义service. 这样就会使用DNS来解析地址,不会使用代理或者端口映射。

1
2
3
4
5
6
7
8
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com

虚拟IP和service代理

每一个k8s节点都有一个kube-proxy服务来管理service的虚拟IP. 有三种实现service代理模式: userspace, iptables, ipvs. 在v1.0版本,service是一个4层通信协议,直到TCP层,所以代理只在用户空间进行。v1.1加入了ingressiptables proxy, 实现了7层service.

  • userspace, 这个模式下当用户访问service时,iptables中有规则会把流量从service对应的port转发到kube-proxy在node创建的随机端口,随机端口再代理到下游pods。这个模式下kube-proxy会监控kubernetes master的对Service和endpoints的增删,
    并会给每一个service随机创建一个本地node端口,任何到这个端口的连接将会被代理到service后面pods.(具体是哪一个pod取决于service的SessionAffinity), 默认采用轮询的方式转发流量.
  • iptables, 默认kube-proxy采用的方式。这个模式下kube-proxy也会监控kubernetes master的对Service和endpoints的增删,每一个service都有一套iptable规则,根据service的ip:port重定向流量到某个Service后端endpoints, endpoints也会安装iptables来选择pod。特点是iptable不需要在用户态和内核态转换, 缺点是如果原来选择的pod无效,
    那么不会重试另一个pod,需要readiness探针来实现重试。具体实现原理可以看地址
  • ipvs, 这模式是v1.9beta版。 此模式调用netlink接口创建ipvs规则,然后从service和endpoint同步ipvs规则, 当一个service被访问时,流量会被重定向到后端pods。 ipvs使用的是hash表,有着更好的性能和多种负载均衡方案:
    • round robin
    • least connection
    • destination hashing
    • source hashing
    • shortest expected delay
    • never queue
  • Post title:Kubernetes的service
  • Post author:Kopei
  • Create time:2018-02-22 00:00:00
  • Post link:https://kopei.github.io/2018/02/21/kubernetes-2018-02-22-k8s-service/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
 Comments