Kubernetes:Service剖析

一. 简介

Service 是 Kubernetes 里重要的服务对象,而 Kubernetes 之所以需要 Service,一方面是因为 Pod 的 IP 不是固定的,另一方面则是因为一组 Pod 实例之间总会有负载均衡的需求。

通过创建 Service 可以为一组相同功能的容器应用提供一个统一的入口,并将请求均衡负载发送到后端的各个容器应用上。

  • 通过label selector来实现选中具体哪些容器
  • 均衡负载算法默认是 RR (Round-Robin 轮询调度)
  • 还可以通过设置 service.spec.sessionAffinity=ClientIp 来启用 SessionAffinity 策略
  • Service 只提供4层负载均衡能力(只能基于ip地址和端口进行转发),而没有7层功能(不能通过主机名及域名的方案去进行负载均衡)

关于本文的项目的代码,都放于链接:GitHub资源

基础架构图如下:


Service Architecture

二. Service类型

2.1 ClusterIP

在集群的内部ip上公开服务,这种类型使得只能从集群内访问服务。

2.1.1 定义

ClusterIP 是默认的方式。
对于 ClusterIP 模式的 Service 来说,它的 A 记录的格式是:..svc.cluster.local。当访问这条 A 记录的时候,它解析到的就是该 Service 的 VIP 地址。

ClusterIP 主要在每个node节点使用 Iptables 或者 IPVS,将发向 ClusterIP 对应端口的数据,转发到kube-proxy 中。然后kube-proxy自己内部实现有负载均衡的方法,并可以查询到这个service下对应pod的地址和端口,进而把数据转发给对应的pod的地址和端口。

2.1.2 转发流程

关于 ClusterIP 的转发流程如下:


Service-ClusterIP

为了实现图上的功能,需要以下几个组件协调工作:

  • api-server
    用户通过kubectl命令向apiserver发送创建 Service 的命令,apiserver接收到请求后将数据存储到etcd中。
  • kube-proxy
    Kubernetes的每个节点中都有一个叫做kube-porxy的进程,这个进程负责感知Service,pod的变化,并将变化的信息写入本地的iptables规则中。
  • iptables
    使用NAT等技术将virtuallP的流量转至endpoint中。

2.1.3 案例

“demo-svc-clusterip.yaml” 文件参考案例如下:

apiVersion: v1
kind: Service
metadata:
  name: demo-svc-clusterip
spec:
  type: ClusterIP
  selector:
    app: demo-svc-clusterip
  ports:
  - name: http
    port: 80
    targetPort: 80

我们通过spec.type: ClusterIP字段来定义即可。

2.2 NodePort

2.2.1 定义

通过将 Service 的 port 映射到集群内每个节点的相同一个端口,实现通过 nodeIP:nodePort从集群外访问服务,这属于 ClusterIP 的超集。

2.2.2 Port

Service中主要涉及三种Port(这里的port表示service暴露在clusterIP上的端口):

  • ClusterIP
    Port 是提供给集群内部访问 Kubernetes 服务的入口。
  • targetPort
    containerPort,targetPort 是 pod 上的端口,从 port 和 nodePort 上到来的数据最终经过kube-proxy 流入到后端 pod 的 targetPort 上进入容器。
  • nodePort
    nodeIP:nodePort 是提供给从集群外部访问 Kubernetes 服务的入口。

总的来说,port 和 nodePort 都是 Service 的端口,前者暴露给从集群内访问服务,后者暴露给从集群外访问服务。从这两个端口到来的数据都需要经过反向代理 kube-proxy 流入后端具体 pod 的 targetPort ,从而进入到 pod 上的容器内。

2.2.3 案例

“demo-svc-nodeport.yaml” 案例代码如下:

apiVersion: v1 
kind: Service 
metadata:
  name: demo-svc-nodeport
spec:
  type: NodePort 
  selector:
    app: demo-svc-nodeport
  ports:
  - name: http 
    port: 80 
    targetPort: 80
    protocol: TCP
  - nodePort: 443
    protocol: TCP
    name: https

在这个 Service 的定义里,我们声明它的类型是,type=NodePort。然后,我在 ports 字段里声明了 Service 的 80 端口代理 Pod 的 80 端口,Service 的 443 端口代理 Pod 的 443 端口。

我们也可以不显式地声明 nodePort 字段,Kubernetes 就会分配随机的可用端口来设置代理。这个端口的范围默认是 30000-32767,可以通过 kube-apiserver–service-node-port-range 参数来修改它。
当我们创建完毕后,可以通过如下访问格式:

<任何一台宿主机的IP地址>:80

2.3 LoadBalancer

2.3.1 定义

在公有云提供的 Kubernetes 服务里,都使用了一个叫作 CloudProvider 的转接层,来跟公有云本身的 API 进行对接。所以,在 LoadBalancer 类型的 Service 被提交后,Kubernetes 就会调用 CloudProvider 在公有云上创建一个负载均衡服务,并且把被代理的 Pod 的 IP 地址配置给负载均衡服务做后端。

2.3.2 案例

”demo-svc-loadbalancer.yaml” 案例如下:

kind: Service
apiVersion: v1
metadata:
  name: demo-svc-loadbalancer
spec:
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    app: demo-svc-loadbalancer
  type: LoadBalancer

2.4 ExternalName

2.4.1 定义

通过返回具有该名称的 CNAME 记录,使用任意名称(在规范中指定)公开服务,并且不使用代理。

2.4.2 案例

kind: Service
apiVersion: v1
metadata:
  name: demo-svc-externalname
spec:
  type: ExternalName
  externalName: demo-svc-externalname.wyatt.plus

在上述 Service 的 YAML 文件中,我指定了一个 externalName=demo-svc-externalname.wyatt.plus 的字段。
当通过 Service 的 DNS 名字访问它的时候,比如访问:demo-svc-externalname.default.svc.cluster.local。那么,Kubernetes 返回的就是demo-svc-externalname.wyatt.plus

2.4.3 CNAME

所以说,ExternalName 类型的 Service 其实是在 kube-dns 里添加了一条 CNAME 记录。当访问 demo-svc-externalname.default.svc.cluster.local 就和访问 demo-svc-externalname.wyatt.plus 这个域名效果一样。

2.4.4 externalIPs

在 ExternalName 模式下,Kubernetes 的 Service 还允许为 Service 分配公有 IP 地址。
“demo-svc-externalips.yaml” 案例如下:

kind: Service
apiVersion: v1
metadata:
  name: demo-svc-externalips
spec:
  selector:
    app: demo-svc-externalips
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 80
  externalIPs:
  - 192.11.11.11

在上述 Service 中,为它指定的 externalIPs=192.11.11.11,就可以通过访问 192.11.11.11:80 访问到被代理的 Pod 了。

三. Service代理

在Kubernetes集群中,为每个节点运行了一个kube-proxykube-proxy 负责为 Service 实现一种 virtual ip 的形式,而这个过程称之为Service代理模式。
不同的 Kubernetes 版本,代理模式的实现方式也不尽相同,前后共有三种模式:

  • userspace(已过期):Kubernetes v1.0 版本使用的是这种代理模式
  • Iptables:从 Kubernetes v1.2 开始使用 Iptables
  • IPVS:Kubernetes v1.14 开始默认使用 IPVS 代理

3.1 Iptables

3.1.1 原理

kube-proxy 通过iptables 处理 Service 的过程,其实需要在宿主机上设置相当多的 iptables 规则。而且,kube-proxy 还需要在控制循环里不断地刷新这些规则来确保它们始终是正确的。

3.1.2 架构图

Iptables architecture

3.1.3 优缺点

当宿主机上有大量 Pod 的时候,成百上千条 iptables 规则不断地被刷新,会大量占用该宿主机的 CPU 资源,甚至会让宿主机“卡”在这个过程中。
所以说,基于 Iptables 的 Service 实现,都是制约 Kubernetes 项目承载更多量级的 Pod 的主要障碍。

3.2 IPVS

3.2.1 原理

IPVS 模式的工作原理,其实跟 Iptables 模式类似。当我们创建了前面的 Service 之后,kube-proxy 首先会在宿主机上创建一个虚拟网卡(叫作:kube-ipvs0),并为它分配 Service VIP 作为 IP 地址。
而接下来,kube-proxy 就会通过 Linux 的 IPVS 模块,为这个 IP 地址设置三个 IPVS 虚拟主机,并设置这三个虚拟主机之间使用轮询模式 (rr) 来作为负载均衡策略。

3.2.2 架构图

IPVS architecture

3.2.3 负载均衡

IPVS 使用哈希表作为底层数据结构并在内核空间中工作,这意味着 IPVS 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。
此外,IPVS 为负载均衡算法提供了更多选项,例如

  • rr:轮询调度
  • 1c:最小连接数
  • dh:目标哈希
  • sh:源哈希
  • sed:最短期望延迟
  • nq:不排队调度

3.2.4 优缺点

而相比于 Iptables,IPVS 在内核中的实现其实也是基于 NetfilterNAT 模式,所以在转发这一层上,理论上 IPVS 并没有显著的性能提升。
但是,IPVS 并不需要在宿主机上为每个 Pod 设置 Iptables 规则,而是把对这些“规则”的处理放到了内核态,从而极大地降低了维护这些规则的代价。所以,“将重要操作放入内核态”是提高性能的重要手段。

注意: IPVS 需要节点上的 IPVS内核模块 支持,如果未安装,则 kube-proxy 将回退到 Iptables 代理模式。

四. 拓展

4.1 Endpoints

在 Kubernetes 中,selector 选中的 Pod,就称为 Service 的 Endpoints,可以使用 kubectl get ep 命令看到它们。
需要注意的是,只有处于 Running 状态,且 readinessProbe 检查通过的 Pod,才会出现在 Service 的 Endpoints 列表里。并且,当某一个 Pod 出现问题时,Kubernetes 会自动把它从 Service 里摘除掉。

4.2 Headless Service

Headless Service 也是一种 ClusterIP ,只不过是一种特殊的情况。
有时不需要或不想要负载均衡,以及单独的 Service IP 。遇到这种情况,可以通过指定 ClusterIP(spec.clusterIP) 的值为 None 来创建 Headless Service
这类 Service 具有如下的特点:

  • 不会分配 Cluster IP
  • kube-proxy 不会处理它们
  • 平台也不会为它们进行负载均衡和路由

通过 Headless Service的方式,可以解决 hostnameportname的变化问题,也就是通过它去进行绑定。例如,我们之前提到的 StatefulSet 这种有状态应用。

五. 总结

Service,其实就是 Kubernetes 为 Pod 分配的、固定的、基于 Iptables(或者 IPVS)的访问入口。而这些访问入口代理的 Pod 信息,则来自于 Etcd,由 kube-proxy 通过控制循环来维护。

当然,我们发现 Service 和 DNS 机制 不具备强多租户能力。比如,在多租户情况下,每个租户应该拥有一套独立的 Service 规则(Service 只应该看到和代理同一个租户下的 Pod)。再比如 DNS,在多租户情况下,每个租户应该拥有自己的 kube-dnskube-dns 只应该为同一个租户下的 Service 和 Pod 创建 DNS Entry)。

欢迎收藏个人博客: Wyatt's Blog ,非常感谢~

Reference

https://kubernetes.io/zh/docs/concepts/services-networking/service/
https://www.cnblogs.com/binghe001/p/13166641.html
https://draveness.me/kubernetes-service/
https://www.cnblogs.com/baoshu/p/13233014.html
https://time.geekbang.org/column/article/68964?utm_campaign=guanwang&utm_source=baidu-ad&utm_medium=ppzq-pc&utm_content=title&utm_term=baidu-ad-ppzq-title
https://draveness.me/kubernetes-service/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容